Worked through some bugs, updated dependencies
The vendor directory is now just composer stuff. Planning to rearrange some files soon but wanted to commit these changes. AYAH is now installed via composer from a package I am maintaining and I dropped the test helpers as it is a dev-only requirement (and that's assuming you even want to test).
This commit is contained in:
parent
c9f39e2e18
commit
293f618bef
43 changed files with 160 additions and 3148 deletions
|
@ -21,7 +21,7 @@ PICKLES is in fact not a true MVC system and won’t be masquerading around as o
|
||||||
### Required Software
|
### Required Software
|
||||||
|
|
||||||
* Web server of your choice (nginx is highly recommended)
|
* Web server of your choice (nginx is highly recommended)
|
||||||
* PHP 5.5+
|
* PHP 5.4+
|
||||||
|
|
||||||
Please note that strides are being made to be compatible with bleeding edge technologies. PICKLES is currently developed against PHP 5.5 and does not pass build tests against prior versions. This effort will be with somewhat of a reckless abandon towards backwards compatibility to keep up with deprecations within PHP.
|
Please note that strides are being made to be compatible with bleeding edge technologies. PICKLES is currently developed against PHP 5.5 and does not pass build tests against prior versions. This effort will be with somewhat of a reckless abandon towards backwards compatibility to keep up with deprecations within PHP.
|
||||||
|
|
||||||
|
@ -35,7 +35,9 @@ As developers we make demands that our end users use modern day browsers while w
|
||||||
* PostgreSQL with PDO and PDO_PGSQL drivers
|
* PostgreSQL with PDO and PDO_PGSQL drivers
|
||||||
* SQLite 3 with PDO and PDO_SQLITE drivers
|
* SQLite 3 with PDO and PDO_SQLITE drivers
|
||||||
* Memcached with the Memcache module
|
* Memcached with the Memcache module
|
||||||
* composer if you want to compile LESS, SCSS or JS also necessary if you want to run the unit tests
|
* composer if you want to compile LESS, SCSS or JS also necessary if you want
|
||||||
|
to run the unit tests
|
||||||
|
* [ext/test_helpers](https://github.com/php-test-helpers/php-test-helpers) if you want to be able to run the test suite
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
|
@ -140,19 +140,10 @@ class Config extends Object
|
||||||
// Defaults profiler to true if it doesn't match an option exactly
|
// Defaults profiler to true if it doesn't match an option exactly
|
||||||
if (isset($this->data['pickles']['profiler']))
|
if (isset($this->data['pickles']['profiler']))
|
||||||
{
|
{
|
||||||
if ($this->data['pickles']['profiler'] !== true)
|
// If we have an array convert to a string
|
||||||
|
if (is_array($this->data['pickles']['profiler']))
|
||||||
{
|
{
|
||||||
// If we have an array convert to a string
|
$this->data['pickles']['profiler'] = implode(',', $this->data['pickles']['profiler']);
|
||||||
if (is_array($this->data['pickles']['profiler']))
|
|
||||||
{
|
|
||||||
$this->data['pickles']['profiler'] = implode(',', $this->data['pickles']['profiler']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks that one of our known values exists, if not, force true
|
|
||||||
if (preg_match('/(objects|timers|queries|explains)/', $this->data['pickles']['profiler']) == false)
|
|
||||||
{
|
|
||||||
$this->data['pickles']['profiler'] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -155,8 +155,6 @@ class Dynamic extends Object
|
||||||
{
|
{
|
||||||
$compiled_filename = str_replace('.min', '', $minified_filename);
|
$compiled_filename = str_replace('.min', '', $minified_filename);
|
||||||
|
|
||||||
require_once $this->config->pickles['path'] . 'vendors/composer/autoload.php';
|
|
||||||
|
|
||||||
if ($less)
|
if ($less)
|
||||||
{
|
{
|
||||||
$less = new lessc();
|
$less = new lessc();
|
||||||
|
@ -241,9 +239,7 @@ class Dynamic extends Object
|
||||||
|
|
||||||
if ($this->config->pickles['minify'] === true)
|
if ($this->config->pickles['minify'] === true)
|
||||||
{
|
{
|
||||||
require_once $this->config->pickles['path'] . 'vendors/composer/autoload.php';
|
$compiler = new Devize\ClosureCompiler\ClosureCompiler();
|
||||||
|
|
||||||
$compiler = new Devize\ClosureCompiler\ClosureCompiler;
|
|
||||||
$compiler->setSourceBaseDir(dirname($original_filename));
|
$compiler->setSourceBaseDir(dirname($original_filename));
|
||||||
$compiler->setTargetBaseDir(dirname($minified_filename));
|
$compiler->setTargetBaseDir(dirname($minified_filename));
|
||||||
$compiler->addSourceFile(basename($original_filename));
|
$compiler->addSourceFile(basename($original_filename));
|
||||||
|
|
|
@ -2,11 +2,20 @@
|
||||||
"config": {
|
"config": {
|
||||||
"vendor-dir": "vendors/composer"
|
"vendor-dir": "vendors/composer"
|
||||||
},
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/joshtronic/php-ayah.git",
|
||||||
|
"type": "git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require-dev": {
|
||||||
|
"mikey179/vfsStream": "1.2.0",
|
||||||
|
"satooshi/php-coveralls": "dev-master"
|
||||||
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"devize/closure-compiler": "@dev",
|
"devize/closure-compiler": "@dev",
|
||||||
|
"joshtronic/php-ayah": "1.1.8",
|
||||||
"leafo/lessphp": "0.4.0",
|
"leafo/lessphp": "0.4.0",
|
||||||
"leafo/scssphp": "0.0.9",
|
"leafo/scssphp": "0.0.9"
|
||||||
"mikey179/vfsStream": "1.2.0",
|
|
||||||
"satooshi/php-coveralls": "dev-master"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
211
composer.lock
generated
211
composer.lock
generated
|
@ -3,7 +3,7 @@
|
||||||
"This file locks the dependencies of your project to a known state",
|
"This file locks the dependencies of your project to a known state",
|
||||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
|
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
|
||||||
],
|
],
|
||||||
"hash": "1d8b441a227410fc9fbef17bf7549d9a",
|
"hash": "d1441533619d080c356f9315ce68b9df",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "devize/closure-compiler",
|
"name": "devize/closure-compiler",
|
||||||
|
@ -42,6 +42,125 @@
|
||||||
"description": "Google's Closure Compiler for use in PHP-based projects",
|
"description": "Google's Closure Compiler for use in PHP-based projects",
|
||||||
"time": "2013-08-14 11:53:34"
|
"time": "2013-08-14 11:53:34"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "joshtronic/php-ayah",
|
||||||
|
"version": "v1.1.8",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/joshtronic/php-ayah.git",
|
||||||
|
"reference": "cc0ebf289394f80a83372e36e097afe2d3355b45"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Some awesome developer over at AreYouAHuman.com",
|
||||||
|
"email": "support@areyouahuman.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Joshua Sherman",
|
||||||
|
"email": "josh@gravityblvd.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Are You a Human PHP Bundle",
|
||||||
|
"time": "2014-01-21 02:56:55"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "leafo/lessphp",
|
||||||
|
"version": "v0.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/leafo/lessphp.git",
|
||||||
|
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/leafo/lessphp/zipball/51f3f06f0fe78a722dabfd14578444bdd078d9de",
|
||||||
|
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "0.3-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"lessc.inc.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT",
|
||||||
|
"GPL-3.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Leaf Corcoran",
|
||||||
|
"email": "leafot@gmail.com",
|
||||||
|
"homepage": "http://leafo.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "lessphp is a compiler for LESS written in PHP.",
|
||||||
|
"homepage": "http://leafo.net/lessphp/",
|
||||||
|
"time": "2013-08-09 17:09:19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "leafo/scssphp",
|
||||||
|
"version": "v0.0.9",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/leafo/scssphp.git",
|
||||||
|
"reference": "a06d702ebf9fabb22542bbb27cc12a905813bb6d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/leafo/scssphp/zipball/a06d702ebf9fabb22542bbb27cc12a905813bb6d",
|
||||||
|
"reference": "a06d702ebf9fabb22542bbb27cc12a905813bb6d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php": ">=5.3.0",
|
||||||
|
"phpunit/phpunit": "3.7.*"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"pscss"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"scss.inc.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT",
|
||||||
|
"GPL-3.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Leaf Corcoran",
|
||||||
|
"email": "leafot@gmail.com",
|
||||||
|
"homepage": "http://leafo.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "scssphp is a compiler for SCSS written in PHP.",
|
||||||
|
"homepage": "http://leafo.net/scssphp/",
|
||||||
|
"time": "2013-12-23 23:28:02"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "guzzle/guzzle",
|
"name": "guzzle/guzzle",
|
||||||
"version": "v3.8.0",
|
"version": "v3.8.0",
|
||||||
|
@ -134,93 +253,6 @@
|
||||||
],
|
],
|
||||||
"time": "2013-12-05 23:39:20"
|
"time": "2013-12-05 23:39:20"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "leafo/lessphp",
|
|
||||||
"version": "v0.4.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/leafo/lessphp.git",
|
|
||||||
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/leafo/lessphp/zipball/51f3f06f0fe78a722dabfd14578444bdd078d9de",
|
|
||||||
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "0.3-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"classmap": [
|
|
||||||
"lessc.inc.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT",
|
|
||||||
"GPL-3.0"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Leaf Corcoran",
|
|
||||||
"email": "leafot@gmail.com",
|
|
||||||
"homepage": "http://leafo.net"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "lessphp is a compiler for LESS written in PHP.",
|
|
||||||
"homepage": "http://leafo.net/lessphp/",
|
|
||||||
"time": "2013-08-09 17:09:19"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "leafo/scssphp",
|
|
||||||
"version": "v0.0.9",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/leafo/scssphp.git",
|
|
||||||
"reference": "a06d702ebf9fabb22542bbb27cc12a905813bb6d"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/leafo/scssphp/zipball/a06d702ebf9fabb22542bbb27cc12a905813bb6d",
|
|
||||||
"reference": "a06d702ebf9fabb22542bbb27cc12a905813bb6d",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=5.2.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"php": ">=5.3.0",
|
|
||||||
"phpunit/phpunit": "3.7.*"
|
|
||||||
},
|
|
||||||
"bin": [
|
|
||||||
"pscss"
|
|
||||||
],
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"classmap": [
|
|
||||||
"scss.inc.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT",
|
|
||||||
"GPL-3.0"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Leaf Corcoran",
|
|
||||||
"email": "leafot@gmail.com",
|
|
||||||
"homepage": "http://leafo.net"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "scssphp is a compiler for SCSS written in PHP.",
|
|
||||||
"homepage": "http://leafo.net/scssphp/",
|
|
||||||
"time": "2013-12-23 23:28:02"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "mikey179/vfsStream",
|
"name": "mikey179/vfsStream",
|
||||||
"version": "v1.2.0",
|
"version": "v1.2.0",
|
||||||
|
@ -655,9 +687,6 @@
|
||||||
"homepage": "http://symfony.com",
|
"homepage": "http://symfony.com",
|
||||||
"time": "2013-12-28 08:12:03"
|
"time": "2013-12-28 08:12:03"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"packages-dev": [
|
|
||||||
|
|
||||||
],
|
],
|
||||||
"aliases": [
|
"aliases": [
|
||||||
|
|
||||||
|
|
44
pickles.php
44
pickles.php
|
@ -87,33 +87,26 @@ function __autoload($class)
|
||||||
'vendor' => $pickles_path . 'vendors/',
|
'vendor' => $pickles_path . 'vendors/',
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($class == 'AYAH')
|
// Path as the key, boolean value is whether ot not to convert back to hyphenated
|
||||||
{
|
$paths = [
|
||||||
$loaded = require_once $pickles_paths['vendor'] . 'ayah/' . strtolower($filename);
|
$pickles_paths['class'] => false,
|
||||||
}
|
SITE_CLASS_PATH => false,
|
||||||
else
|
SITE_MODEL_PATH => false,
|
||||||
{
|
SITE_MODULE_PATH => true,
|
||||||
// Path as the key, boolean value is whether ot not to convert back to hyphenated
|
];
|
||||||
$paths = [
|
|
||||||
$pickles_paths['class'] => false,
|
|
||||||
SITE_CLASS_PATH => false,
|
|
||||||
SITE_MODEL_PATH => false,
|
|
||||||
SITE_MODULE_PATH => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($paths as $path => $hyphenated)
|
foreach ($paths as $path => $hyphenated)
|
||||||
|
{
|
||||||
|
// Converts the filename back to hypenated
|
||||||
|
if ($hyphenated == true)
|
||||||
{
|
{
|
||||||
// Converts the filename back to hypenated
|
$filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));;
|
||||||
if ($hyphenated == true)
|
}
|
||||||
{
|
|
||||||
$filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_exists($path . $filename))
|
if (file_exists($path . $filename))
|
||||||
{
|
{
|
||||||
$loaded = require_once $path . $filename;
|
$loaded = require_once $path . $filename;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +124,9 @@ $config = Config::getInstance();
|
||||||
// Injects PICKLES variables into the config
|
// Injects PICKLES variables into the config
|
||||||
$config->data['pickles']['path'] = dirname(__FILE__) . '/';
|
$config->data['pickles']['path'] = dirname(__FILE__) . '/';
|
||||||
|
|
||||||
|
// Requires the Composer autoloader
|
||||||
|
require_once $config->pickles['path'] . 'vendors/composer/autoload.php';
|
||||||
|
|
||||||
// Configures any available PHP configuration options
|
// Configures any available PHP configuration options
|
||||||
if (is_array($config->php) && count($config->php))
|
if (is_array($config->php) && count($config->php))
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,18 +123,6 @@ class ConfigTest extends PHPUnit_Framework_TestCase
|
||||||
$this->assertEquals('objects,timers', $config->pickles['profiler']);
|
$this->assertEquals('objects,timers', $config->pickles['profiler']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testProfilerForceTrue()
|
|
||||||
{
|
|
||||||
setUpConfig([
|
|
||||||
'environment' => 'local',
|
|
||||||
'pickles' => ['profiler' => ['unknown']],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$config = new Config();
|
|
||||||
|
|
||||||
$this->assertTrue($config->pickles['profiler']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSecurityConstant()
|
public function testSecurityConstant()
|
||||||
{
|
{
|
||||||
setUpConfig([
|
setUpConfig([
|
||||||
|
|
1
vendors/ayah
vendored
1
vendors/ayah
vendored
|
@ -1 +0,0 @@
|
||||||
ayah-1.1.7
|
|
482
vendors/ayah-1.1.7/ayah.php
vendored
482
vendors/ayah-1.1.7/ayah.php
vendored
|
@ -1,482 +0,0 @@
|
||||||
<?php
|
|
||||||
/*
|
|
||||||
* Are You A Human
|
|
||||||
* PHP Integration Library
|
|
||||||
*
|
|
||||||
* @version 1.1.8
|
|
||||||
*
|
|
||||||
* - Documentation and latest version
|
|
||||||
* http://portal.areyouahuman.com/help
|
|
||||||
* - Get an AYAH Publisher Key
|
|
||||||
* https://portal.areyouahuman.com
|
|
||||||
* - Discussion group
|
|
||||||
* http://getsatisfaction.com/areyouahuman
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013 AYAH LLC -- http://www.areyouahuman.com
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Only define the AYAH class if it does not already exist.
|
|
||||||
if ( ! class_exists('AYAH')):
|
|
||||||
|
|
||||||
class AYAH {
|
|
||||||
// Set defaults for values that can be specified via the config file or passed in via __construct.
|
|
||||||
protected $ayah_publisher_key = '';
|
|
||||||
protected $ayah_scoring_key = '';
|
|
||||||
protected $ayah_web_service_host = 'ws.areyouahuman.com';
|
|
||||||
protected $ayah_debug_mode = FALSE;
|
|
||||||
protected $ayah_use_curl = TRUE;
|
|
||||||
|
|
||||||
protected $session_secret;
|
|
||||||
|
|
||||||
protected $__valid_construct_params = array('publisher_key', 'scoring_key', 'web_service_host', 'debug_mode', 'use_curl');
|
|
||||||
protected $__message_buffer = array();
|
|
||||||
protected $__version_number = '1.1.7';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* If the session secret exists in input, it grabs it
|
|
||||||
* @param $params associative array with keys publisher_key, scoring_key, web_service_host
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function __construct($params = array())
|
|
||||||
{
|
|
||||||
// Try to load the ayah_config.php file.
|
|
||||||
if ( ! $this->__load_config_file())
|
|
||||||
{
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "The ayah_config.php file is missing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get and use any valid parameters that were passed in via the $params array.
|
|
||||||
foreach ((array)$this->__valid_construct_params as $partial_variable_name)
|
|
||||||
{
|
|
||||||
// Build the full variable name...and create an upper case version.
|
|
||||||
$variable_name = "ayah_" . $partial_variable_name;
|
|
||||||
$uc_variable_name = strtoupper($variable_name);
|
|
||||||
|
|
||||||
// Check to see if it was passed in via $params.
|
|
||||||
if (isset($params[$partial_variable_name]))
|
|
||||||
{
|
|
||||||
$this->{$variable_name} = $params[$partial_variable_name];
|
|
||||||
}
|
|
||||||
// Check to see if it was defined in the ayah_config file.
|
|
||||||
elseif (defined($uc_variable_name))
|
|
||||||
{
|
|
||||||
$this->{$variable_name} = constant($uc_variable_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate some warnings/errors if needed variables are not set.
|
|
||||||
if ($this->ayah_publisher_key == "")
|
|
||||||
{
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Warning: Publisher key is not defined. This won't work.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "Publisher key: '$this->ayah_publisher_key'");
|
|
||||||
}
|
|
||||||
if ($this->ayah_scoring_key == "")
|
|
||||||
{
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Warning: Scoring key is not defined. This won't work.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For security reasons, don't output the scoring key as part of the debug info.
|
|
||||||
}
|
|
||||||
if ($this->ayah_web_service_host == "")
|
|
||||||
{
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Warning: Web service host is not defined. This won't work.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "AYAH Webservice host: '$this->ayah_web_service_host'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If available, set the session secret.
|
|
||||||
if(array_key_exists("session_secret", $_REQUEST)) {
|
|
||||||
$this->session_secret = $_REQUEST["session_secret"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the markup for the PlayThru
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPublisherHTML($config = array())
|
|
||||||
{
|
|
||||||
// Initialize.
|
|
||||||
$session_secret = "";
|
|
||||||
$fields = array('config' => $config);
|
|
||||||
$webservice_url = '/ws/setruntimeoptions/' . $this->ayah_publisher_key;
|
|
||||||
|
|
||||||
// If necessary, process the config data.
|
|
||||||
if ( ! empty($config))
|
|
||||||
{
|
|
||||||
// Log it.
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "Setting runtime options...config data='".implode(",", $config)."'");
|
|
||||||
|
|
||||||
// Add the gameid to the options url.
|
|
||||||
if (array_key_exists("gameid", $config))
|
|
||||||
{
|
|
||||||
$webservice_url .= '/' . $config['gameid'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the webservice and get the response.
|
|
||||||
$resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, $webservice_url, $fields);
|
|
||||||
if ($resp)
|
|
||||||
{
|
|
||||||
// Get the session secret from the response.
|
|
||||||
$session_secret = $resp->session_secret;
|
|
||||||
|
|
||||||
// Build the url to the AYAH webservice.
|
|
||||||
$url = 'https://'; // The AYAH webservice API requires https.
|
|
||||||
$url.= $this->ayah_web_service_host; // Add the host.
|
|
||||||
$url.= "/ws/script/"; // Add the path to the API script.
|
|
||||||
$url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key.
|
|
||||||
$url.= (empty($session_secret))? "" : "/".$session_secret; // If set, add the session_secret.
|
|
||||||
|
|
||||||
// Build and return the needed HTML code.
|
|
||||||
return "<div id='AYAH'></div><script src='". $url ."' type='text/javascript' language='JavaScript'></script>";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Build and log a detailed message.
|
|
||||||
$url = "https://".$this->ayah_web_service_host.$webservice_url;
|
|
||||||
$message = "Unable to connect to the AYAH webservice server. url='$url'";
|
|
||||||
$this->__log("ERROR", __FUNCTION__, $message);
|
|
||||||
|
|
||||||
// Build and display a helpful message to the site user.
|
|
||||||
$style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;";
|
|
||||||
$message = "Unable to load the <i>Are You a Human</i> PlayThru™. Please contact the site owner to report the problem.";
|
|
||||||
echo "<p style=\"$style\">$message</p>\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the user is a human
|
|
||||||
* Wrapper for the scoreGame API call
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function scoreResult() {
|
|
||||||
$result = false;
|
|
||||||
if ($this->session_secret) {
|
|
||||||
$fields = array(
|
|
||||||
'session_secret' => urlencode($this->session_secret),
|
|
||||||
'scoring_key' => $this->ayah_scoring_key
|
|
||||||
);
|
|
||||||
$resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, "/ws/scoreGame", $fields);
|
|
||||||
if ($resp) {
|
|
||||||
$result = ($resp->status_code == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "Unable to score the result. Please check that your ayah_config.php file contains your correct publisher key and scoring key.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Records a conversion
|
|
||||||
* Called on the goal page that A and B redirect to
|
|
||||||
* A/B Testing Specific Function
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function recordConversion() {
|
|
||||||
// Build the url to the AYAH webservice..
|
|
||||||
$url = 'https://'; // The AYAH webservice API requires https.
|
|
||||||
$url.= $this->ayah_web_service_host; // Add the host.
|
|
||||||
$url.= "/ws/recordConversion/"; // Add the path to the API script.
|
|
||||||
$url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key.
|
|
||||||
|
|
||||||
if( isset( $this->session_secret ) ){
|
|
||||||
return '<iframe style="border: none;" height="0" width="0" src="' . $url . '"></iframe>';
|
|
||||||
} else {
|
|
||||||
$this->__log("ERROR", __FUNCTION__, 'AYAH Conversion Error: No Session Secret');
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do a HTTPS POST, return some JSON decoded as array (Internal function)
|
|
||||||
* @param $host hostname
|
|
||||||
* @param $path path
|
|
||||||
* @param $fields associative array of fields
|
|
||||||
* return JSON decoded data structure or empty data structure
|
|
||||||
*/
|
|
||||||
protected function doHttpsPostReturnJSONArray($hostname, $path, $fields) {
|
|
||||||
$result = $this->doHttpsPost($hostname, $path, $fields);
|
|
||||||
|
|
||||||
if ($result) {
|
|
||||||
$result = $this->doJSONArrayDecode($result);
|
|
||||||
} else {
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Post to https://$hostname$path returned no result.");
|
|
||||||
$result = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal function; does an HTTPS post
|
|
||||||
protected function doHttpsPost($hostname, $path, $fields) {
|
|
||||||
$result = "";
|
|
||||||
// URLencode the post string
|
|
||||||
$fields_string = "";
|
|
||||||
foreach($fields as $key=>$value) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
if ( ! empty($value)) {
|
|
||||||
foreach ($value as $k => $v) {
|
|
||||||
$fields_string .= $key . '['. $k .']=' . $v . '&';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$fields_string .= $key . '=&';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$fields_string .= $key.'='.$value.'&';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rtrim($fields_string,'&');
|
|
||||||
|
|
||||||
// Use cURL?
|
|
||||||
if ($this->__use_curl())
|
|
||||||
{
|
|
||||||
// Build the cURL url.
|
|
||||||
$curl_url = "https://" . $hostname . $path;
|
|
||||||
|
|
||||||
// Log it.
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "Using cURl: url='$curl_url', fields='$fields_string'");
|
|
||||||
|
|
||||||
// Initialize cURL session.
|
|
||||||
if ($ch = curl_init($curl_url))
|
|
||||||
{
|
|
||||||
// Set the cURL options.
|
|
||||||
curl_setopt($ch, CURLOPT_POST, count($fields));
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
||||||
|
|
||||||
// Execute the cURL request.
|
|
||||||
$result = curl_exec($ch);
|
|
||||||
|
|
||||||
// Close the curl session.
|
|
||||||
curl_close($ch);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Log it.
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "Unable to initialize cURL: url='$curl_url'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Log it.
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "Using fsockopen(): fields='$fields_string'");
|
|
||||||
|
|
||||||
// Build a header
|
|
||||||
$http_request = "POST $path HTTP/1.1\r\n";
|
|
||||||
$http_request .= "Host: $hostname\r\n";
|
|
||||||
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
|
|
||||||
$http_request .= "Content-Length: " . strlen($fields_string) . "\r\n";
|
|
||||||
$http_request .= "User-Agent: AreYouAHuman/PHP " . $this->get_version_number() . "\r\n";
|
|
||||||
$http_request .= "Connection: Close\r\n";
|
|
||||||
$http_request .= "\r\n";
|
|
||||||
$http_request .= $fields_string ."\r\n";
|
|
||||||
|
|
||||||
$result = '';
|
|
||||||
$errno = $errstr = "";
|
|
||||||
$fs = fsockopen("ssl://" . $hostname, 443, $errno, $errstr, 10);
|
|
||||||
if( false == $fs ) {
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Could not open socket");
|
|
||||||
} else {
|
|
||||||
fwrite($fs, $http_request);
|
|
||||||
while (!feof($fs)) {
|
|
||||||
$result .= fgets($fs, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = explode("\r\n\r\n", $result, 2);
|
|
||||||
$result = $result[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log the result.
|
|
||||||
$this->__log("DEBUG", __FUNCTION__, "result='$result'");
|
|
||||||
|
|
||||||
// Return the result.
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal function: does a JSON decode of the string
|
|
||||||
protected function doJSONArrayDecode($string) {
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
if (function_exists("json_decode")) {
|
|
||||||
try {
|
|
||||||
$result = json_decode( $string);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Exception when calling json_decode: " . $e->getMessage());
|
|
||||||
$result = null;
|
|
||||||
}
|
|
||||||
} elseif (file_Exists("json.php")) {
|
|
||||||
require_once('json.php');
|
|
||||||
$json = new Services_JSON();
|
|
||||||
$result = $json->decode($string);
|
|
||||||
|
|
||||||
if (!is_array($result)) {
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "Expected array; got something else: $result");
|
|
||||||
$result = array();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->__log("ERROR", __FUNCTION__, "No JSON decode function available.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current debug mode (TRUE or FALSE)
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function debug_mode($mode=null)
|
|
||||||
{
|
|
||||||
// Set it if the mode is passed.
|
|
||||||
if (null !== $mode)
|
|
||||||
{
|
|
||||||
// Save it.
|
|
||||||
$this->ayah_debug_mode = $mode;
|
|
||||||
|
|
||||||
// Display a message if debug_mode is TRUE.
|
|
||||||
if ($mode)
|
|
||||||
{
|
|
||||||
$version_number = $this->get_version_number();
|
|
||||||
$this->__log("DEBUG", "", "Debug mode is now on. (ayah.php version=$version_number)");
|
|
||||||
|
|
||||||
// Flush the buffer.
|
|
||||||
$this->__flush_message_buffer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If necessary, set the default.
|
|
||||||
if ( ! isset($this->ayah_debug_mode) or (null == $this->ayah_debug_mode)) $this->ayah_debug_mode = FALSE;
|
|
||||||
|
|
||||||
// Return TRUE or FALSE.
|
|
||||||
return ($this->ayah_debug_mode)? TRUE : FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current version number
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function get_version_number()
|
|
||||||
{
|
|
||||||
return (isset($this->__version_number))? $this->__version_number : FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether or not cURL is available to use.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
private function __use_curl()
|
|
||||||
{
|
|
||||||
if (FALSE === $this->ayah_use_curl)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
elseif (function_exists('curl_init') and function_exists('curl_exec'))
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the config file.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
private function __load_config_file()
|
|
||||||
{
|
|
||||||
// Initialize.
|
|
||||||
$name = 'ayah_config.php';
|
|
||||||
$locations = array(
|
|
||||||
'./',
|
|
||||||
dirname(__FILE__)."/",
|
|
||||||
);
|
|
||||||
|
|
||||||
// Look for the config file in each location.
|
|
||||||
foreach ($locations as $location)
|
|
||||||
{
|
|
||||||
if (file_exists($location.$name))
|
|
||||||
{
|
|
||||||
require_once($location.$name);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Could not find the config file.
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
protected function __log($type, $function, $message)
|
|
||||||
{
|
|
||||||
// Add a prefix to the message.
|
|
||||||
$message = __CLASS__ . "::$function: " . $message;
|
|
||||||
|
|
||||||
// Is it an error message?
|
|
||||||
if (FALSE !== stripos($type, "error"))
|
|
||||||
{
|
|
||||||
error_log($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the full message.
|
|
||||||
$message_style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;";
|
|
||||||
$full_message = "<p style=\"$message_style\"><strong>$type:</strong> $message</p>\n";
|
|
||||||
|
|
||||||
// Output to the screen too?
|
|
||||||
if ($this->debug_mode())
|
|
||||||
{
|
|
||||||
echo "$full_message";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add the message to the buffer in case we need it later.
|
|
||||||
$this->__message_buffer[] = $full_message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function __flush_message_buffer()
|
|
||||||
{
|
|
||||||
// Flush the buffer.
|
|
||||||
if ( ! empty($this->__message_buffer))
|
|
||||||
{
|
|
||||||
foreach ($this->__message_buffer as $buffered_message)
|
|
||||||
{
|
|
||||||
// Print the buffered message.
|
|
||||||
echo "$buffered_message";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
endif; // if ( ! class_exists('AYAH')):
|
|
13
vendors/ayah-1.1.7/ayah_config.php
vendored
13
vendors/ayah-1.1.7/ayah_config.php
vendored
|
@ -1,13 +0,0 @@
|
||||||
<?php
|
|
||||||
// Edit the two lines below to use the keys for your site.
|
|
||||||
// (Note: you can find your keys at http://portal.areyouahuman.com/dashboard)
|
|
||||||
define( 'AYAH_PUBLISHER_KEY', 'your_publisher_key_goes_here');
|
|
||||||
define( 'AYAH_SCORING_KEY', 'your_scoring_key_goes_here');
|
|
||||||
|
|
||||||
|
|
||||||
// Set defaults for values needed by the ayah.php file.
|
|
||||||
// (Note: you do not need to change these.)
|
|
||||||
define( 'AYAH_WEB_SERVICE_HOST', 'ws.areyouahuman.com');
|
|
||||||
define( 'AYAH_TIMEOUT', 0);
|
|
||||||
define( 'AYAH_DEBUG_MODE', FALSE);
|
|
||||||
define( 'AYAH_USE_CURL', TRUE);
|
|
811
vendors/ayah-1.1.7/json.php
vendored
811
vendors/ayah-1.1.7/json.php
vendored
|
@ -1,811 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
if (!defined('IN_PHPBB'))
|
|
||||||
{
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts to and from JSON format.
|
|
||||||
*
|
|
||||||
* JSON (JavaScript Object Notation) is a lightweight data-interchange
|
|
||||||
* format. It is easy for humans to read and write. It is easy for machines
|
|
||||||
* to parse and generate. It is based on a subset of the JavaScript
|
|
||||||
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
|
|
||||||
* This feature can also be found in Python. JSON is a text format that is
|
|
||||||
* completely language independent but uses conventions that are familiar
|
|
||||||
* to programmers of the C-family of languages, including C, C++, C#, Java,
|
|
||||||
* JavaScript, Perl, TCL, and many others. These properties make JSON an
|
|
||||||
* ideal data-interchange language.
|
|
||||||
*
|
|
||||||
* This package provides a simple encoder and decoder for JSON notation. It
|
|
||||||
* is intended for use with client-side Javascript applications that make
|
|
||||||
* use of HTTPRequest to perform server communication functions - data can
|
|
||||||
* be encoded into JSON notation for use in a client-side javascript, or
|
|
||||||
* decoded from incoming Javascript requests. JSON format is native to
|
|
||||||
* Javascript, and can be directly eval()'ed with no further parsing
|
|
||||||
* overhead
|
|
||||||
*
|
|
||||||
* All strings should be in ASCII or UTF-8 format!
|
|
||||||
*
|
|
||||||
* LICENSE: Redistribution and use in source and binary forms, with or
|
|
||||||
* without modification, are permitted provided that the following
|
|
||||||
* conditions are met: Redistributions of source code must retain the
|
|
||||||
* above copyright notice, this list of conditions and the following
|
|
||||||
* disclaimer. Redistributions in binary form must reproduce the above
|
|
||||||
* copyright notice, this list of conditions and the following disclaimer
|
|
||||||
* in the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
||||||
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
||||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
||||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
* DAMAGE.
|
|
||||||
*
|
|
||||||
* @category
|
|
||||||
* @package Services_JSON
|
|
||||||
* @author Michal Migurski <mike-json@teczno.com>
|
|
||||||
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
|
|
||||||
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
|
|
||||||
* @copyright 2005 Michal Migurski
|
|
||||||
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
|
|
||||||
* @license http://www.opensource.org/licenses/bsd-license.php
|
|
||||||
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_SLICE', 1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_IN_STR', 2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_IN_ARR', 3);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_IN_OBJ', 4);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_IN_CMT', 5);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Behavior switch for Services_JSON::decode()
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_LOOSE_TYPE', 16);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Behavior switch for Services_JSON::decode()
|
|
||||||
*/
|
|
||||||
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts to and from JSON format.
|
|
||||||
*
|
|
||||||
* Brief example of use:
|
|
||||||
*
|
|
||||||
* <code>
|
|
||||||
* // create a new instance of Services_JSON
|
|
||||||
* $json = new Services_JSON();
|
|
||||||
*
|
|
||||||
* // convert a complexe value to JSON notation, and send it to the browser
|
|
||||||
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
|
|
||||||
* $output = $json->encode($value);
|
|
||||||
*
|
|
||||||
* print($output);
|
|
||||||
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
|
|
||||||
*
|
|
||||||
* // accept incoming POST data, assumed to be in JSON notation
|
|
||||||
* $input = file_get_contents('php://input', 1000000);
|
|
||||||
* $value = $json->decode($input);
|
|
||||||
* </code>
|
|
||||||
*/
|
|
||||||
class Services_JSON
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* constructs a new JSON instance
|
|
||||||
*
|
|
||||||
* @param int $use object behavior flags; combine with boolean-OR
|
|
||||||
*
|
|
||||||
* possible values:
|
|
||||||
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
|
||||||
* "{...}" syntax creates associative arrays
|
|
||||||
* instead of objects in decode().
|
|
||||||
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
|
||||||
* Values which can't be encoded (e.g. resources)
|
|
||||||
* appear as NULL instead of throwing errors.
|
|
||||||
* By default, a deeply-nested resource will
|
|
||||||
* bubble up with an error, so all return values
|
|
||||||
* from encode() should be checked with isError()
|
|
||||||
*/
|
|
||||||
function Services_JSON($use = 0)
|
|
||||||
{
|
|
||||||
$this->use = $use;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convert a string from one UTF-16 char to one UTF-8 char
|
|
||||||
*
|
|
||||||
* Normally should be handled by mb_convert_encoding, but
|
|
||||||
* provides a slower PHP-only method for installations
|
|
||||||
* that lack the multibye string extension.
|
|
||||||
*
|
|
||||||
* @param string $utf16 UTF-16 character
|
|
||||||
* @return string UTF-8 character
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function utf162utf8($utf16)
|
|
||||||
{
|
|
||||||
// oh please oh please oh please oh please oh please
|
|
||||||
if(function_exists('mb_convert_encoding')) {
|
|
||||||
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
|
||||||
}
|
|
||||||
|
|
||||||
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
|
|
||||||
|
|
||||||
switch(true) {
|
|
||||||
case ((0x7F & $bytes) == $bytes):
|
|
||||||
// this case should never be reached, because we are in ASCII range
|
|
||||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
return chr(0x7F & $bytes);
|
|
||||||
|
|
||||||
case (0x07FF & $bytes) == $bytes:
|
|
||||||
// return a 2-byte UTF-8 character
|
|
||||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
|
||||||
. chr(0x80 | ($bytes & 0x3F));
|
|
||||||
|
|
||||||
case (0xFFFF & $bytes) == $bytes:
|
|
||||||
// return a 3-byte UTF-8 character
|
|
||||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
|
||||||
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
|
||||||
. chr(0x80 | ($bytes & 0x3F));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignoring UTF-32 for now, sorry
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convert a string from one UTF-8 char to one UTF-16 char
|
|
||||||
*
|
|
||||||
* Normally should be handled by mb_convert_encoding, but
|
|
||||||
* provides a slower PHP-only method for installations
|
|
||||||
* that lack the multibye string extension.
|
|
||||||
*
|
|
||||||
* @param string $utf8 UTF-8 character
|
|
||||||
* @return string UTF-16 character
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function utf82utf16($utf8)
|
|
||||||
{
|
|
||||||
// oh please oh please oh please oh please oh please
|
|
||||||
if(function_exists('mb_convert_encoding')) {
|
|
||||||
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(strlen($utf8)) {
|
|
||||||
case 1:
|
|
||||||
// this case should never be reached, because we are in ASCII range
|
|
||||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
return $utf8;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
// return a UTF-16 character from a 2-byte UTF-8 char
|
|
||||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
return chr(0x07 & (ord($utf8{0}) >> 2))
|
|
||||||
. chr((0xC0 & (ord($utf8{0}) << 6))
|
|
||||||
| (0x3F & ord($utf8{1})));
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
// return a UTF-16 character from a 3-byte UTF-8 char
|
|
||||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
return chr((0xF0 & (ord($utf8{0}) << 4))
|
|
||||||
| (0x0F & (ord($utf8{1}) >> 2)))
|
|
||||||
. chr((0xC0 & (ord($utf8{1}) << 6))
|
|
||||||
| (0x7F & ord($utf8{2})));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignoring UTF-32 for now, sorry
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* encodes an arbitrary variable into JSON format
|
|
||||||
*
|
|
||||||
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
|
||||||
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
|
||||||
* if var is a strng, note that encode() always expects it
|
|
||||||
* to be in ASCII or UTF-8 format!
|
|
||||||
*
|
|
||||||
* @return mixed JSON string representation of input var or an error if a problem occurs
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
function encode($var)
|
|
||||||
{
|
|
||||||
switch (gettype($var)) {
|
|
||||||
case 'boolean':
|
|
||||||
return $var ? 'true' : 'false';
|
|
||||||
|
|
||||||
case 'NULL':
|
|
||||||
return 'null';
|
|
||||||
|
|
||||||
case 'integer':
|
|
||||||
return (int) $var;
|
|
||||||
|
|
||||||
case 'double':
|
|
||||||
case 'float':
|
|
||||||
return (float) $var;
|
|
||||||
|
|
||||||
case 'string':
|
|
||||||
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
|
||||||
$ascii = '';
|
|
||||||
$strlen_var = strlen($var);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Iterate over every character in the string,
|
|
||||||
* escaping with a slash or encoding to UTF-8 where necessary
|
|
||||||
*/
|
|
||||||
for ($c = 0; $c < $strlen_var; ++$c) {
|
|
||||||
|
|
||||||
$ord_var_c = ord($var{$c});
|
|
||||||
|
|
||||||
switch (true) {
|
|
||||||
case $ord_var_c == 0x08:
|
|
||||||
$ascii .= '\b';
|
|
||||||
break;
|
|
||||||
case $ord_var_c == 0x09:
|
|
||||||
$ascii .= '\t';
|
|
||||||
break;
|
|
||||||
case $ord_var_c == 0x0A:
|
|
||||||
$ascii .= '\n';
|
|
||||||
break;
|
|
||||||
case $ord_var_c == 0x0C:
|
|
||||||
$ascii .= '\f';
|
|
||||||
break;
|
|
||||||
case $ord_var_c == 0x0D:
|
|
||||||
$ascii .= '\r';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case $ord_var_c == 0x22:
|
|
||||||
case $ord_var_c == 0x2F:
|
|
||||||
case $ord_var_c == 0x5C:
|
|
||||||
// double quote, slash, slosh
|
|
||||||
$ascii .= '\\'.$var{$c};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
|
||||||
// characters U-00000000 - U-0000007F (same as ASCII)
|
|
||||||
$ascii .= $var{$c};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (($ord_var_c & 0xE0) == 0xC0):
|
|
||||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
|
|
||||||
$c += 1;
|
|
||||||
$utf16 = $this->utf82utf16($char);
|
|
||||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (($ord_var_c & 0xF0) == 0xE0):
|
|
||||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$char = pack('C*', $ord_var_c,
|
|
||||||
ord($var{$c + 1}),
|
|
||||||
ord($var{$c + 2}));
|
|
||||||
$c += 2;
|
|
||||||
$utf16 = $this->utf82utf16($char);
|
|
||||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (($ord_var_c & 0xF8) == 0xF0):
|
|
||||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$char = pack('C*', $ord_var_c,
|
|
||||||
ord($var{$c + 1}),
|
|
||||||
ord($var{$c + 2}),
|
|
||||||
ord($var{$c + 3}));
|
|
||||||
$c += 3;
|
|
||||||
$utf16 = $this->utf82utf16($char);
|
|
||||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (($ord_var_c & 0xFC) == 0xF8):
|
|
||||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$char = pack('C*', $ord_var_c,
|
|
||||||
ord($var{$c + 1}),
|
|
||||||
ord($var{$c + 2}),
|
|
||||||
ord($var{$c + 3}),
|
|
||||||
ord($var{$c + 4}));
|
|
||||||
$c += 4;
|
|
||||||
$utf16 = $this->utf82utf16($char);
|
|
||||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (($ord_var_c & 0xFE) == 0xFC):
|
|
||||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$char = pack('C*', $ord_var_c,
|
|
||||||
ord($var{$c + 1}),
|
|
||||||
ord($var{$c + 2}),
|
|
||||||
ord($var{$c + 3}),
|
|
||||||
ord($var{$c + 4}),
|
|
||||||
ord($var{$c + 5}));
|
|
||||||
$c += 5;
|
|
||||||
$utf16 = $this->utf82utf16($char);
|
|
||||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '"'.$ascii.'"';
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
/*
|
|
||||||
* As per JSON spec if any array key is not an integer
|
|
||||||
* we must treat the the whole array as an object. We
|
|
||||||
* also try to catch a sparsely populated associative
|
|
||||||
* array with numeric keys here because some JS engines
|
|
||||||
* will create an array with empty indexes up to
|
|
||||||
* max_index which can cause memory issues and because
|
|
||||||
* the keys, which may be relevant, will be remapped
|
|
||||||
* otherwise.
|
|
||||||
*
|
|
||||||
* As per the ECMA and JSON specification an object may
|
|
||||||
* have any string as a property. Unfortunately due to
|
|
||||||
* a hole in the ECMA specification if the key is a
|
|
||||||
* ECMA reserved word or starts with a digit the
|
|
||||||
* parameter is only accessible using ECMAScript's
|
|
||||||
* bracket notation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// treat as a JSON object
|
|
||||||
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
|
||||||
$properties = array_map(array($this, 'name_value'),
|
|
||||||
array_keys($var),
|
|
||||||
array_values($var));
|
|
||||||
|
|
||||||
foreach($properties as $property) {
|
|
||||||
if(Services_JSON::isError($property)) {
|
|
||||||
return $property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '{' . join(',', $properties) . '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
// treat it like a regular array
|
|
||||||
$elements = array_map(array($this, 'encode'), $var);
|
|
||||||
|
|
||||||
foreach($elements as $element) {
|
|
||||||
if(Services_JSON::isError($element)) {
|
|
||||||
return $element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '[' . join(',', $elements) . ']';
|
|
||||||
|
|
||||||
case 'object':
|
|
||||||
$vars = get_object_vars($var);
|
|
||||||
|
|
||||||
$properties = array_map(array($this, 'name_value'),
|
|
||||||
array_keys($vars),
|
|
||||||
array_values($vars));
|
|
||||||
|
|
||||||
foreach($properties as $property) {
|
|
||||||
if(Services_JSON::isError($property)) {
|
|
||||||
return $property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '{' . join(',', $properties) . '}';
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
|
||||||
? 'null'
|
|
||||||
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* array-walking function for use in generating JSON-formatted name-value pairs
|
|
||||||
*
|
|
||||||
* @param string $name name of key to use
|
|
||||||
* @param mixed $value reference to an array element to be encoded
|
|
||||||
*
|
|
||||||
* @return string JSON-formatted name-value pair, like '"name":value'
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function name_value($name, $value)
|
|
||||||
{
|
|
||||||
$encoded_value = $this->encode($value);
|
|
||||||
|
|
||||||
if(Services_JSON::isError($encoded_value)) {
|
|
||||||
return $encoded_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->encode(strval($name)) . ':' . $encoded_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reduce a string by removing leading and trailing comments and whitespace
|
|
||||||
*
|
|
||||||
* @param $str string string value to strip of comments and whitespace
|
|
||||||
*
|
|
||||||
* @return string string value stripped of comments and whitespace
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function reduce_string($str)
|
|
||||||
{
|
|
||||||
$str = preg_replace(array(
|
|
||||||
|
|
||||||
// eliminate single line comments in '// ...' form
|
|
||||||
'#^\s*//(.+)$#m',
|
|
||||||
|
|
||||||
// eliminate multi-line comments in '/* ... */' form, at start of string
|
|
||||||
'#^\s*/\*(.+)\*/#Us',
|
|
||||||
|
|
||||||
// eliminate multi-line comments in '/* ... */' form, at end of string
|
|
||||||
'#/\*(.+)\*/\s*$#Us'
|
|
||||||
|
|
||||||
), '', $str);
|
|
||||||
|
|
||||||
// eliminate extraneous space
|
|
||||||
return trim($str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* decodes a JSON string into appropriate variable
|
|
||||||
*
|
|
||||||
* @param string $str JSON-formatted string
|
|
||||||
*
|
|
||||||
* @return mixed number, boolean, string, array, or object
|
|
||||||
* corresponding to given JSON input string.
|
|
||||||
* See argument 1 to Services_JSON() above for object-output behavior.
|
|
||||||
* Note that decode() always returns strings
|
|
||||||
* in ASCII or UTF-8 format!
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
function decode($str)
|
|
||||||
{
|
|
||||||
$str = $this->reduce_string($str);
|
|
||||||
|
|
||||||
switch (strtolower($str)) {
|
|
||||||
case 'true':
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 'false':
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case 'null':
|
|
||||||
return null;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$m = array();
|
|
||||||
|
|
||||||
if (is_numeric($str)) {
|
|
||||||
// Lookie-loo, it's a number
|
|
||||||
|
|
||||||
// This would work on its own, but I'm trying to be
|
|
||||||
// good about returning integers where appropriate:
|
|
||||||
// return (float)$str;
|
|
||||||
|
|
||||||
// Return float or int, as appropriate
|
|
||||||
return ((float)$str == (integer)$str)
|
|
||||||
? (integer)$str
|
|
||||||
: (float)$str;
|
|
||||||
|
|
||||||
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
|
||||||
// STRINGS RETURNED IN UTF-8 FORMAT
|
|
||||||
$delim = substr($str, 0, 1);
|
|
||||||
$chrs = substr($str, 1, -1);
|
|
||||||
$utf8 = '';
|
|
||||||
$strlen_chrs = strlen($chrs);
|
|
||||||
|
|
||||||
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
|
||||||
|
|
||||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
|
||||||
$ord_chrs_c = ord($chrs{$c});
|
|
||||||
|
|
||||||
switch (true) {
|
|
||||||
case $substr_chrs_c_2 == '\b':
|
|
||||||
$utf8 .= chr(0x08);
|
|
||||||
++$c;
|
|
||||||
break;
|
|
||||||
case $substr_chrs_c_2 == '\t':
|
|
||||||
$utf8 .= chr(0x09);
|
|
||||||
++$c;
|
|
||||||
break;
|
|
||||||
case $substr_chrs_c_2 == '\n':
|
|
||||||
$utf8 .= chr(0x0A);
|
|
||||||
++$c;
|
|
||||||
break;
|
|
||||||
case $substr_chrs_c_2 == '\f':
|
|
||||||
$utf8 .= chr(0x0C);
|
|
||||||
++$c;
|
|
||||||
break;
|
|
||||||
case $substr_chrs_c_2 == '\r':
|
|
||||||
$utf8 .= chr(0x0D);
|
|
||||||
++$c;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case $substr_chrs_c_2 == '\\"':
|
|
||||||
case $substr_chrs_c_2 == '\\\'':
|
|
||||||
case $substr_chrs_c_2 == '\\\\':
|
|
||||||
case $substr_chrs_c_2 == '\\/':
|
|
||||||
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
|
||||||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
|
||||||
$utf8 .= $chrs{++$c};
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
|
|
||||||
// single, escaped unicode character
|
|
||||||
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
|
|
||||||
. chr(hexdec(substr($chrs, ($c + 4), 2)));
|
|
||||||
$utf8 .= $this->utf162utf8($utf16);
|
|
||||||
$c += 5;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
|
||||||
$utf8 .= $chrs{$c};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($ord_chrs_c & 0xE0) == 0xC0:
|
|
||||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
|
||||||
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$utf8 .= substr($chrs, $c, 2);
|
|
||||||
++$c;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($ord_chrs_c & 0xF0) == 0xE0:
|
|
||||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$utf8 .= substr($chrs, $c, 3);
|
|
||||||
$c += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($ord_chrs_c & 0xF8) == 0xF0:
|
|
||||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$utf8 .= substr($chrs, $c, 4);
|
|
||||||
$c += 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($ord_chrs_c & 0xFC) == 0xF8:
|
|
||||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$utf8 .= substr($chrs, $c, 5);
|
|
||||||
$c += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($ord_chrs_c & 0xFE) == 0xFC:
|
|
||||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
|
||||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
$utf8 .= substr($chrs, $c, 6);
|
|
||||||
$c += 5;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $utf8;
|
|
||||||
|
|
||||||
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
|
||||||
// array, or object notation
|
|
||||||
|
|
||||||
if ($str{0} == '[') {
|
|
||||||
$stk = array(SERVICES_JSON_IN_ARR);
|
|
||||||
$arr = array();
|
|
||||||
} else {
|
|
||||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
|
||||||
$stk = array(SERVICES_JSON_IN_OBJ);
|
|
||||||
$obj = array();
|
|
||||||
} else {
|
|
||||||
$stk = array(SERVICES_JSON_IN_OBJ);
|
|
||||||
$obj = new stdClass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
array_push($stk, array('what' => SERVICES_JSON_SLICE,
|
|
||||||
'where' => 0,
|
|
||||||
'delim' => false));
|
|
||||||
|
|
||||||
$chrs = substr($str, 1, -1);
|
|
||||||
$chrs = $this->reduce_string($chrs);
|
|
||||||
|
|
||||||
if ($chrs == '') {
|
|
||||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
|
||||||
return $arr;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return $obj;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//print("\nparsing {$chrs}\n");
|
|
||||||
|
|
||||||
$strlen_chrs = strlen($chrs);
|
|
||||||
|
|
||||||
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
|
||||||
|
|
||||||
$top = end($stk);
|
|
||||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
|
||||||
|
|
||||||
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
|
|
||||||
// found a comma that is not inside a string, array, etc.,
|
|
||||||
// OR we've reached the end of the character list
|
|
||||||
$slice = substr($chrs, $top['where'], ($c - $top['where']));
|
|
||||||
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
|
|
||||||
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
|
||||||
|
|
||||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
|
||||||
// we are in an array, so just push an element onto the stack
|
|
||||||
array_push($arr, $this->decode($slice));
|
|
||||||
|
|
||||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
|
||||||
// we are in an object, so figure
|
|
||||||
// out the property name and set an
|
|
||||||
// element in an associative array,
|
|
||||||
// for now
|
|
||||||
$parts = array();
|
|
||||||
|
|
||||||
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
|
||||||
// "name":value pair
|
|
||||||
$key = $this->decode($parts[1]);
|
|
||||||
$val = $this->decode($parts[2]);
|
|
||||||
|
|
||||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
|
||||||
$obj[$key] = $val;
|
|
||||||
} else {
|
|
||||||
$obj->$key = $val;
|
|
||||||
}
|
|
||||||
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
|
||||||
// name:value pair, where name is unquoted
|
|
||||||
$key = $parts[1];
|
|
||||||
$val = $this->decode($parts[2]);
|
|
||||||
|
|
||||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
|
||||||
$obj[$key] = $val;
|
|
||||||
} else {
|
|
||||||
$obj->$key = $val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
|
|
||||||
// found a quote, and we are not inside a string
|
|
||||||
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
|
|
||||||
//print("Found start of string at {$c}\n");
|
|
||||||
|
|
||||||
} elseif (($chrs{$c} == $top['delim']) &&
|
|
||||||
($top['what'] == SERVICES_JSON_IN_STR) &&
|
|
||||||
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
|
|
||||||
// found a quote, we're in a string, and it's not escaped
|
|
||||||
// we know that it's not escaped becase there is _not_ an
|
|
||||||
// odd number of backslashes at the end of the string so far
|
|
||||||
array_pop($stk);
|
|
||||||
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
|
||||||
|
|
||||||
} elseif (($chrs{$c} == '[') &&
|
|
||||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
|
||||||
// found a left-bracket, and we are in an array, object, or slice
|
|
||||||
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
|
|
||||||
//print("Found start of array at {$c}\n");
|
|
||||||
|
|
||||||
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
|
|
||||||
// found a right-bracket, and we're in an array
|
|
||||||
array_pop($stk);
|
|
||||||
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
|
||||||
|
|
||||||
} elseif (($chrs{$c} == '{') &&
|
|
||||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
|
||||||
// found a left-brace, and we are in an array, object, or slice
|
|
||||||
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
|
|
||||||
//print("Found start of object at {$c}\n");
|
|
||||||
|
|
||||||
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
|
|
||||||
// found a right-brace, and we're in an object
|
|
||||||
array_pop($stk);
|
|
||||||
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
|
||||||
|
|
||||||
} elseif (($substr_chrs_c_2 == '/*') &&
|
|
||||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
|
||||||
// found a comment start, and we are in an array, object, or slice
|
|
||||||
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
|
|
||||||
$c++;
|
|
||||||
//print("Found start of comment at {$c}\n");
|
|
||||||
|
|
||||||
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
|
|
||||||
// found a comment end, and we're in one now
|
|
||||||
array_pop($stk);
|
|
||||||
$c++;
|
|
||||||
|
|
||||||
for ($i = $top['where']; $i <= $c; ++$i)
|
|
||||||
$chrs = substr_replace($chrs, ' ', $i, 1);
|
|
||||||
|
|
||||||
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
|
||||||
return $arr;
|
|
||||||
|
|
||||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
|
||||||
return $obj;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Ultimately, this should just call PEAR::isError()
|
|
||||||
*/
|
|
||||||
function isError($data, $code = null)
|
|
||||||
{
|
|
||||||
if (class_exists('pear')) {
|
|
||||||
return PEAR::isError($data, $code);
|
|
||||||
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
|
|
||||||
is_subclass_of($data, 'services_json_error'))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (class_exists('PEAR_Error')) {
|
|
||||||
|
|
||||||
class Services_JSON_Error extends PEAR_Error
|
|
||||||
{
|
|
||||||
function Services_JSON_Error($message = 'unknown error', $code = null,
|
|
||||||
$mode = null, $options = null, $userinfo = null)
|
|
||||||
{
|
|
||||||
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Ultimately, this class shall be descended from PEAR_Error
|
|
||||||
*/
|
|
||||||
class Services_JSON_Error
|
|
||||||
{
|
|
||||||
function Services_JSON_Error($message = 'unknown error', $code = null,
|
|
||||||
$mode = null, $options = null, $userinfo = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
64
vendors/ayah-1.1.7/sample.php
vendored
64
vendors/ayah-1.1.7/sample.php
vendored
|
@ -1,64 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<?php
|
|
||||||
//******************************************************************************
|
|
||||||
/*
|
|
||||||
Name: sample.php
|
|
||||||
|
|
||||||
Purpose: Provide an example of how to integrate an AYAH PlayThru on PHP web form.
|
|
||||||
|
|
||||||
Requirements:
|
|
||||||
- your web server uses PHP5 (or higher).
|
|
||||||
- all the AYAH PHP library files are in the same directory as this file.
|
|
||||||
- the ayah_config.php contains a valid publisher key and scoring key.
|
|
||||||
- you have read the installation instructions page at:
|
|
||||||
http://portal.areyouahuman.com/installation/php
|
|
||||||
|
|
||||||
Notes: - if the Game Style for your PlayThru is set to "Lightbox", the
|
|
||||||
PlayThru will not display until after you click the submit button.
|
|
||||||
To change this setting, use the dashboard at:
|
|
||||||
http://portal.areyouahuman.com/dashboard.php
|
|
||||||
*/
|
|
||||||
//******************************************************************************
|
|
||||||
|
|
||||||
// Instantiate the AYAH object. You need to instantiate the AYAH object
|
|
||||||
// on each page that is using PlayThru.
|
|
||||||
require_once("ayah.php");
|
|
||||||
$ayah = new AYAH();
|
|
||||||
|
|
||||||
// Check to see if the user has submitted the form. You will need to replace
|
|
||||||
// 'my_submit_button_name' with the name of your 'Submit' button.
|
|
||||||
if (array_key_exists('my_submit_button_name', $_POST))
|
|
||||||
{
|
|
||||||
// Use the AYAH object to see if the user passed or failed the game.
|
|
||||||
$score = $ayah->scoreResult();
|
|
||||||
|
|
||||||
if ($score)
|
|
||||||
{
|
|
||||||
// This happens if the user passes the game. In this case,
|
|
||||||
// we're just displaying a congratulatory message.
|
|
||||||
echo "Congratulations: you are a human!";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This happens if the user does not pass the game.
|
|
||||||
echo "Sorry, but we were not able to verify you as human. Please try again.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- Now we're going to build the form that PlayThru is attached to.
|
|
||||||
In this example, the form submits to itself. -->
|
|
||||||
<form method="post" action="">
|
|
||||||
|
|
||||||
<p>Please enter your name: <input type="text" name="name" /></p>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
// Use the AYAH object to get the HTML code needed to
|
|
||||||
// load and run PlayThru. You should place this code
|
|
||||||
// directly before your 'Submit' button.
|
|
||||||
echo $ayah->getPublisherHTML();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- Make sure the name of your 'Submit' matches the name you used on line 9. -->
|
|
||||||
<input type="Submit" name="my_submit_button_name" value=" Submit ">
|
|
||||||
</form>
|
|
32
vendors/php-test-helpers/.gitignore
vendored
32
vendors/php-test-helpers/.gitignore
vendored
|
@ -1,32 +0,0 @@
|
||||||
.deps
|
|
||||||
.libs
|
|
||||||
build
|
|
||||||
modules
|
|
||||||
*.lo
|
|
||||||
*.loT
|
|
||||||
*.la
|
|
||||||
Makefile
|
|
||||||
Makefile.fragments
|
|
||||||
Makefile.global
|
|
||||||
Makefile.objects
|
|
||||||
acinclude.m4
|
|
||||||
aclocal.m4
|
|
||||||
config.cache
|
|
||||||
config.guess
|
|
||||||
config.h
|
|
||||||
config.h.in
|
|
||||||
config.log
|
|
||||||
config.nice
|
|
||||||
config.status
|
|
||||||
config.sub
|
|
||||||
configure
|
|
||||||
configure.in
|
|
||||||
install-sh
|
|
||||||
libtool
|
|
||||||
ltmain.sh
|
|
||||||
missing
|
|
||||||
mkinstalldirs
|
|
||||||
run-tests.php
|
|
||||||
test.ini
|
|
||||||
tmp-php.ini
|
|
||||||
autom4te.cache
|
|
15
vendors/php-test-helpers/.travis.yml
vendored
15
vendors/php-test-helpers/.travis.yml
vendored
|
@ -1,15 +0,0 @@
|
||||||
language: php
|
|
||||||
|
|
||||||
php:
|
|
||||||
- 5.3
|
|
||||||
- 5.4
|
|
||||||
- 5.5
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- phpize
|
|
||||||
- ./configure --enable-test-helpers
|
|
||||||
- make
|
|
||||||
- sed -i -e 's/save_or_mail_results();//g' -e 's/\($failed_test_data\['\''test_name'\''\] . $failed_test_data\['\''info'\''\]\)/str_repeat('\''='\'', 80) . "\\n" . \1 . "\\n" . str_repeat('\''='\'', 80) . "\\n" . file_get_contents(realpath($failed_test_data['\''output'\'']), FILE_BINARY) . "\\n" . str_repeat('\''='\'', 80) . "\\n" . file_get_contents(realpath($failed_test_data['\''diff'\'']), FILE_BINARY)/g' run-tests.php
|
|
||||||
- sed -i -e 's/-\(@if test ! -z\)/\1/' -e 's/rm $(top_builddir)\/tmp-php.ini;//' -e 's/^\(.*TEST_PHP_EXECUTABLE=$(PHP_EXECUTABLE) \\\)/\t\t$(SED) -i '\''s\/^\\(.*xdebug.so\\)\/;\\1\/'\'' $\(top_builddir\)\/tmp-php.ini; \\\n\1/' Makefile
|
|
||||||
|
|
||||||
script: REPORT_EXIT_STATUS=1 make test
|
|
2
vendors/php-test-helpers/CREDITS
vendored
2
vendors/php-test-helpers/CREDITS
vendored
|
@ -1,2 +0,0 @@
|
||||||
test_helpers
|
|
||||||
Sebastian Bergmann, Johannes Schlüter
|
|
197
vendors/php-test-helpers/README.markdown
vendored
197
vendors/php-test-helpers/README.markdown
vendored
|
@ -1,197 +0,0 @@
|
||||||
# ext/test_helpers #
|
|
||||||
|
|
||||||
`ext/test_helpers` is an extension for the PHP Interpreter to ease testing of PHP code.
|
|
||||||
|
|
||||||
## Installation ##
|
|
||||||
|
|
||||||
`ext/test_helpers` should be installed using the [PEAR Installer](http://pear.php.net/). This installer is the backbone of PEAR and PECL, which provides a distribution system for PHP packages and extensions, and is shipped with every release of PHP since version 4.3.0.
|
|
||||||
|
|
||||||
The PEAR channel (`pear.phpunit.de`) that is used to distribute `ext/test_helpers` needs to be registered with the local PEAR environment:
|
|
||||||
|
|
||||||
sb@ubuntu ~ % pear channel-discover pear.phpunit.de
|
|
||||||
Adding Channel "pear.phpunit.de" succeeded
|
|
||||||
Discovery of channel "pear.phpunit.de" succeeded
|
|
||||||
|
|
||||||
This has to be done only once. Now the PEAR Installer can be used to install extensions and packages from the PHPUnit channel:
|
|
||||||
|
|
||||||
sb@ubuntu ~ % pecl install phpunit/test_helpers
|
|
||||||
downloading test_helpers-1.0.0.tgz ...
|
|
||||||
Starting to download test_helpers-1.0.0.tgz (6,980 bytes)
|
|
||||||
.....done: 6,980 bytes
|
|
||||||
4 source files, building
|
|
||||||
.
|
|
||||||
.
|
|
||||||
.
|
|
||||||
install ok: channel://pear.phpunit.de/test_helpers-1.0.0
|
|
||||||
You should add "extension=test_helpers.so" to php.ini
|
|
||||||
|
|
||||||
Further information about building stand-alone extensions for PHP can be found in the [Installation of PECL extensions](http://php.net/install.pecl) section of the PHP manual.
|
|
||||||
|
|
||||||
## Usage ##
|
|
||||||
|
|
||||||
### Intercepting the Exit Statement ###
|
|
||||||
|
|
||||||
When a [unit test](http://en.wikipedia.org/wiki/Unit_test) exercises code that contains an `exit` / `die` statement, the execution of the whole test suite is aborted. This is not a good thing.
|
|
||||||
|
|
||||||
With the `set_exit_overload()` function it is possible to overload the `exit` / `die` statement and make it a no-op, for instance:
|
|
||||||
|
|
||||||
<?php
|
|
||||||
set_exit_overload(function() { return FALSE; });
|
|
||||||
exit;
|
|
||||||
print 'We did not exit.';
|
|
||||||
unset_exit_overload();
|
|
||||||
exit;
|
|
||||||
print 'We exited and this will not be printed.';
|
|
||||||
?>
|
|
||||||
|
|
||||||
The code above will output
|
|
||||||
|
|
||||||
We did not exit.
|
|
||||||
|
|
||||||
The callback registered by `set_exit_overload()` might receive a parameter in case `exit` / `die` was called with a parameter:
|
|
||||||
|
|
||||||
<?php
|
|
||||||
set_exit_overload(function($param = NULL) { echo ($param ?: "No value given"), "\n"; return FALSE; }
|
|
||||||
die("Hello");
|
|
||||||
die;
|
|
||||||
?>
|
|
||||||
|
|
||||||
The code above will output
|
|
||||||
|
|
||||||
Hello
|
|
||||||
No value given
|
|
||||||
|
|
||||||
Another way of dealing with low-level functions and statements such as `die()` and `exit` is to wrap them in a proxy that by default (in production) delegates to the native implementation but for testing has a "testable" behaviour.
|
|
||||||
|
|
||||||
### Intercepting Object Creation ###
|
|
||||||
|
|
||||||
In a [unit test](http://en.wikipedia.org/wiki/Unit_test), [mock objects](http://en.wikipedia.org/wiki/Mock_Object) can simulate the behavior of complex, real (non-mock) objects and are therefore useful when a real object is difficult or impossible to incorporate into a unit test.
|
|
||||||
|
|
||||||
A mock object can be used anywhere in the program where the program expects an object of the mocked class. However, this only works as long as the object can be passed into the context where the original object is used.
|
|
||||||
|
|
||||||
Consider the following example:
|
|
||||||
|
|
||||||
<?php
|
|
||||||
class SomeClass
|
|
||||||
{
|
|
||||||
public function doSomething()
|
|
||||||
{
|
|
||||||
$object = new SomeOtherClass;
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
With the code above, it is impossible to run a unit test for the `SomeClass::doSomething()` method without also creating an object of `SomeOtherClass`. As the method creates the object of `SomeOtherClass` itself, we cannot inject a mock object in its stead.
|
|
||||||
|
|
||||||
In a perfect world, code such as the above could be refactored using [Dependency Injection](http://en.wikipedia.org/wiki/Dependency_Injection):
|
|
||||||
|
|
||||||
<?php
|
|
||||||
class SomeClass
|
|
||||||
{
|
|
||||||
protected $object;
|
|
||||||
|
|
||||||
public function __construct(SomeOtherClass $object)
|
|
||||||
{
|
|
||||||
$this->object = $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function doSomething()
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
Unfortunately, this is not always possible (not because of technical reasons, though).
|
|
||||||
|
|
||||||
This is where the `set_new_overload()` function comes into play. It can be used to register a [callback](http://www.php.net/manual/en/language.pseudo-types.php) that is automatically invoked when the `new` operator is executed:
|
|
||||||
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback($className) {
|
|
||||||
if ($className == 'Foo') {
|
|
||||||
$className = 'Bar';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $className;
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(get_class(new Foo));
|
|
||||||
|
|
||||||
set_new_overload('callback');
|
|
||||||
var_dump(get_class(new Foo));
|
|
||||||
?>
|
|
||||||
|
|
||||||
string(3) "Foo"
|
|
||||||
string(3) "Bar"
|
|
||||||
|
|
||||||
The `new` operator callback can be unset when it is no longer required:
|
|
||||||
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback($className) {
|
|
||||||
return 'Bar';
|
|
||||||
}
|
|
||||||
|
|
||||||
set_new_overload('callback');
|
|
||||||
var_dump(get_class(new Foo));
|
|
||||||
|
|
||||||
unset_new_overload();
|
|
||||||
var_dump(get_class(new Foo));
|
|
||||||
?>
|
|
||||||
|
|
||||||
string(3) "Bar"
|
|
||||||
string(3) "Foo"
|
|
||||||
|
|
||||||
#### Class Posing ####
|
|
||||||
|
|
||||||
The `set_new_overload()` function can be used to implement a programming language feature named *Class Posing*. [The implementation of Class Posing in Objective-C](http://en.wikipedia.org/wiki/Objective-C#Posing), for instance, permits a class to wholly replace another class within a program. The replacing class is said to "pose as" the target class.
|
|
||||||
|
|
||||||
Class Posing has the following restrictions
|
|
||||||
|
|
||||||
* A class may only pose as one of its direct or indirect superclasses
|
|
||||||
* The posing class must not define any new instance variables which are absent from the target class (though it may define or override methods).
|
|
||||||
* The target class may not have received any messages prior to the posing.
|
|
||||||
|
|
||||||
These restrictions are not enforced by `ext/test_helpers` because the extension is only intended to ease the development of unit tests (for legacy software systems that cannot be refactored to use Dependency Injection).
|
|
||||||
|
|
||||||
### Renaming Functions ###
|
|
||||||
|
|
||||||
The `rename_function()` function can be used to rename function:
|
|
||||||
|
|
||||||
<?php
|
|
||||||
function foo()
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
function foo_stub()
|
|
||||||
{
|
|
||||||
return 'stubbed result';
|
|
||||||
}
|
|
||||||
|
|
||||||
rename_function('foo', 'foo_orig');
|
|
||||||
rename_function('foo_stub', 'foo');
|
|
||||||
var_dump(foo());
|
|
||||||
rename_function('foo', 'foo_stub');
|
|
||||||
rename_function('foo_orig', 'foo');
|
|
||||||
?>
|
|
||||||
|
|
||||||
string(14) "stubbed result"
|
|
||||||
|
|
||||||
This allows the stubbing/mocking of functions.
|
|
||||||
|
|
||||||
## Notes ##
|
|
||||||
|
|
||||||
If this extension is used in combination with other extensions, such as Xdebug, which are also overloading the `ZEND_NEW` opcode you have to load it as `zend_extension` after loading the conflicting extension. This can be done in your `php.ini` like this:
|
|
||||||
|
|
||||||
zend_extension=xdebug.so
|
|
||||||
zend_extension=test-helpers.so
|
|
||||||
|
|
||||||
Please refer to `phpinfo()` to verify whether a conflict was detected and whether the work-around was enabled.
|
|
||||||
|
|
6
vendors/php-test-helpers/config.m4
vendored
6
vendors/php-test-helpers/config.m4
vendored
|
@ -1,6 +0,0 @@
|
||||||
PHP_ARG_ENABLE(test_helpers, whether to enable test_helpers support,
|
|
||||||
[ --enable-test-helpers Enable test_helpers support])
|
|
||||||
|
|
||||||
if test "$PHP_TEST_HELPERS" != "no"; then
|
|
||||||
PHP_NEW_EXTENSION(test_helpers, test_helpers.c, $ext_shared)
|
|
||||||
fi
|
|
6
vendors/php-test-helpers/config.w32
vendored
6
vendors/php-test-helpers/config.w32
vendored
|
@ -1,6 +0,0 @@
|
||||||
ARG_ENABLE("test_helpers", "enable test_helpers support", "no");
|
|
||||||
|
|
||||||
if (PHP_TEST_HELPERS != "no") {
|
|
||||||
EXTENSION("test_helpers", "test_helpers.c");
|
|
||||||
}
|
|
||||||
|
|
75
vendors/php-test-helpers/package.xml
vendored
75
vendors/php-test-helpers/package.xml
vendored
|
@ -1,75 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<package packagerversion="1.4.9"
|
|
||||||
version="2.0"
|
|
||||||
xmlns="http://pear.php.net/dtd/package-2.0"
|
|
||||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
|
||||||
http://pear.php.net/dtd/tasks-1.0.xsd
|
|
||||||
http://pear.php.net/dtd/package-2.0
|
|
||||||
http://pear.php.net/dtd/package-2.0.xsd">
|
|
||||||
<name>test_helpers</name>
|
|
||||||
<channel>pear.phpunit.de</channel>
|
|
||||||
<summary>An extension for the PHP Interpreter to ease testing of PHP code.</summary>
|
|
||||||
<description>An extension for the PHP Interpreter to ease testing of PHP code.</description>
|
|
||||||
<lead>
|
|
||||||
<name>Sebastian Bergmann</name>
|
|
||||||
<user>sebastian</user>
|
|
||||||
<email>sebastian@php.net</email>
|
|
||||||
<active>yes</active>
|
|
||||||
</lead>
|
|
||||||
<lead>
|
|
||||||
<name>Johannes Schlueter</name>
|
|
||||||
<user>johannes</user>
|
|
||||||
<email>johannes@php.net</email>
|
|
||||||
<active>yes</active>
|
|
||||||
</lead>
|
|
||||||
<date>2010-10-25</date>
|
|
||||||
<version>
|
|
||||||
<release>1.1.0</release>
|
|
||||||
<api>1.1.0</api>
|
|
||||||
</version>
|
|
||||||
<stability>
|
|
||||||
<release>stable</release>
|
|
||||||
<api>stable</api>
|
|
||||||
</stability>
|
|
||||||
<license>BSD License</license>
|
|
||||||
<notes>http://github.com/sebastianbergmann/php-test-helpers</notes>
|
|
||||||
<contents>
|
|
||||||
<dir name="/">
|
|
||||||
<dir name="tests">
|
|
||||||
<file name="set_exit_overload.phpt" role="test" />
|
|
||||||
<file name="unset_exit_overload.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_closure.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_error_non_existing_class.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_error_return_non_existing_class.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_error_undefined_callback.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_function.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_functor.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_multiple.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_non_static_method.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_non_static_method_same_object.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_private_method.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_static_method.phpt" role="test" />
|
|
||||||
<file name="set_new_overload_unset_reset.phpt" role="test" />
|
|
||||||
</dir>
|
|
||||||
<file name="config.m4" role="src" />
|
|
||||||
<file name="config.w32" role="src" />
|
|
||||||
<file name="php_test_helpers.h" role="src" />
|
|
||||||
<file name="README.markdown" role="doc" />
|
|
||||||
<file name="test_helpers.c" role="src" />
|
|
||||||
</dir>
|
|
||||||
</contents>
|
|
||||||
<dependencies>
|
|
||||||
<required>
|
|
||||||
<php>
|
|
||||||
<min>5.2.1</min>
|
|
||||||
</php>
|
|
||||||
<pearinstaller>
|
|
||||||
<min>1.4.0b1</min>
|
|
||||||
</pearinstaller>
|
|
||||||
</required>
|
|
||||||
</dependencies>
|
|
||||||
<providesextension>test_helpers</providesextension>
|
|
||||||
<extsrcrelease />
|
|
||||||
</package>
|
|
59
vendors/php-test-helpers/php_test_helpers.h
vendored
59
vendors/php-test-helpers/php_test_helpers.h
vendored
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| ext/test_helper |
|
|
||||||
| An extension for the PHP Interpreter to ease testing of PHP code. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2009-2013 Sebastian Bergmann. All rights reserved. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Redistribution and use in source and binary forms, with or without |
|
|
||||||
| modification, are permitted provided that the following conditions |
|
|
||||||
| are met: |
|
|
||||||
| |
|
|
||||||
| * Redistributions of source code must retain the above copyright |
|
|
||||||
| notice, this list of conditions and the following disclaimer. |
|
|
||||||
| |
|
|
||||||
| * Redistributions in binary form must reproduce the above copyright |
|
|
||||||
| notice, this list of conditions and the following disclaimer in |
|
|
||||||
| the documentation and/or other materials provided with the |
|
|
||||||
| distribution. |
|
|
||||||
| |
|
|
||||||
| * Neither the name of Sebastian Bergmann nor the names of his |
|
|
||||||
| contributors may be used to endorse or promote products derived |
|
|
||||||
| from this software without specific prior written permission. |
|
|
||||||
| |
|
|
||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
|
||||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
|
||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
|
||||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
|
||||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
|
||||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
|
||||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
|
||||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
|
||||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
|
||||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
|
||||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
|
||||||
| POSSIBILITY OF SUCH DAMAGE. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Author: Sebastian Bergmann <sb@sebastian-bergmann.de> |
|
|
||||||
| Johannes Schlüter <johannes@schlueters.de> |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PHP_TEST_HELPERS_H
|
|
||||||
#define PHP_TEST_HELPERS_H
|
|
||||||
|
|
||||||
extern zend_module_entry test_helpers_module_entry;
|
|
||||||
#define phpext_test_helpers_ptr &test_helpers_module_entry
|
|
||||||
|
|
||||||
#define TEST_HELPERS_VERSION "1.0.1-dev"
|
|
||||||
|
|
||||||
#endif /* PHP_TEST_HELPERS_H */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Local variables:
|
|
||||||
* tab-width: 4
|
|
||||||
* c-basic-offset: 4
|
|
||||||
* End:
|
|
||||||
* vim600: noet sw=4 ts=4 fdm=marker
|
|
||||||
* vim<600: noet sw=4 ts=4
|
|
||||||
*/
|
|
671
vendors/php-test-helpers/test_helpers.c
vendored
671
vendors/php-test-helpers/test_helpers.c
vendored
|
@ -1,671 +0,0 @@
|
||||||
/*
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| ext/test_helper |
|
|
||||||
| An extension for the PHP Interpreter to ease testing of PHP code. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2009-2013 Sebastian Bergmann. All rights reserved. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Redistribution and use in source and binary forms, with or without |
|
|
||||||
| modification, are permitted provided that the following conditions |
|
|
||||||
| are met: |
|
|
||||||
| |
|
|
||||||
| * Redistributions of source code must retain the above copyright |
|
|
||||||
| notice, this list of conditions and the following disclaimer. |
|
|
||||||
| |
|
|
||||||
| * Redistributions in binary form must reproduce the above copyright |
|
|
||||||
| notice, this list of conditions and the following disclaimer in |
|
|
||||||
| the documentation and/or other materials provided with the |
|
|
||||||
| distribution. |
|
|
||||||
| |
|
|
||||||
| * Neither the name of Sebastian Bergmann nor the names of his |
|
|
||||||
| contributors may be used to endorse or promote products derived |
|
|
||||||
| from this software without specific prior written permission. |
|
|
||||||
| |
|
|
||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
|
||||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
|
||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
|
||||||
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
|
||||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
|
||||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
|
||||||
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
|
||||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
|
||||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
|
||||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
|
||||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
|
||||||
| POSSIBILITY OF SUCH DAMAGE. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Author: Johannes Schlüter <johannes@schlueters.de> |
|
|
||||||
| Scott MacVicar <scott@macvicar.net> |
|
|
||||||
| Sebastian Bergmann <sb@sebastian-bergmann.de> |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "php.h"
|
|
||||||
#include "php_ini.h"
|
|
||||||
#include "ext/standard/info.h"
|
|
||||||
#include "php_test_helpers.h"
|
|
||||||
#include "Zend/zend_exceptions.h"
|
|
||||||
#include "Zend/zend_extensions.h"
|
|
||||||
|
|
||||||
#ifdef PHP_WIN32
|
|
||||||
# define PHP_TEST_HELPERS_API __declspec(dllexport)
|
|
||||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
|
||||||
# define PHP_TEST_HELPERS_API __attribute__ ((visibility("default")))
|
|
||||||
#else
|
|
||||||
# define PHP_TEST_HELPERS_API
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* {{{ PHP < 5.3.0 */
|
|
||||||
#if PHP_VERSION_ID < 50300
|
|
||||||
typedef opcode_handler_t user_opcode_handler_t;
|
|
||||||
|
|
||||||
#define Z_ADDREF_P(z) ((z)->refcount++)
|
|
||||||
|
|
||||||
#define zend_parse_parameters_none() zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
|
|
||||||
|
|
||||||
static void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* {{{ */
|
|
||||||
{
|
|
||||||
if (fci->params) {
|
|
||||||
if (free_mem) {
|
|
||||||
efree(fci->params);
|
|
||||||
fci->params = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fci->param_count = 0;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int zend_fcall_info_argv(zend_fcall_info *fci TSRMLS_DC, int argc, va_list *argv) /* {{{ */
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
zval **arg;
|
|
||||||
|
|
||||||
if (argc < 0) {
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
zend_fcall_info_args_clear(fci, !argc);
|
|
||||||
|
|
||||||
if (argc) {
|
|
||||||
fci->param_count = argc;
|
|
||||||
fci->params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
|
|
||||||
|
|
||||||
for (i = 0; i < argc; ++i) {
|
|
||||||
arg = va_arg(*argv, zval **);
|
|
||||||
fci->params[i] = arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int zend_fcall_info_argn(zend_fcall_info *fci TSRMLS_DC, int argc, ...) /* {{{ */
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
va_list argv;
|
|
||||||
|
|
||||||
va_start(argv, argc);
|
|
||||||
ret = zend_fcall_info_argv(fci TSRMLS_CC, argc, &argv);
|
|
||||||
va_end(argv);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
#endif /* PHP_VERSION_ID < 50300 */
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static user_opcode_handler_t old_new_handler = NULL;
|
|
||||||
static user_opcode_handler_t old_exit_handler = NULL;
|
|
||||||
static int test_helpers_module_initialized = 0;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
zend_fcall_info fci;
|
|
||||||
zend_fcall_info_cache fcc;
|
|
||||||
} user_handler_t;
|
|
||||||
|
|
||||||
ZEND_BEGIN_MODULE_GLOBALS(test_helpers)
|
|
||||||
user_handler_t new_handler;
|
|
||||||
user_handler_t exit_handler;
|
|
||||||
ZEND_END_MODULE_GLOBALS(test_helpers)
|
|
||||||
|
|
||||||
ZEND_DECLARE_MODULE_GLOBALS(test_helpers)
|
|
||||||
|
|
||||||
#ifdef ZTS
|
|
||||||
#define THG(v) TSRMG(test_helpers_globals_id, zend_test_helpers_globals *, v)
|
|
||||||
#else
|
|
||||||
#define THG(v) (test_helpers_globals.v)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef EX
|
|
||||||
#define EX(element) execute_data->element
|
|
||||||
|
|
||||||
#if PHP_VERSION_ID >= 50500
|
|
||||||
# define EX_T(offset) (*EX_TMP_VAR(execute_data, offset))
|
|
||||||
#else
|
|
||||||
# define EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PHP_VERSION_ID >= 50399
|
|
||||||
# define PTH_ZNODE znode_op
|
|
||||||
# define PTH_TYPE(t) t##_type
|
|
||||||
#else
|
|
||||||
# define PTH_ZNODE znode
|
|
||||||
# define PTH_TYPE(t) t.op_type
|
|
||||||
#endif
|
|
||||||
|
|
||||||
zval *pth_get_zval_ptr(int node_type, PTH_ZNODE *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC)
|
|
||||||
{
|
|
||||||
*freeval = NULL;
|
|
||||||
|
|
||||||
switch (node_type) {
|
|
||||||
case IS_CONST:
|
|
||||||
#if PHP_VERSION_ID >= 50399
|
|
||||||
return node->zv;
|
|
||||||
#else
|
|
||||||
return &node->u.constant;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IS_VAR:
|
|
||||||
#if PHP_VERSION_ID >= 50399
|
|
||||||
if (EX_T(node->var).var.ptr) {
|
|
||||||
return EX_T(node->var).var.ptr;
|
|
||||||
#else
|
|
||||||
if (EX_T(node->u.var).var.ptr) {
|
|
||||||
return EX_T(node->u.var).var.ptr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IS_TMP_VAR:
|
|
||||||
#if PHP_VERSION_ID >= 50399
|
|
||||||
return (*freeval = &EX_T(node->var).tmp_var);
|
|
||||||
#else
|
|
||||||
return (*freeval = &EX_T(node->u.var).tmp_var);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IS_CV: {
|
|
||||||
zval **tmp;
|
|
||||||
#if PHP_VERSION_ID >= 50399
|
|
||||||
tmp = zend_get_compiled_variable_value(execute_data, node->constant);
|
|
||||||
#else
|
|
||||||
tmp = zend_get_compiled_variable_value(execute_data, node->u.constant.value.lval);
|
|
||||||
#endif
|
|
||||||
if (tmp) {
|
|
||||||
return *tmp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_helpers_free_handler(zend_fcall_info *fci TSRMLS_DC) /* {{{ */
|
|
||||||
{
|
|
||||||
if (fci->function_name) {
|
|
||||||
zval_ptr_dtor(&fci->function_name);
|
|
||||||
fci->function_name = NULL;
|
|
||||||
}
|
|
||||||
#if PHP_VERSION_ID >= 50300
|
|
||||||
if (fci->object_ptr) {
|
|
||||||
zval_ptr_dtor(&fci->object_ptr);
|
|
||||||
fci->object_ptr = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int pth_new_handler(ZEND_OPCODE_HANDLER_ARGS) /* {{{ */
|
|
||||||
{
|
|
||||||
zval *retval, *arg;
|
|
||||||
zend_op *opline = EX(opline);
|
|
||||||
zend_class_entry *old_ce, **new_ce;
|
|
||||||
|
|
||||||
if (THG(new_handler).fci.function_name == NULL) {
|
|
||||||
if (old_new_handler) {
|
|
||||||
return old_new_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
|
||||||
} else {
|
|
||||||
return ZEND_USER_OPCODE_DISPATCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ZEND_EXTENSION_API_NO >= 220100525
|
|
||||||
old_ce = EX_T(opline->op1.var).class_entry;
|
|
||||||
#else
|
|
||||||
old_ce = EX_T(opline->op1.u.var).class_entry;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MAKE_STD_ZVAL(arg);
|
|
||||||
ZVAL_STRINGL(arg, old_ce->name, old_ce->name_length, 1);
|
|
||||||
|
|
||||||
zend_fcall_info_argn(&THG(new_handler).fci TSRMLS_CC, 1, &arg);
|
|
||||||
zend_fcall_info_call(&THG(new_handler).fci, &THG(new_handler).fcc, &retval, NULL TSRMLS_CC);
|
|
||||||
zend_fcall_info_args_clear(&THG(new_handler).fci, 1);
|
|
||||||
|
|
||||||
convert_to_string_ex(&retval);
|
|
||||||
if (zend_lookup_class(Z_STRVAL_P(retval), Z_STRLEN_P(retval), &new_ce TSRMLS_CC) == FAILURE) {
|
|
||||||
if (!EG(exception)) {
|
|
||||||
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), -1 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(retval));
|
|
||||||
}
|
|
||||||
zval_ptr_dtor(&arg);
|
|
||||||
zval_ptr_dtor(&retval);
|
|
||||||
|
|
||||||
return ZEND_USER_OPCODE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
zval_ptr_dtor(&arg);
|
|
||||||
zval_ptr_dtor(&retval);
|
|
||||||
|
|
||||||
|
|
||||||
#if ZEND_EXTENSION_API_NO >= 220100525
|
|
||||||
EX_T(opline->op1.var).class_entry = *new_ce;
|
|
||||||
#else
|
|
||||||
EX_T(opline->op1.u.var).class_entry = *new_ce;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (old_new_handler) {
|
|
||||||
return old_new_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
|
||||||
} else {
|
|
||||||
return ZEND_USER_OPCODE_DISPATCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int pth_exit_handler(ZEND_OPCODE_HANDLER_ARGS) /* {{{ */
|
|
||||||
{
|
|
||||||
zval *msg, *freeop;
|
|
||||||
zend_op *opline = EX(opline);
|
|
||||||
zval *retval = NULL;
|
|
||||||
|
|
||||||
if (THG(exit_handler).fci.function_name == NULL) {
|
|
||||||
if (old_exit_handler) {
|
|
||||||
return old_exit_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
|
||||||
} else {
|
|
||||||
return ZEND_USER_OPCODE_DISPATCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = pth_get_zval_ptr(opline->PTH_TYPE(op1), &opline->op1, &freeop, execute_data TSRMLS_CC);
|
|
||||||
|
|
||||||
if (msg) {
|
|
||||||
zend_fcall_info_argn(&THG(exit_handler).fci TSRMLS_CC, 1, &msg);
|
|
||||||
}
|
|
||||||
zend_fcall_info_call(&THG(exit_handler).fci, &THG(exit_handler).fcc, &retval, NULL TSRMLS_CC);
|
|
||||||
zend_fcall_info_args_clear(&THG(exit_handler).fci, 1);
|
|
||||||
|
|
||||||
if(UNEXPECTED(retval == NULL)) {
|
|
||||||
EX(opline)++;
|
|
||||||
return ZEND_USER_OPCODE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_boolean(retval);
|
|
||||||
if (Z_LVAL_P(retval)) {
|
|
||||||
zval_ptr_dtor(&retval);
|
|
||||||
if (old_exit_handler) {
|
|
||||||
return old_exit_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
|
||||||
} else {
|
|
||||||
return ZEND_USER_OPCODE_DISPATCH;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zval_ptr_dtor(&retval);
|
|
||||||
EX(opline)++;
|
|
||||||
return ZEND_USER_OPCODE_CONTINUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static void php_test_helpers_init_globals(zend_test_helpers_globals *globals) /* {{{ */
|
|
||||||
{
|
|
||||||
globals->new_handler.fci.function_name = NULL;
|
|
||||||
globals->exit_handler.fci.function_name = NULL;
|
|
||||||
#if PHP_VERSION_ID >= 50300
|
|
||||||
globals->new_handler.fci.object_ptr = NULL;
|
|
||||||
globals->exit_handler.fci.object_ptr = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ PHP_MINIT_FUNCTION
|
|
||||||
*/
|
|
||||||
static PHP_MINIT_FUNCTION(test_helpers)
|
|
||||||
{
|
|
||||||
if (test_helpers_module_initialized) {
|
|
||||||
/* This should never happen as it is handled by the module loader, but let's play safe */
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "test_helpers had already been initialized! Either load it as regular PHP extension or zend_extension");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZEND_INIT_MODULE_GLOBALS(test_helpers, php_test_helpers_init_globals, NULL);
|
|
||||||
old_new_handler = zend_get_user_opcode_handler(ZEND_NEW);
|
|
||||||
zend_set_user_opcode_handler(ZEND_NEW, pth_new_handler);
|
|
||||||
|
|
||||||
old_exit_handler = zend_get_user_opcode_handler(ZEND_EXIT);
|
|
||||||
zend_set_user_opcode_handler(ZEND_EXIT, pth_exit_handler);
|
|
||||||
|
|
||||||
test_helpers_module_initialized = 1;
|
|
||||||
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ PHP_RSHUTDOWN_FUNCTION
|
|
||||||
*/
|
|
||||||
static PHP_RSHUTDOWN_FUNCTION(test_helpers)
|
|
||||||
{
|
|
||||||
test_helpers_free_handler(&THG(new_handler).fci TSRMLS_CC);
|
|
||||||
test_helpers_free_handler(&THG(exit_handler).fci TSRMLS_CC);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ PHP_MINFO_FUNCTION
|
|
||||||
*/
|
|
||||||
static PHP_MINFO_FUNCTION(test_helpers)
|
|
||||||
{
|
|
||||||
char *conflict_text;
|
|
||||||
|
|
||||||
if (pth_new_handler != zend_get_user_opcode_handler(ZEND_NEW)) {
|
|
||||||
conflict_text = "Yes. The work-around was NOT enabled. Please make sure test_helpers was loaded as zend_extension AFTER conflicting extensions like Xdebug!";
|
|
||||||
} else if (old_new_handler != NULL) {
|
|
||||||
conflict_text = "Yes, work-around enabled";
|
|
||||||
} else {
|
|
||||||
conflict_text = "No conflict detected";
|
|
||||||
}
|
|
||||||
php_info_print_table_start();
|
|
||||||
php_info_print_table_header(2, "test_helpers support", "enabled");
|
|
||||||
php_info_print_table_row(2, "Conflicting extension found", conflict_text);
|
|
||||||
php_info_print_table_end();
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static void overload_helper(user_opcode_handler_t op_handler, int opcode, user_handler_t *handler, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
|
||||||
{
|
|
||||||
zend_fcall_info fci;
|
|
||||||
zend_fcall_info_cache fcc;
|
|
||||||
|
|
||||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", &fci, &fcc) == FAILURE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op_handler != zend_get_user_opcode_handler(opcode)) {
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "A conflicting extension was detected. Make sure to load test_helpers as zend_extension after other extensions");
|
|
||||||
}
|
|
||||||
|
|
||||||
test_helpers_free_handler(&handler->fci TSRMLS_CC);
|
|
||||||
|
|
||||||
handler->fci = fci;
|
|
||||||
handler->fcc = fcc;
|
|
||||||
Z_ADDREF_P(handler->fci.function_name);
|
|
||||||
#if PHP_VERSION_ID >= 50300
|
|
||||||
if (handler->fci.object_ptr) {
|
|
||||||
Z_ADDREF_P(handler->fci.object_ptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RETURN_TRUE;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ proto bool set_new_overload(callback cb)
|
|
||||||
Register a callback, called on instantiation of a new object */
|
|
||||||
static PHP_FUNCTION(set_new_overload)
|
|
||||||
{
|
|
||||||
overload_helper(pth_new_handler, ZEND_NEW, &THG(new_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ proto bool set_exit_overload(callback cb)
|
|
||||||
Register a callback, called on exit()/die() */
|
|
||||||
static PHP_FUNCTION(set_exit_overload)
|
|
||||||
{
|
|
||||||
overload_helper(pth_exit_handler, ZEND_EXIT, &THG(exit_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static void unset_overload_helper(user_handler_t *handler, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
|
||||||
{
|
|
||||||
if (zend_parse_parameters_none() == FAILURE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
test_helpers_free_handler(&handler->fci TSRMLS_CC);
|
|
||||||
RETURN_TRUE;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ proto bool unset_new_overload()
|
|
||||||
Remove the current new handler */
|
|
||||||
static PHP_FUNCTION(unset_new_overload)
|
|
||||||
{
|
|
||||||
unset_overload_helper(&THG(new_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ proto bool unset_exit_overload()
|
|
||||||
Remove the current exit handler */
|
|
||||||
static PHP_FUNCTION(unset_exit_overload)
|
|
||||||
{
|
|
||||||
unset_overload_helper(&THG(exit_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int pth_rename_function_impl(HashTable *table, char *orig, int orig_len, char *new, int new_len TSRMLS_DC) /* {{{ */
|
|
||||||
{
|
|
||||||
zend_function *func, *dummy_func;
|
|
||||||
|
|
||||||
if (zend_hash_find(table, orig, orig_len + 1, (void **) &func) == FAILURE) {
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s(%s, %s) failed: %s does not exist!" ,
|
|
||||||
get_active_function_name(TSRMLS_C),
|
|
||||||
orig, new, orig);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Add infrastructure for resetting internal funcs */
|
|
||||||
if (func->type != ZEND_USER_FUNCTION) {
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "\"%s\" is an internal function", orig);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zend_hash_find(table, new, new_len + 1, (void **) &dummy_func) == SUCCESS) {
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s(%s, %s) failed: %s already exists!" ,
|
|
||||||
get_active_function_name(TSRMLS_C),
|
|
||||||
orig, new, new);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zend_hash_add(table, new, new_len + 1, func, sizeof(zend_function), NULL) == FAILURE) {
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s() failed to insert %s into EG(function_table)", get_active_function_name(TSRMLS_C), new);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (func->type == ZEND_USER_FUNCTION) {
|
|
||||||
function_add_ref(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zend_hash_del(table, orig, orig_len + 1) == FAILURE) {
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s() failed to remove %s from function table", get_active_function_name(TSRMLS_C), orig);
|
|
||||||
|
|
||||||
zend_hash_del(table, new, new_len + 1);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int pth_rename_function(HashTable *table, char *orig, int orig_len, char *new, int new_len TSRMLS_DC) /* {{{ */
|
|
||||||
{
|
|
||||||
char *lower_orig, *lower_new;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
lower_orig = zend_str_tolower_dup(orig, orig_len);
|
|
||||||
lower_new = zend_str_tolower_dup(new, new_len);
|
|
||||||
|
|
||||||
success = pth_rename_function_impl(table, lower_orig, orig_len, lower_new, new_len TSRMLS_CC);
|
|
||||||
|
|
||||||
efree(lower_orig);
|
|
||||||
efree(lower_new);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ proto bool rename_method(string class name, string orig_method_name, string new_method_name)
|
|
||||||
Rename a method inside a class. The method whil remain partof the same class */
|
|
||||||
static PHP_FUNCTION(rename_method)
|
|
||||||
{
|
|
||||||
zend_class_entry *ce = NULL;
|
|
||||||
char *orig_fname, *new_fname;
|
|
||||||
int orig_fname_len, new_fname_len;
|
|
||||||
|
|
||||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Css", &ce, &orig_fname, &orig_fname_len, &new_fname, &new_fname_len) == FAILURE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCESS == pth_rename_function(&ce->function_table, orig_fname, orig_fname_len, new_fname, new_fname_len TSRMLS_CC)) {
|
|
||||||
RETURN_TRUE;
|
|
||||||
} else {
|
|
||||||
RETURN_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ proto bool rename_function(string orig_func_name, string new_func_name)
|
|
||||||
Rename a function from its original to a new name. This is mainly useful in
|
|
||||||
unittest to stub out untested functions */
|
|
||||||
static PHP_FUNCTION(rename_function)
|
|
||||||
{
|
|
||||||
char *orig_fname, *new_fname;
|
|
||||||
int orig_fname_len, new_fname_len;
|
|
||||||
|
|
||||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &orig_fname, &orig_fname_len, &new_fname, &new_fname_len) == FAILURE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCESS == pth_rename_function(EG(function_table), orig_fname, orig_fname_len, new_fname, new_fname_len TSRMLS_CC)) {
|
|
||||||
RETURN_TRUE;
|
|
||||||
} else {
|
|
||||||
RETURN_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ arginfo */
|
|
||||||
/* {{{ unset_new_overload */
|
|
||||||
ZEND_BEGIN_ARG_INFO(arginfo_unset_new_overload, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ unset_exit_overload */
|
|
||||||
ZEND_BEGIN_ARG_INFO(arginfo_unset_exit_overload, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ set_new_overload */
|
|
||||||
ZEND_BEGIN_ARG_INFO(arginfo_set_new_overload, 0)
|
|
||||||
ZEND_ARG_INFO(0, callback)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ rename_method */
|
|
||||||
ZEND_BEGIN_ARG_INFO(arginfo_rename_method, 0)
|
|
||||||
ZEND_ARG_INFO(0, class_name)
|
|
||||||
ZEND_ARG_INFO(0, orig_method_name)
|
|
||||||
ZEND_ARG_INFO(0, new_method_name)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ rename_function */
|
|
||||||
ZEND_BEGIN_ARG_INFO(arginfo_rename_function, 0)
|
|
||||||
ZEND_ARG_INFO(0, orig_func_name)
|
|
||||||
ZEND_ARG_INFO(0, new_func_name)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ set_exit_overload */
|
|
||||||
ZEND_BEGIN_ARG_INFO(arginfo_set_exit_overload, 0)
|
|
||||||
ZEND_ARG_INFO(0, "callback")
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ test_helpers_functions[]
|
|
||||||
*/
|
|
||||||
static const zend_function_entry test_helpers_functions[] = {
|
|
||||||
PHP_FE(unset_new_overload, arginfo_unset_new_overload)
|
|
||||||
PHP_FE(set_new_overload, arginfo_set_new_overload)
|
|
||||||
PHP_FE(unset_exit_overload, arginfo_unset_exit_overload)
|
|
||||||
PHP_FE(set_exit_overload, arginfo_set_exit_overload)
|
|
||||||
PHP_FE(rename_method, arginfo_rename_method)
|
|
||||||
PHP_FE(rename_function, arginfo_rename_function)
|
|
||||||
{NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ test_helpers_module_entry
|
|
||||||
*/
|
|
||||||
zend_module_entry test_helpers_module_entry = {
|
|
||||||
STANDARD_MODULE_HEADER,
|
|
||||||
"test_helpers",
|
|
||||||
test_helpers_functions,
|
|
||||||
PHP_MINIT(test_helpers),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
PHP_RSHUTDOWN(test_helpers),
|
|
||||||
PHP_MINFO(test_helpers),
|
|
||||||
TEST_HELPERS_VERSION,
|
|
||||||
STANDARD_MODULE_PROPERTIES
|
|
||||||
};
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int test_helpers_zend_startup(zend_extension *extension) /* {{{ */
|
|
||||||
{
|
|
||||||
return zend_startup_module(&test_helpers_module_entry);
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
#ifndef ZEND_EXT_API
|
|
||||||
#define ZEND_EXT_API ZEND_DLEXPORT
|
|
||||||
#endif
|
|
||||||
ZEND_EXTENSION();
|
|
||||||
|
|
||||||
zend_extension zend_extension_entry = {
|
|
||||||
"test_helpers",
|
|
||||||
TEST_HELPERS_VERSION,
|
|
||||||
"Johannes Schlueter, Scott MacVicar, Sebastian Bergmann",
|
|
||||||
"http://github.com/johannes/php-test-helpers",
|
|
||||||
"Copyright (c) 2009-2013",
|
|
||||||
test_helpers_zend_startup,
|
|
||||||
NULL, /* shutdown_func_t */
|
|
||||||
NULL, /* activate_func_t */
|
|
||||||
NULL, /* deactivate_func_t */
|
|
||||||
NULL, /* message_handler_func_t */
|
|
||||||
NULL, /* op_array_handler_func_t */
|
|
||||||
NULL, /* statement_handler_func_t */
|
|
||||||
NULL, /* fcall_begin_handler_func_t */
|
|
||||||
NULL, /* fcall_end_handler_func_t */
|
|
||||||
NULL, /* op_array_ctor_func_t */
|
|
||||||
NULL, /* op_array_dtor_func_t */
|
|
||||||
STANDARD_ZEND_EXTENSION_PROPERTIES
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef COMPILE_DL_TEST_HELPERS
|
|
||||||
ZEND_GET_MODULE(test_helpers)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Local variables:
|
|
||||||
* tab-width: 4
|
|
||||||
* c-basic-offset: 4
|
|
||||||
* End:
|
|
||||||
* vim600: noet sw=4 ts=4 fdm=marker
|
|
||||||
* vim<600: noet sw=4 ts=4
|
|
||||||
*/
|
|
6
vendors/php-test-helpers/tests/.gitignore
vendored
6
vendors/php-test-helpers/tests/.gitignore
vendored
|
@ -1,6 +0,0 @@
|
||||||
*.diff
|
|
||||||
*.exp
|
|
||||||
*.log
|
|
||||||
*.mem
|
|
||||||
*.out
|
|
||||||
*.php
|
|
|
@ -1,21 +0,0 @@
|
||||||
--TEST--
|
|
||||||
Loading test_helpers as zend_extension
|
|
||||||
--INI--
|
|
||||||
zend_extension=test_helpers.so
|
|
||||||
error_log=
|
|
||||||
display_errors=0
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (version_compare(PHP_VERSION, '5.5', '<')) die("skip this test is for PHP 5.5+.");
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
if (!file_exists('modules/test_helpers.so')) die('skip test_helpers.so not found Static build? out-of-src-dir build?');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
// The test framework will load the extension as PHP extension, we verify that a second load attempt is made
|
|
||||||
// This test has some flaws, the major one is that it expects a specific .so file at a specific location ...
|
|
||||||
echo "done";
|
|
||||||
?>
|
|
||||||
--EXPECT--
|
|
||||||
PHP Warning: Module 'test_helpers' already loaded in Unknown on line 0
|
|
||||||
done
|
|
|
@ -1,21 +0,0 @@
|
||||||
--TEST--
|
|
||||||
Loading test_helpers as zend_extension
|
|
||||||
--INI--
|
|
||||||
zend_extension=modules/test_helpers.so
|
|
||||||
error_log=
|
|
||||||
display_errors=0
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (version_compare(PHP_VERSION, '5.5', '>=')) die("skip test is for PHP < 5.5.");
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
if (!file_exists('modules/test_helpers.so')) die('skip test_helpers.so not found Static build? out-of-src-dir build?');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
// The test framework will load the extension as PHP extension, we verify that a second load attempt is made
|
|
||||||
// This test has some flaws, the major one is that it expects a specific .so file at a specific location ...
|
|
||||||
echo "done";
|
|
||||||
?>
|
|
||||||
--EXPECT--
|
|
||||||
PHP Warning: Module 'test_helpers' already loaded in Unknown on line 0
|
|
||||||
done
|
|
|
@ -1,17 +0,0 @@
|
||||||
--TEST--
|
|
||||||
rename_function() and user-defined functions
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
function foo()
|
|
||||||
{
|
|
||||||
print 'foo';
|
|
||||||
}
|
|
||||||
|
|
||||||
rename_function('foo', 'bar');
|
|
||||||
bar();
|
|
||||||
--EXPECT--
|
|
||||||
foo
|
|
|
@ -1,28 +0,0 @@
|
||||||
--TEST--
|
|
||||||
rename_function() and internal functions
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--XFAIL--
|
|
||||||
Not yet implemented
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
$headers = array();
|
|
||||||
|
|
||||||
function my_header($header)
|
|
||||||
{
|
|
||||||
$GLOBALS['headers'][] = $header;
|
|
||||||
}
|
|
||||||
|
|
||||||
rename_function('header', 'internal_header');
|
|
||||||
rename_function('my_header', 'header');
|
|
||||||
header('Location: http://www.example.com/');
|
|
||||||
rename_function('header', 'my_header');
|
|
||||||
rename_function('internal_header', 'header');
|
|
||||||
var_dump($headers);
|
|
||||||
--EXPECT--
|
|
||||||
array(1) {
|
|
||||||
[0]=>
|
|
||||||
string(33) "Location: http://www.example.com/"
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
--TEST--
|
|
||||||
rename_method() and user-defined functions
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class A {
|
|
||||||
static function foo()
|
|
||||||
{
|
|
||||||
print 'foo';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rename_method('A', 'foo', 'bar');
|
|
||||||
A::bar();
|
|
||||||
--EXPECT--
|
|
||||||
foo
|
|
|
@ -1,26 +0,0 @@
|
||||||
--TEST--
|
|
||||||
set_exit_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
set_exit_overload(function($arg = NULL) { var_dump($arg); echo "FALSE\n"; return false; });
|
|
||||||
die("DIE 1");
|
|
||||||
die;
|
|
||||||
exit;
|
|
||||||
set_exit_overload(function($arg) { var_dump($arg); echo "TRUE\n"; return true; });
|
|
||||||
die("DIE 4");
|
|
||||||
echo "HAHA";
|
|
||||||
?>
|
|
||||||
--EXPECT--
|
|
||||||
string(5) "DIE 1"
|
|
||||||
FALSE
|
|
||||||
NULL
|
|
||||||
FALSE
|
|
||||||
NULL
|
|
||||||
FALSE
|
|
||||||
string(5) "DIE 4"
|
|
||||||
TRUE
|
|
||||||
DIE 4
|
|
|
@ -1,17 +0,0 @@
|
||||||
--TEST--
|
|
||||||
set_exit_overload() with an uncaught exception
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
set_exit_overload(function($arg = NULL) { throw new Exception("Please don't segfault"); });
|
|
||||||
try {
|
|
||||||
exit("hi");
|
|
||||||
} catch(Exception $exception) {
|
|
||||||
echo $exception->getMessage();
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
--EXPECT--
|
|
||||||
Please don't segfault
|
|
|
@ -1,28 +0,0 @@
|
||||||
--TEST--
|
|
||||||
debug_print_backtrace() should work inside the callback.
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback($className) {
|
|
||||||
debug_print_backtrace();
|
|
||||||
return 'Foo';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getObject() {
|
|
||||||
return new Bar();
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload('callback'));
|
|
||||||
var_dump(getObject());
|
|
||||||
--EXPECTF--
|
|
||||||
bool(true)
|
|
||||||
#0 callback(Bar) called at [%s:%d]
|
|
||||||
#1 getObject() called at [%s:%d]
|
|
||||||
object(Foo)#1 (0) {
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A closure can be registered as a callback with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
if (version_compare(PHP_VERSION, '5.3.0') < 0) die('skip Test requires PHP 5.3');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
var_dump(set_new_overload(function ($className) { return 'Foo'; }));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,21 +0,0 @@
|
||||||
--TEST--
|
|
||||||
Callback for the new operator is invoked for non-existing classes
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--XFAIL--
|
|
||||||
Currently not supported by the implementation but nice to have
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
|
|
||||||
function callback($className) {
|
|
||||||
return 'Foo';
|
|
||||||
}
|
|
||||||
|
|
||||||
set_new_overload('callback');
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,24 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A fatal error is triggered when the class returned by the callback does not exist
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback($className) {
|
|
||||||
return 'Foo';
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload('callback'));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECTF--
|
|
||||||
bool(true)
|
|
||||||
|
|
||||||
Fatal error: Uncaught exception 'Exception' with message 'Class Foo does not exist' in %s:%d
|
|
||||||
Stack trace:
|
|
||||||
#0 {main}
|
|
||||||
thrown in %s on line %d
|
|
|
@ -1,17 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A warning is triggered when the callback passed to set_new_overload() is not defined
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
var_dump(set_new_overload('callback'));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECTF--
|
|
||||||
Warning: set_new_overload() expects parameter 1 to be a valid callback, function 'callback' not found or invalid function name in %s on line %d
|
|
||||||
NULL
|
|
||||||
string(3) "Bar"
|
|
|
@ -1,21 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A function can be registered as a callback with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback($className) {
|
|
||||||
return 'Foo';
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload('callback'));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,26 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A functor can be registered as a callback with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
if (version_compare(PHP_VERSION, '5.3.0') < 0) die('skip Test requires PHP 5.3');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
class Callback
|
|
||||||
{
|
|
||||||
public function __invoke($className)
|
|
||||||
{
|
|
||||||
return 'Foo';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload(new Callback));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,33 +0,0 @@
|
||||||
--TEST--
|
|
||||||
set_new_overload() can be called multiple times and unset_new_overload() works
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo1 {}
|
|
||||||
class Foo2 {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback1($className) {
|
|
||||||
return 'Foo1';
|
|
||||||
}
|
|
||||||
|
|
||||||
function callback2($className) {
|
|
||||||
return 'foo2';
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload('callback1'));
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
var_dump(set_new_overload('callback2'));
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
var_dump(unset_new_overload());
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(4) "Foo1"
|
|
||||||
bool(true)
|
|
||||||
string(4) "Foo2"
|
|
||||||
bool(true)
|
|
||||||
string(3) "Bar"
|
|
|
@ -1,27 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A non-static method can be registered as a callback with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
class CB {
|
|
||||||
function callback($className) {
|
|
||||||
if ($className == 'Bar') {
|
|
||||||
return 'Foo';
|
|
||||||
} else {
|
|
||||||
return $className;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload(array(new CB(), 'callback')));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,86 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A non-static method of the same object can be registered as a callback with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo
|
|
||||||
{
|
|
||||||
public function doSomething()
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
|
|
||||||
// ...
|
|
||||||
|
|
||||||
$bar = new Bar;
|
|
||||||
$bar->doSomethingElse();
|
|
||||||
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Bar
|
|
||||||
{
|
|
||||||
public function doSomethingElse()
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BarMock extends Bar
|
|
||||||
{
|
|
||||||
public function doSomethingElse()
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FooTest
|
|
||||||
{
|
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
|
|
||||||
set_new_overload(array($this, 'newCallback'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown()
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
|
|
||||||
unset_new_overload();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function newCallback($className)
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
|
|
||||||
switch ($className) {
|
|
||||||
case 'Bar': return 'BarMock';
|
|
||||||
default: return $className;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDoSomething()
|
|
||||||
{
|
|
||||||
var_dump(__METHOD__);
|
|
||||||
|
|
||||||
$foo = new Foo;
|
|
||||||
$foo->doSomething();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$test = new FooTest;
|
|
||||||
$test->setUp();
|
|
||||||
$test->testDoSomething();
|
|
||||||
$test->tearDown();
|
|
||||||
--EXPECT--
|
|
||||||
string(14) "FooTest::setUp"
|
|
||||||
string(24) "FooTest::testDoSomething"
|
|
||||||
string(20) "FooTest::newCallback"
|
|
||||||
string(16) "Foo::doSomething"
|
|
||||||
string(20) "FooTest::newCallback"
|
|
||||||
string(24) "BarMock::doSomethingElse"
|
|
||||||
string(17) "FooTest::tearDown"
|
|
|
@ -1,38 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A private method can be registered from the right context with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
class CB {
|
|
||||||
private function callback($className) {
|
|
||||||
if ($className == 'Bar') {
|
|
||||||
return 'Foo';
|
|
||||||
} else {
|
|
||||||
return $className;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function set_overload() {
|
|
||||||
return set_new_overload(array($this, 'callback'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$cb = new CB();
|
|
||||||
|
|
||||||
var_dump(set_new_overload(array($cb, 'callback')));
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
|
|
||||||
var_dump($cb->set_overload());
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECTF--
|
|
||||||
Warning: set_new_overload() expects parameter 1 to be a valid callback, cannot access private method CB::callback() in %s on line %d
|
|
||||||
NULL
|
|
||||||
string(3) "Bar"
|
|
||||||
bool(true)
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,23 +0,0 @@
|
||||||
--TEST--
|
|
||||||
A static method can be registered as a callback with set_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
class CB {
|
|
||||||
static function callback($className) {
|
|
||||||
return 'Foo';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload(array('CB', 'callback')));
|
|
||||||
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(3) "Foo"
|
|
|
@ -1,33 +0,0 @@
|
||||||
--TEST--
|
|
||||||
set_new_overload() can be called after unset_new_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
class Foo1 {}
|
|
||||||
class Foo2 {}
|
|
||||||
class Bar {}
|
|
||||||
|
|
||||||
function callback1($className) {
|
|
||||||
return 'Foo1';
|
|
||||||
}
|
|
||||||
|
|
||||||
function callback2($className) {
|
|
||||||
return 'foo2';
|
|
||||||
}
|
|
||||||
|
|
||||||
var_dump(set_new_overload('callback1'));
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
var_dump(unset_new_overload());
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
var_dump(set_new_overload('callback2'));
|
|
||||||
var_dump(get_class(new Bar));
|
|
||||||
--EXPECT--
|
|
||||||
bool(true)
|
|
||||||
string(4) "Foo1"
|
|
||||||
bool(true)
|
|
||||||
string(3) "Bar"
|
|
||||||
bool(true)
|
|
||||||
string(4) "Foo2"
|
|
|
@ -1,15 +0,0 @@
|
||||||
--TEST--
|
|
||||||
set_exit_overload()
|
|
||||||
--SKIPIF--
|
|
||||||
<?php
|
|
||||||
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
|
||||||
?>
|
|
||||||
--FILE--
|
|
||||||
<?php
|
|
||||||
set_exit_overload(function() { echo "FALSE\n"; return false; });
|
|
||||||
unset_exit_overload();
|
|
||||||
die("DIE");
|
|
||||||
echo "HAHA";
|
|
||||||
?>
|
|
||||||
--EXPECT--
|
|
||||||
DIE
|
|
Loading…
Add table
Add a link
Reference in a new issue