package.xml 0000644 0001750 0001750 00000043513 13177372464 012331 0 ustar tyson tyson
igbinary
pecl.php.net
igbinary extension
Igbinary is a drop in replacement for the standard php serializer. Instead of
time and space consuming textual representation, igbinary stores php data
structures in a compact binary form. Savings are significant when using
memcached or similar memory based storages for serialized data.
Oleg Grenrus
phadej
oleg.grenrus@iki.fi
yes
Pierre Joye
pajoye
pierre@php.net
yes
Teddy Grenman
tricky
teddy.pecl@luuseri.com
yes
Tyson Andre
tandre
tysonandre775@hotmail.com
yes
2017-11-04
2.0.5
1.1.1
stable
stable
BSD-3-Clause
* Same as 2.0.5RC1 (no bugs were reported in that release candidate)
5.2.0
1.4.0b1
igbinary
2017-11-04
2.0.5
1.1.1
stable
stable
BSD-3-Clause
* Same as 2.0.5RC1 (no bugs were reported in that release candidate)
2017-10-15
2.0.5RC1
1.1.1
beta
stable
BSD-3-Clause
* Improve performance when unserializing objects/arrays and serializing objects/arrays/strings in php 5/7.
* Update unserialization of integer object keys for php 7.2: Make those keys accessible when unserializing.
* Properly pick up presence of gcc for default compiler flags (`cc --version` doesn't contain gcc).
Add -O2 to default gcc compiler flags.
* Use empty string for serializing empty $_SESSION array, similar to "session.serialize_handler=php".
Older igbinary releases already unserialize the empty string to the empty array.
2017-04-14
2.0.4
1.1.1
stable
stable
BSD-3-Clause
* Fixes bug #129: Should not call __wakeup() on data which was created by Serializable::unserialize()
2017-03-31
2.0.3
1.1.1
stable
stable
BSD-3-Clause
- Fixes bug #126: Fatal error: "igbinary_serialize_zval: zval has unknown type 0" (IS_UNDEF)
Make this a warning instead of a fatal error (and serialize as null instead), since IS_UNDEF is a known type.
Later releases will fix the root cause of the warning, and consistently omit array/object/other entries for IS_UNDEF.
2017-02-28
2.0.2
1.1.1
stable
stable
BSD-3-Clause
- Compatible with PHP 5.2 - 7.1
- Fixes crash in Memcached->setMulti (in php 7.0+) when the first level of array elements have references as values.
Other extensions using igbinary shouldn't be affected.
2016-11-19
2.0.1
1.1.1
stable
stable
BSD-3-Clause
- Compatible with PHP 5.2 - 7.0
- Fixes bug in session decoder not calling wakeup in php 7.0+
- (Enhancement) Reuses identical strings when unserializing objects and arrays in php 7.0+
2016-10-30
2.0.0
1.1.1
stable
stable
BSD-3-Clause
- Compatible with PHP 5.2 - 7.0 (Adds PHP 7 support)
- Serialization format is unchanged
- Performance improvements for serialization and unserialization in PHP 5.2 - 7.0
- (PHP 7) Don't call __destruct if __wakeup threw an exception (or __wakeup wasn't called yet)
- Ports integration with other extensions to PHP 7.0 (session serialization, Memcached, Redis, APCu, etc.)
- Fixes Windows PECL builds for PHP 5.6+
- Reword warnings for invalid header bytes of serialized data (in igbinary_unserialize).
2014-08-29
1.2.1
1.1.1
stable
stable
BSD-3-Clause-3-Clause
- Compatible with PHP 5.2 - 5.6
2014-08-29
1.2.0
1.1.1
stable
stable
BSD-3-Clause
- PECL bug #22614, igbinary_unserialize(FALSE) must return FALSE
- PHP bug #54662, unserializing nested objects cause crash
- Other fixes
2011-03-14
1.1.1
1.1.1
stable
stable
BSD-3-Clause
- Initial PECL release
2009-09-02
1.0.2
1.0.2
stable
stable
PHP like license
- Use Z_ADDREF_PP or Z_ADDREF et al. when increasing refcount.
igbinary-2.0.5/tests/igbinary_001.phpt 0000644 0001750 0001750 00000001064 13177372464 016676 0 ustar tyson tyson --TEST--
Check for igbinary presence
--SKIPIF--
--FILE--
--EXPECT--
igbinary extension is available
igbinary-2.0.5/tests/igbinary_002.phpt 0000644 0001750 0001750 00000001446 13177372464 016703 0 ustar tyson tyson --TEST--
Check for null serialisation
--SKIPIF--
--FILE--
--EXPECT--
null
00
OK
igbinary-2.0.5/tests/igbinary_003.phpt 0000644 0001750 0001750 00000001535 13177372464 016703 0 ustar tyson tyson --TEST--
Check for bool serialisation
--SKIPIF--
--FILE--
--EXPECT--
bool true
05
OK
bool false
04
OK
igbinary-2.0.5/tests/igbinary_004.phpt 0000644 0001750 0001750 00000002141 13177372464 016676 0 ustar tyson tyson --TEST--
Check for integer serialisation
--SKIPIF--
--FILE--
--EXPECT--
zero: 0
0600
OK
small: 1
0601
OK
small: -1
0701
OK
medium: 1000
0803e8
OK
medium: -1000
0903e8
OK
large: 100000
0a000186a0
OK
large: -100000
0b000186a0
OK
igbinary-2.0.5/tests/igbinary_005.phpt 0000644 0001750 0001750 00000001521 13177372464 016700 0 ustar tyson tyson --TEST--
Check for double serialisation
--SKIPIF--
--FILE--
--EXPECT--
double: 123.456
0c405edd2f1a9fbe77
OK
igbinary-2.0.5/tests/igbinary_006.phpt 0000644 0001750 0001750 00000001600 13177372464 016677 0 ustar tyson tyson --TEST--
Check for simple string serialization
--SKIPIF--
--FILE--
--EXPECT--
empty: ""
0d
OK
string: "foobar"
1106666f6f626172
OK
igbinary-2.0.5/tests/igbinary_007.phpt 0000644 0001750 0001750 00000002175 13177372464 016710 0 ustar tyson tyson --TEST--
Check for simple array serialization
--SKIPIF--
--FILE--
--EXPECT--
empty array:
1400
OK
array(1, 2, 3)
1403060006010601060206020603
OK
array(array(1, 2, 3), arr...
1403060014030600060106010602060206030601140306000604060106050602060606021403060006070601060806020609
OK
igbinary-2.0.5/tests/igbinary_008.phpt 0000644 0001750 0001750 00000002037 13177372464 016706 0 ustar tyson tyson --TEST--
Check for array+string serialization
--SKIPIF--
--FILE--
1, "two" => 2))', array("one" => 1, "two" => 2));
test('array("kek" => "lol", "lol" => "kek")', array("kek" => "lol", "lol" => "kek"));
test('array("" => "empty")', array("" => "empty"));
?>
--EXPECT--
array("foo", "foo", "foo")
140306001103666f6f06010e0006020e00
OK
array("one" => 1, "two" => 2))
140211036f6e650601110374776f0602
OK
array("kek" => "lol", "lol" => "kek")
140211036b656b11036c6f6c0e010e00
OK
array("" => "empty")
14010d1105656d707479
OK
igbinary-2.0.5/tests/igbinary_009.phpt 0000644 0001750 0001750 00000002705 13177372464 016711 0 ustar tyson tyson --TEST--
Check for reference serialisation
--SKIPIF--
array(
'b' => 'c',
'd' => 'e'
),
'f' => array(
'g' => 'h'
)
);
test('array', $a, false);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
array
140211016114021101621101631101641101651101661401110167110168
OK
igbinary-2.0.5/tests/igbinary_012.phpt 0000644 0001750 0001750 00000002151 13177372464 016676 0 ustar tyson tyson --TEST--
Object test
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
$this->c = $c;
}
}
$o = new Obj(1, 2, 3);
test('object', $o);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a140311016106011104002a006206021106004f626a00630603
OK
igbinary-2.0.5/tests/igbinary_013.phpt 0000644 0001750 0001750 00000002012 13177372464 016673 0 ustar tyson tyson --TEST--
Object-Array test
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
}
$o = array(new Obj(1, 2), new Obj(3, 4));
test('object', $o, false);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
object
1402060017034f626a14021101610601110162060206011a0014020e0106030e020604
OK
igbinary-2.0.5/tests/igbinary_014.phpt 0000644 0001750 0001750 00000001227 13177372464 016703 0 ustar tyson tyson --TEST--
Object-Reference test
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
}
$o = new Obj(1, 2);
$a = array(&$o, &$o);
test('object', $a, false);
--EXPECT--
object
140206002517034f626a1402110161060111016206020601252201
OK
igbinary-2.0.5/tests/igbinary_015.phpt 0000644 0001750 0001750 00000002533 13177372464 016705 0 ustar tyson tyson --TEST--
Check for serialization handler
--SKIPIF--
--EXPECT--
2
14011103666f6f0602
igbinary-2.0.5/tests/igbinary_015b.phpt 0000644 0001750 0001750 00000002561 13177372464 017050 0 ustar tyson tyson --TEST--
Check for serialization handler, ini-directive
--SKIPIF--
--EXPECT--
2
14011103666f6f0602
igbinary-2.0.5/tests/igbinary_015c.phpt 0000644 0001750 0001750 00000002665 13177372464 017056 0 ustar tyson tyson --TEST--
Check for serialization handler
--SKIPIF--
--FILE--
--EXPECT--
read(abcdef10231512dfaz_12311)
write(abcdef10231512dfaz_12311): data:()
igbinary-2.0.5/tests/igbinary_016.phpt 0000644 0001750 0001750 00000002277 13177372464 016713 0 ustar tyson tyson --TEST--
Object test, __sleep
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
$this->c = $c;
$this->d = $d;
}
function __sleep() {
return array('a', 'b', 'c');
}
# function __wakeup() {
# $this->d = $this->a + $this->b + $this->c;
# }
}
$o = new Obj(1, 2, 3, 4);
test('object', $o, true);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a140311016106011104002a006206021106004f626a00630603
OK
igbinary-2.0.5/tests/igbinary_017.phpt 0000644 0001750 0001750 00000002005 13177372464 016701 0 ustar tyson tyson --TEST--
Object test, __wakeup
--SKIPIF--
--FILE--
b == 3 ? 'OK' : 'ERROR';
echo "\n";
}
class Obj {
var $a;
var $b;
function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
function __wakeup() {
$this->b = $this->a * 3;
}
}
$o = new Obj(1, 2);
test('object', $o, false);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a140211016106011101620602
OK
igbinary-2.0.5/tests/igbinary_018.phpt 0000644 0001750 0001750 00000002522 13177372464 016706 0 ustar tyson tyson --TEST--
Object test, __sleep error cases
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
function __sleep() {
return array('c');
}
# function __wakeup() {
# $this->b = $this->a * 3;
# }
}
class Opj {
var $a;
var $b;
function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
function __sleep() {
return array(1);
}
# function __wakeup() {
#
# }
}
$o = new Obj(1, 2);
$p = new Opj(1, 2);
test('nonexisting', $o, true);
test('wrong', $p, true);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
nonexisting
17034f626a140111016300
OK
wrong
17034f706a140100
OK
igbinary-2.0.5/tests/igbinary_019.phpt 0000644 0001750 0001750 00000002070 13177372464 016705 0 ustar tyson tyson --TEST--
Object test, __autoload
--SKIPIF--
--FILE--
b == 2 ? 'OK' : 'ERROR';
echo "\n";
}
function test_autoload($classname) {
class Obj {
var $a;
var $b;
function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
}
}
spl_autoload_register("test_autoload");
test('autoload', '0000000217034f626a140211016106011101620602', false);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
autoload
17034f626a140211016106011101620602
OK
igbinary-2.0.5/tests/igbinary_020.phpt 0000644 0001750 0001750 00000001743 13177372464 016703 0 ustar tyson tyson --TEST--
Object test, incomplete class
--SKIPIF--
--FILE--
--EXPECTF--
incom
17034f626a140211016106011101620602
object(__PHP_Incomplete_Class)#%d (3) {
["__PHP_Incomplete_Class_Name"]=>
string(3) "Obj"
["a"]=>
int(1)
["b"]=>
int(2)
}
igbinary-2.0.5/tests/igbinary_021.phpt 0000644 0001750 0001750 00000002267 13177372464 016706 0 ustar tyson tyson --TEST--
Object Serializable interface
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
public function serialize() {
return pack('NN', $this->a, $this->b);
}
public function unserialize($serialized) {
$tmp = unpack('N*', $serialized);
$this->__construct($tmp[1], $tmp[2]);
}
}
$o = new Obj(1, 2);
test('object', $o, false);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a1d080000000100000002
OK
igbinary-2.0.5/tests/igbinary_022.phpt 0000644 0001750 0001750 00000002105 13177372464 016676 0 ustar tyson tyson --TEST--
Object test, unserialize_callback_func
--SKIPIF--
--INI--
unserialize_callback_func=autoload
--FILE--
b == 2 ? 'OK' : 'ERROR';
echo "\n";
}
function autoload($classname) {
class Obj {
var $a;
var $b;
function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
}
}
test('autoload', '0000000217034f626a140211016106011101620602', false);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
autoload
17034f626a140211016106011101620602
OK
igbinary-2.0.5/tests/igbinary_023.phpt 0000644 0001750 0001750 00000000752 13177372464 016705 0 ustar tyson tyson --TEST--
Resource
--SKIPIF--
a = $a;
$this->b = $b;
$this->c = $c;
}
}
class Obj2 {
public $aa;
protected $bb;
private $cc;
private $obj;
function __construct($a, $b, $c) {
$this->a = $a;
$this->b = $b;
$this->c = $c;
$this->obj = new Obj($a, $b, $c);
}
}
class Obj3 {
private $objs;
function __construct($a, $b, $c) {
$this->objs = array();
for ($i = $a; $i < $c; $i += $b) {
$this->objs[] = new Obj($a, $i, $c);
}
}
}
class Obj4 {
private $a;
private $obj;
function __construct($a) {
$this->a = $a;
}
public function set($obj) {
$this->obj = $obj;
}
}
$o2 = new Obj2(1, 2, 3);
test('objectrec', $o2, false);
$o3 = new Obj3(0, 1, 4);
test('objectrecarr', $o3, false);
$o4 = new Obj4(100);
$o4->set($o4);
test('objectselfrec', $o4, true);
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
objectrec
17044f626a32140711026161001105002a006262001108004f626a32006363001109004f626a32006f626a17034f626a140311016106011104002a006206021106004f626a006306030e06060111016206021101630603
OK
objectrecarr
17044f626a331401110a004f626a33006f626a731404060017034f626a140311016106001104002a006206001106004f626a0063060406011a0214030e0306000e0406010e05060406021a0214030e0306000e0406020e05060406031a0214030e0306000e0406030e050604
OK
objectselfrec
17044f626a3414021107004f626a34006106641109004f626a34006f626a2200
OK
igbinary-2.0.5/tests/igbinary_025.phpt 0000644 0001750 0001750 00000004006 13177372464 016703 0 ustar tyson tyson --TEST--
Object test, array of objects with __sleep
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
$this->c = $c;
$this->d = $d;
}
function __sleep() {
return array('a', 'b', 'c');
}
# function __wakeup() {
# $this->d = $this->a + $this->b + $this->c;
# }
}
$array = array(
new Obj("aa", "bb", "cc", "dd"),
new Obj("ee", "ff", "gg", "hh"),
new Obj(1, 2, 3, 4),
);
test('array', $array, true);
?>
--EXPECTREGEX--
array\(3\) {
\[0\]=>
object\(Obj\)#1 \(4\) {
\["a"\]=>
string\(2\) "aa"
\[("b":protected|"b:protected")\]=>
string\(2\) "bb"
\["?c"?:("Obj":)?private"?\]=>
string\(2\) "cc"
\["d"\]=>
string\(2\) "dd"
}
\[1\]=>
object\(Obj\)#2 \(4\) {
\["a"\]=>
string\(2\) "ee"
\["?b"?:protected"?\]=>
string\(2\) "ff"
\["?c"?:("Obj":)?private"?\]=>
string\(2\) "gg"
\["d"\]=>
string\(2\) "hh"
}
\[2\]=>
object\(Obj\)#3 \(4\) {
\["a"\]=>
int\(1\)
\["?b"?:protected"?\]=>
int\(2\)
\["?c"?:("Obj":)?private"?\]=>
int\(3\)
\["d"\]=>
int\(4\)
}
}
array\(3\) {
\[0\]=>
object\(Obj\)#4 \(4\) {
\["a"\]=>
string\(2\) "aa"
\["?b"?:protected"?\]=>
string\(2\) "bb"
\["?c"?:("Obj":)?private"?\]=>
string\(2\) "cc"
\["d"\]=>
NULL
}
\[1\]=>
object\(Obj\)#5 \(4\) {
\["a"\]=>
string\(2\) "ee"
\["?b"?:protected"?\]=>
string\(2\) "ff"
\["?c"?:("Obj":)?private"?\]=>
string\(2\) "gg"
\["d"\]=>
NULL
}
\[2\]=>
object\(Obj\)#6 \(4\) {
\["a"\]=>
int\(1\)
\["?b"?:protected"?\]=>
int\(2\)
\["?c"?:("Obj":)?private"?\]=>
int\(3\)
\["d"\]=>
NULL
}
}
igbinary-2.0.5/tests/igbinary_026.phpt 0000644 0001750 0001750 00000002312 13177372464 016702 0 ustar tyson tyson --TEST--
Cyclic array test
--INI--
report_memleaks=0
--SKIPIF--
array(
'b' => 'c',
'd' => 'e'
),
);
$a['f'] = &$a;
test('array', $a, false);
$a = array("foo" => &$b);
$b = array(1, 2, $a);
$exp = $a;
$act = igbinary_unserialize(igbinary_serialize($a));
ob_start();
var_dump($exp);
$dump_exp = ob_get_clean();
ob_start();
var_dump($act);
$dump_act = ob_get_clean();
if ($dump_act !== $dump_exp) {
echo "Var dump differs:\n", $dump_act, "\n", $dump_exp, "\n";
} else {
echo "Var dump OK\n";
}
$act['foo'][1] = 'test value';
$exp['foo'][1] = 'test value';
if ($act['foo'][1] !== $act['foo'][2]['foo'][1]) {
echo "Recursive elements differ:\n";
var_dump($act);
var_dump($act['foo']);
var_dump($exp);
var_dump($exp['foo']);
}
?>
--EXPECT--
array
140211016114021101621101631101641101651101662514020e0001010e05250102
OK
Var dump OK
igbinary-2.0.5/tests/igbinary_026b.phpt 0000644 0001750 0001750 00000001750 13177372464 017051 0 ustar tyson tyson --TEST--
Cyclic array test 2
--INI--
report_memleaks=0
--SKIPIF--
&$b);
$b = array(1, 2, $a);
/* all three statements below should produce same output however PHP stock
* unserialize/serialize produces different output (5.2.16). I consider this is
* a PHP bug. - Oleg Grenrus
*/
//$k = $a;
//$k = unserialize(serialize($a));
$k = igbinary_unserialize(igbinary_serialize($a));
function check($a, $k) {
ob_start();
var_dump($a);
$a_str = ob_get_clean();
ob_start();
var_dump($k);
$k_str = ob_get_clean();
if ($a_str !== $k_str) {
echo "Output differs\n";
echo "Expected:\n", $a_str, "\n";
echo "Actual:\n", $k_str, "\n";
} else {
echo "OK\n";
}
}
check($a, $k);
$a["foo"][2]["foo"][1] = "b";
$k["foo"][2]["foo"][1] = "b";
check($a, $k);
?>
--EXPECT--
OK
OK
igbinary-2.0.5/tests/igbinary_027.phpt 0000644 0001750 0001750 00000003040 13177372464 016702 0 ustar tyson tyson --TEST--
Check for serialization handler
--SKIPIF--
--EXPECT--
bool(true)
read
wrote: 14021103666f6f06011104746573741106666f6f626172
igbinary-2.0.5/tests/igbinary_028.phpt 0000644 0001750 0001750 00000004551 13177372464 016713 0 ustar tyson tyson --TEST--
Serialize object into session, full set
--SKIPIF--
d1 = $foo;
$this->d2 = $foo;
$this->d3 = $foo;
}
}
class Bar {
private static $s1 = array();
protected static $s2 = array();
public static $s3 = array();
public $d1;
private $d2;
protected $d3;
public function __construct() {
}
public function set($foo) {
$this->d1 = $foo;
$this->d2 = $foo;
$this->d3 = $foo;
}
}
if(!extension_loaded('igbinary')) {
dl('igbinary.' . PHP_SHLIB_SUFFIX);
}
$output = '';
function open($path, $name) {
return true;
}
function close() {
return true;
}
function read($id) {
global $output;
$output .= "read\n";
$a = new Bar();
$b = new Foo($a);
$a->set($b);
$session = array('old' => $b);
return igbinary_serialize($session);
}
function write($id, $data) {
global $output;
$output .= "write: ";
$output .= substr(bin2hex($data), 8). "\n";
return true;
}
function destroy($id) {
return true;
}
function gc($time) {
return true;
}
ini_set('session.serialize_handler', 'igbinary');
session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');
session_start();
$_SESSION['test'] = "foobar";
$a = new Bar();
$b = new Foo($a);
$a->set($b);
$_SESSION['new'] = $a;
session_write_close();
echo $output;
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
read
write: 140311036f6c641703466f6f1403110700466f6f0064311703426172140311026431220111070042617200643222011105002a00643322011105002a00643222021102643322021104746573741106666f6f62617211036e65771a0314030e041a0114030e0222030e0722030e0822030e0522040e062204
igbinary-2.0.5/tests/igbinary_029.phpt 0000644 0001750 0001750 00000000706 13177372464 016712 0 ustar tyson tyson --TEST--
Igbinary module info
--SKIPIF--
--FILE--
enabled
igbinary version => %s
igbinary AP%s serializer ABI => %s
igbinary session support => %s
igbinary.compact_strings => %s => %s
igbinary-2.0.5/tests/igbinary_030_php72.phpt 0000644 0001750 0001750 00000002067 13177372464 017724 0 ustar tyson tyson --TEST--
Unserialize invalid data (php 7.2+)
--SKIPIF--
--FILE--
{"1"} = "manual";
$datas = array(
87817,
-1,
array(1,2,3,"testing" => 10, "foo"),
true,
false,
0.187182,
"dakjdh98389\000",
null,
(object)array(1,2,3),
$o,
);
error_reporting(0);
foreach ($datas as $data) {
$str = igbinary_serialize($data);
$len = strlen($str);
// truncated
for ($i = 0; $i < $len - 1; $i++) {
$v = igbinary_unserialize(substr($str, 0, $i));
if (is_object($data) && $v !== null && $v == $data) {
continue;
} elseif ($v !== null && $v != FALSE && $v !== $data) {
echo "output at $i:\n";
var_dump($v);
echo "vs.\n";
var_dump($data);
}
}
// padded
$str .= "98398afa\000y21_ ";
$v = igbinary_unserialize($str);
if ($v !== $data && !(is_object($data) && $v == $data)) {
echo "padded should get original\n";
var_dump($v);
echo "vs.\n";
var_dump($data);
}
}
?>
--EXPECT--
igbinary-2.0.5/tests/igbinary_030_php7.phpt 0000644 0001750 0001750 00000002416 13177372464 017640 0 ustar tyson tyson --TEST--
Unserialize invalid data
--SKIPIF--
= 70200 || PHP_VERSION_ID < 70000) {
echo "Skip php 7.1 or 7.0 required\n";
}
?>
--FILE--
{"1"} = "manual";
$datas = array(
87817,
-1,
array(1,2,3,"testing" => 10, "foo"),
true,
false,
0.187182,
"dakjdh98389\000",
null,
(object)array(1,2,3),
$o,
);
error_reporting(0);
foreach ($datas as $data) {
$str = igbinary_serialize($data);
$len = strlen($str);
// truncated
for ($i = 0; $i < $len - 1; $i++) {
$v = igbinary_unserialize(substr($str, 0, $i));
if (is_object($data) && $v !== null && $v == $data) {
continue;
} elseif ($v !== null && $v != FALSE && $v !== $data) {
echo "output at $i:\n";
var_dump($v);
echo "vs.\n";
var_dump($data);
}
}
// padded
$str .= "98398afa\000y21_ ";
$v = igbinary_unserialize($str);
if ($v !== $data && !(is_object($data) && $v == $data)) {
echo "padded should get original\n";
var_dump($v);
echo "vs.\n";
var_dump($data);
}
}
?>
--EXPECT--
padded should get original
object(stdClass)#3 (3) {
["0"]=>
int(1)
["1"]=>
int(2)
["2"]=>
int(3)
}
vs.
object(stdClass)#2 (3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
igbinary-2.0.5/tests/igbinary_030.phpt 0000644 0001750 0001750 00000002745 13177372464 016707 0 ustar tyson tyson --TEST--
Unserialize invalid data (PHP 5)
--SKIPIF--
= 70000) {
echo "Skip php 5.6 or older required\n";
}
?>
--FILE--
{"1"} = "manual";
$datas = array(
87817,
-1,
array(1,2,3,"testing" => 10, "foo"),
true,
false,
0.187182,
"dakjdh98389\000",
null,
(object)array(1,2,3),
$o, // some weirdness unserializing with zend_hash_update on strings that are integers.
);
error_reporting(0);
foreach ($datas as $data) {
$str = igbinary_serialize($data);
$len = strlen($str);
// truncated
for ($i = 0; $i < $len - 1; $i++) {
$v = igbinary_unserialize(substr($str, 0, $i));
if (is_object($data) && $v !== null && $v == $data) {
continue;
} elseif ($v !== null && $v != FALSE && $v !== $data) {
echo "output at $i:\n";
var_dump($v);
echo "vs.\n";
var_dump($data);
}
}
// padded
$str .= "98398afa\000y21_ ";
$v = igbinary_unserialize($str);
if ($v !== $data && !(is_object($data) && $v == $data)) {
echo "padded should get original\n";
var_dump($v);
echo "vs.\n";
var_dump($data);
}
}
?>
--EXPECT--
padded should get original
object(stdClass)#8 (3) {
["0"]=>
int(1)
["1"]=>
int(2)
["2"]=>
int(3)
}
vs.
object(stdClass)#2 (3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
padded should get original
object(stdClass)#11 (1) {
[1]=>
string(6) "manual"
}
vs.
object(stdClass)#1 (1) {
["1"]=>
string(6) "manual"
}
igbinary-2.0.5/tests/igbinary_031.phpt 0000644 0001750 0001750 00000003331 13177372464 016700 0 ustar tyson tyson --TEST--
Object Serializable interface throws exceptions
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
public function serialize() {
$c = self::$count++;
echo "call serialize, ", ($this->a ? "throw" : "no throw"),"\n";
if ($this->a) {
throw new Exception("exception in serialize $c");
}
return pack('NN', $this->a, $this->b);
}
public function unserialize($serialized) {
$tmp = unpack('N*', $serialized);
$this->__construct($tmp[1], $tmp[2]);
$c = self::$count++;
echo "call unserialize, ", ($this->b ? "throw" : "no throw"),"\n";
if ($this->b) {
throw new Exception("exception in unserialize $c");
}
}
}
$a = new Obj(1, 0);
$a = new Obj(0, 0);
$b = new Obj(0, 0);
$c = new Obj(1, 0);
$d = new Obj(0, 1);
echo "a, a, c\n";
try {
test(array($a, $a, $c));
} catch (Exception $e) {
if (version_compare(phpversion(), "5.3.0", ">=")) {
if ($e->getPrevious()) {
$e = $e->getPrevious();
}
}
echo $e->getMessage(), "\n";
}
echo "b, b, d\n";
try {
test(array($b, $b, $d));
} catch (Exception $e) {
if (version_compare(phpversion(), "5.3.0", ">=")) {
if ($e->getPrevious()) {
$e = $e->getPrevious();
}
}
echo $e->getMessage(), "\n";
}
--EXPECT--
a, a, c
call serialize, no throw
call serialize, throw
exception in serialize 2
b, b, d
call serialize, no throw
call serialize, no throw
call unserialize, no throw
call unserialize, throw
exception in unserialize 6
igbinary-2.0.5/tests/igbinary_032.phpt 0000644 0001750 0001750 00000002605 13177372464 016704 0 ustar tyson tyson --TEST--
Object test, __sleep and __wakeup exceptions
--SKIPIF--
a = $a;
$this->b = $b;
}
function __sleep() {
$c = self::$count++;
if ($this->a) {
throw new Exception("exception in __sleep $c");
}
return array('a', 'b');
}
function __wakeup() {
$c = self::$count++;
if ($this->b) {
throw new Exception("exception in __wakeup $c");
}
$this->b = $this->a * 3;
}
}
$a = new Obj(1, 0);
$b = new Obj(0, 1);
$c = new Obj(0, 0);
try {
test($a);
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
try {
test($b);
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
try {
test($c);
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
/*
* you can add regression tests for your extension here
*
* the output of your test code has to be equal to the
* text in the --EXPECT-- section below for the tests
* to pass, differences between the output and the
* expected text are interpreted as failure
*
* see php5/README.TESTING for further information on
* writing regression tests
*/
?>
--EXPECT--
exception in __sleep 0
exception in __wakeup 2
igbinary-2.0.5/tests/igbinary_033.phpt 0000644 0001750 0001750 00000001555 13177372464 016710 0 ustar tyson tyson --TEST--
Object test, cyclic references
--SKIPIF--
parent = null;
$this->children = array();
}
public function addChild(Foo $obj) {
$this->children[] = $obj;
$obj->setParent($this);
}
public function setParent(Foo $obj) {
$this->parent = $obj;
}
}
$obj1 = new Foo();
for ($i = 0; $i < 10; $i++) {
$obj = new Foo();
$obj1->addChild($obj);
}
$o = igbinary_unserialize(igbinary_serialize($obj1->children));
foreach ($obj1->children as $k => $v) {
$obj_v = $v;
$o_v = $o[$k];
echo gettype($obj_v), "\t", gettype($o_v), "\n";
}
--EXPECT--
object object
object object
object object
object object
object object
object object
object object
object object
object object
object object
igbinary-2.0.5/tests/igbinary_034.phpt 0000644 0001750 0001750 00000001164 13177372464 016705 0 ustar tyson tyson --TEST--
Unserialize invalid random data
--SKIPIF--
10, "foo"),
true,
false,
0.187182,
"dakjdh98389\000",
null,
(object)array(1,2,3),
);
error_reporting(0);
foreach ($datas as $data) {
$str = igbinary_serialize($data);
$len = strlen($str);
for ($j = 0; $j < 200; $j++) {
for ($i = 0; $i < $len - 1; $i++) {
$sub = substr($str, 0, $i);
$sub .= mcrypt_create_iv(30, MCRYPT_DEV_URANDOM);
$php_errormsg = null;
$v = igbinary_unserialize($sub);
}
}
}
--EXPECT--
igbinary-2.0.5/tests/igbinary_040.phpt 0000644 0001750 0001750 00000002347 13177372464 016706 0 ustar tyson tyson --TEST--
b0rked random data test
--SKIPIF--
--FILE--
--EXPECT--
igbinary-2.0.5/tests/igbinary_041.phpt 0000644 0001750 0001750 00000004160 13177372464 016702 0 ustar tyson tyson --TEST--
Check for double NaN, Inf, -Inf, 0, and -0. IEEE 754 doubles
--FILE--
--INI--
igbinary.compact_strings=Off
--FILE--
$object) {
if (!isset($actual_array[$key])) {
$error = 'ERROR';
echo "Key $key is missing from result.\n";
echo "Expected key/value:\n";
var_dump($key, $object);
var_dump($object);
break;
}
if (!is_object($actual_array[$key]) ||
get_class($object) !== get_class($actual_array[$key])) {
$error = 'ERROR';
echo "Array mismatch on $key\n";
echo "Expected key/value:\n";
var_dump($key, $object);
echo "Actual key/value:\n";
var_dump($key, $actual_array[$key]);
break;
}
}
echo $error, "\n";
--EXPECT--
OK
igbinary-2.0.5/tests/igbinary_044.phpt 0000644 0001750 0001750 00000011224 13177372464 016704 0 ustar tyson tyson --TEST--
Check for double extremes
--FILE--
getVersion(), '3.1.7', '<')) {
echo "skip require APC version 3.1.7 or above";
}
--INI--
apc.enable_cli=1
apc.serializer=igbinary
--FILE--
int(10)
}
igbinary-2.0.5/tests/igbinary_045b.phpt 0000644 0001750 0001750 00000001072 13177372464 017047 0 ustar tyson tyson --TEST--
APCu serializer registration
--SKIPIF--
getVersion(), '4.0.2', '<')) {
echo "skip require APCu version 4.0.2 or above";
}
--INI--
apc.enable_cli=1
apc.serializer=igbinary
extension=apcu.so
--FILE--
int(10)
}
igbinary-2.0.5/tests/igbinary_045c.phpt 0000644 0001750 0001750 00000003506 13177372464 017054 0 ustar tyson tyson --TEST--
APCu serializer registration - more data types
--INI--
apc.enable_cli=1
apc.serializer=igbinary
extension=apcu.so
--SKIPIF--
getVersion(), '4.0.2') < 0) {
echo "skip require APCu version 4.0.2 or above";
return;
}
if (PHP_MAJOR_VERSION >= 7) {
if (version_compare($ext->getVersion(), '5.1.6') < 0) {
echo "skip require APCu version 5.1.6 or above";
return;
}
}
?>
--FILE--
foo = $a;
apcu_store('objloop', $a);
unset($a);
var_dump(apcu_fetch('objloop'));
apcu_store('nullval', null);
var_dump(apcu_fetch('nullval'));
apcu_store('intval', 777);
var_dump(apcu_fetch('intval'));
$o = new stdClass();
$o->prop = 5;
$a = [$o, $o];
apcu_store('simplearrayval', $a);
$unserialized = apcu_fetch('simplearrayval');
var_dump($unserialized);
if ($unserialized[0] === $unserialized[1]) {
echo "SAME\n";
} else {
echo "DIFFERENT\n";
printf("%s\n", bin2hex(igbinary_serialize($a)));
}
unset($o);
unset($a);
unset($unserialized);
$o = new stdClass();
$o->prop = 6;
$a = [&$o, &$o];
apcu_store('refarrayval', $a);
$unserialized = apcu_fetch('refarrayval');
var_dump($unserialized);
if ($unserialized[0] === $unserialized[1]) {
echo "SAME\n";
} else {
echo "DIFFERENT\n";
printf("%s\n", bin2hex(igbinary_serialize($a)));
}
?>
--EXPECTF--
igbinary
object(Bar)#%d (1) {
["foo"]=>
*RECURSION*
}
NULL
int(777)
array(2) {
[0]=>
object(stdClass)#%d (1) {
["prop"]=>
int(5)
}
[1]=>
object(stdClass)#%d (1) {
["prop"]=>
int(5)
}
}
SAME
array(2) {
[0]=>
&object(stdClass)#%d (1) {
["prop"]=>
int(6)
}
[1]=>
&object(stdClass)#%d (1) {
["prop"]=>
int(6)
}
}
SAME
igbinary-2.0.5/tests/igbinary_046.phpt 0000644 0001750 0001750 00000001064 13177372464 016707 0 ustar tyson tyson --TEST--
Correctly unserialize scalar refs.
--SKIPIF--
&string(1) "V"
[1]=>
&string(1) "V"
[2]=>
&string(1) "V"
[3]=>
&string(1) "V"
}
igbinary-2.0.5/tests/igbinary_046b.phpt 0000644 0001750 0001750 00000001301 13177372464 017043 0 ustar tyson tyson --TEST--
Correctly unserialize multiple object refs.
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
&string(1) "V"
[1]=>
&string(1) "V"
[2]=>
&string(1) "V"
[3]=>
&string(1) "V"
}
igbinary-2.0.5/tests/igbinary_046c.phpt 0000644 0001750 0001750 00000001213 13177372464 017046 0 ustar tyson tyson --TEST--
Correctly unserialize multiple array refs.
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
&string(1) "V"
[1]=>
&string(1) "V"
[2]=>
&string(1) "V"
[3]=>
&string(1) "V"
}
igbinary-2.0.5/tests/igbinary_046d.phpt 0000644 0001750 0001750 00000002520 13177372464 017051 0 ustar tyson tyson --TEST--
Correctly unserialize multiple object refs and non-refs.
--SKIPIF--
object(stdClass)#%d (0) {
}
[1]=>
&object(stdClass)#%d (0) {
}
[2]=>
&object(stdClass)#%d (0) {
}
[3]=>
object(stdClass)#%d (0) {
}
}
a:4:{i:0;O:8:"stdClass":0:{}i:1;R:2;i:2;R:2;i:3;r:2;}
00000002140406001708737464436c61737314000601252201060225220106032201
a:4:{i:0;O:8:"stdClass":0:{}i:1;R:2;i:2;R:2;i:3;r:2;}
array(4) {
[0]=>
object(stdClass)#%d (0) {
}
[1]=>
&object(stdClass)#%d (0) {
}
[2]=>
&object(stdClass)#%d (0) {
}
[3]=>
object(stdClass)#%d (0) {
}
}
array(4) {
[0]=>
object(stdClass)#%d (0) {
}
[1]=>
&string(1) "V"
[2]=>
&string(1) "V"
[3]=>
object(stdClass)#%d (0) {
}
}
igbinary-2.0.5/tests/igbinary_047.phpt 0000644 0001750 0001750 00000004046 13177372464 016713 0 ustar tyson tyson --TEST--
Check for serialization handler, SessionHandlerInterface
--SKIPIF--
= 5.4.0)
if (version_compare(phpversion(), "5.4.0", "<")) {
exit("skip php version less than 5.4.x");
}
if (!extension_loaded('session')) {
exit('skip session extension not loaded');
}
ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();
$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
exit('skip igbinary session handler not available');
}
--FILE--
--EXPECT--
bool(true)
read
wrote: 14021103666f6f06011104746573741106666f6f626172
igbinary-2.0.5/tests/igbinary_048.phpt 0000644 0001750 0001750 00000001461 13177372464 016712 0 ustar tyson tyson --TEST--
Object test, __set not called for private attr in extended class
--SKIPIF--
= 5.4.0)
if (version_compare(phpversion(), "5.4.0", "<")) {
exit("skip php version less than 5.4.x");
}
--FILE--
a = [1, 2, 3];
$x->nonexistent = 'aaa';
igbinary_unserialize(igbinary_serialize($x));
--EXPECT--
magic function called for nonexistent with 'aaa'
igbinary-2.0.5/tests/igbinary_048b.phpt 0000644 0001750 0001750 00000001331 13177372464 017050 0 ustar tyson tyson --TEST--
Object test, __set not called for private attr in extended class
--SKIPIF--
= 5.4.0)
if (version_compare(phpversion(), "5.4.0", "<")) {
exit("skip php version less than 5.4.x");
}
--FILE--
a = [1, 2, 3];
$x->nonexistent = 'aaa';
unserialize(serialize($x));
--EXPECT--
magic function called for nonexistent with 'aaa'
igbinary-2.0.5/tests/igbinary_049.phpt 0000644 0001750 0001750 00000003466 13177372464 016722 0 ustar tyson tyson --TEST--
Correctly unserialize multiple references in arrays
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
prop = &$a[8];
$a[11] = &$a[10];
$a[12] = $a[9];
$ig_ser = igbinary_serialize($a);
printf("ig_ser=%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
var_dump($ig);
$f = &$ig[3];
$f = 'V';
$g = &$ig[5];
$g = 'H';
$h = $ig[10];
$h->prop = 'S';
var_dump($ig);
--EXPECTF--
ig_ser=00000002140d0600251101410601250101060225010106032501010604250406052501020606251703466f6f1400060725220306082522030609140106000621060a251708737464436c6173731401110470726f70252203060b252205060c0104
array(13) {
[0]=>
&string(1) "A"
[1]=>
&string(1) "A"
[2]=>
&string(1) "A"
[3]=>
&string(1) "A"
[4]=>
&bool(false)
[5]=>
&bool(false)
[6]=>
&object(Foo)#%d (0) {
}
[7]=>
&object(Foo)#%d (0) {
}
[8]=>
&object(Foo)#%d (0) {
}
[9]=>
array(1) {
[0]=>
int(33)
}
[10]=>
&object(stdClass)#%d (1) {
["prop"]=>
&object(Foo)#%d (0) {
}
}
[11]=>
&object(stdClass)#%d (1) {
["prop"]=>
&object(Foo)#%d (0) {
}
}
[12]=>
array(1) {
[0]=>
int(33)
}
}
array(13) {
[0]=>
&string(1) "V"
[1]=>
&string(1) "V"
[2]=>
&string(1) "V"
[3]=>
&string(1) "V"
[4]=>
&string(1) "H"
[5]=>
&string(1) "H"
[6]=>
&string(1) "S"
[7]=>
&string(1) "S"
[8]=>
&string(1) "S"
[9]=>
array(1) {
[0]=>
int(33)
}
[10]=>
&object(stdClass)#%d (1) {
["prop"]=>
&string(1) "S"
}
[11]=>
&object(stdClass)#%d (1) {
["prop"]=>
&string(1) "S"
}
[12]=>
array(1) {
[0]=>
int(33)
}
}
igbinary-2.0.5/tests/igbinary_049b.phpt 0000644 0001750 0001750 00000002647 13177372464 017064 0 ustar tyson tyson --TEST--
Correctly unserialize multiple references in objects
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
x0 = NULL;
$a->x1 = &$a->x0;
$a->x2 = &$a->x1;
$a->x3 = &$a->x2;
$a->x4 = false;
$a->x5 = &$a->x4;
$a->x6 = new Foo();
$a->x7 = &$a->x6;
$a->x8 = &$a->x7;
$a->x9 = array(33);
$a->x10 = new stdClass();
$a->x10->prop = &$a->x8;
$a->x11 = &$a->x10;
$a->x12 = $a->x9;
$ig_ser = igbinary_serialize($a);
printf("ig_ser=%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
$f = &$ig->x3;
$f = 'V';
$g = &$ig->x5;
$g = 'H';
$h = $ig->x10;
$h->prop = 'S';
var_dump($ig);
--EXPECTF--
ig_ser=000000021708737464436c617373140d1102783025001102783125010111027832250101110278332501011102783425041102783525010211027836251703466f6f14001102783725220311027838252203110278391401060006211103783130251a001401110470726f70252203110378313125220511037831320104
object(stdClass)#%d (13) {
["x0"]=>
&string(1) "V"
["x1"]=>
&string(1) "V"
["x2"]=>
&string(1) "V"
["x3"]=>
&string(1) "V"
["x4"]=>
&string(1) "H"
["x5"]=>
&string(1) "H"
["x6"]=>
&string(1) "S"
["x7"]=>
&string(1) "S"
["x8"]=>
&string(1) "S"
["x9"]=>
array(1) {
[0]=>
int(33)
}
["x10"]=>
&object(stdClass)#%d (1) {
["prop"]=>
&string(1) "S"
}
["x11"]=>
&object(stdClass)#%d (1) {
["prop"]=>
&string(1) "S"
}
["x12"]=>
array(1) {
[0]=>
int(33)
}
}
igbinary-2.0.5/tests/igbinary_050.phpt 0000644 0001750 0001750 00000002025 13177372464 016700 0 ustar tyson tyson --TEST--
Correctly unserialize cyclic object references
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
foo = &$a;
$a->bar = &$a;
$b = new stdClass();
$b->cyclic = &$a;
printf("%s\n", serialize($b));
$ig_ser = igbinary_serialize($b);
printf("%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
printf("%s\n", serialize($ig));
var_dump($ig);
$f = &$ig->cyclic->foo;
$f = 'V';
var_dump($ig);
// Note: While the php7 unserializer consistently makes a distinction between refs to an object and non-refs,
// the php5 serializer does not yet.
--EXPECTF--
O:8:"stdClass":1:{s:6:"cyclic";O:8:"stdClass":2:{s:3:"foo";R:2;s:3:"bar";R:2;}}
000000021708737464436c617373140111066379636c6963251a0014021103666f6f2522011103626172252201
O:8:"stdClass":1:{s:6:"cyclic";O:8:"stdClass":2:{s:3:"foo";R:2;s:3:"bar";R:2;}}
object(stdClass)#3 (1) {
["cyclic"]=>
&object(stdClass)#4 (2) {
["foo"]=>
*RECURSION*
["bar"]=>
*RECURSION*
}
}
object(stdClass)#3 (1) {
["cyclic"]=>
&string(1) "V"
}
igbinary-2.0.5/tests/igbinary_051.phpt 0000644 0001750 0001750 00000001457 13177372464 016711 0 ustar tyson tyson --TEST--
Object test, __wakeup (With multiple references)
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
function __wakeup() {
$this->b = $this->a * 3;
}
}
function main() {
$o = new Obj(1, 2);
$variable = array(&$o, &$o);
$serialized = igbinary_serialize($variable);
$unserialized = igbinary_unserialize($serialized);
echo substr(bin2hex($serialized), 8), "\n";
echo $unserialized[0]->b === 3 && $unserialized[0]->a === 1 ? 'OK' : 'ERROR';
echo "\n";
$unserialized[0] = 'a';
var_dump($unserialized);
}
main();
--EXPECT--
140206002517034f626a1402110161060111016206020601252201
OK
array(2) {
[0]=>
&string(1) "a"
[1]=>
&string(1) "a"
}
igbinary-2.0.5/tests/igbinary_052.phpt 0000644 0001750 0001750 00000002765 13177372464 016715 0 ustar tyson tyson --TEST--
Object Serializable interface can be serialized in references
--SKIPIF--
--FILE--
a = $a;
$this->b = $b;
}
public function serialize() {
$c = self::$count++;
echo "call serialize\n";
return pack('NN', $this->a, $this->b);
}
public function unserialize($serialized) {
$tmp = unpack('N*', $serialized);
$this->__construct($tmp[1], $tmp[2]);
$c = self::$count++;
echo "call unserialize\n";
}
}
function main() {
$a = new Obj(1, 0);
$b = new Obj(42, 43);
$variable = array(&$a, &$a, $b);
$serialized = igbinary_serialize($variable);
printf("%s\n", bin2hex($serialized));
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
$unserialized[0] = 'A';
var_dump($unserialized[1]);
}
main();
--EXPECTF--
call serialize
call serialize
00000002140306002517034f626a1d080000000100000000060125220106021a001d080000002a0000002b
call unserialize
call unserialize
array(3) {
[0]=>
&object(Obj)#%d (2) {
["a"]=>
int(1)
["b"]=>
int(0)
}
[1]=>
&object(Obj)#%d (2) {
["a"]=>
int(1)
["b"]=>
int(0)
}
[2]=>
object(Obj)#%d (2) {
["a"]=>
int(42)
["b"]=>
int(43)
}
}
string(1) "A"
igbinary-2.0.5/tests/igbinary_053.phpt 0000644 0001750 0001750 00000002137 13177372464 016707 0 ustar tyson tyson --TEST--
__wakeup can modify properties without affecting other objects
--SKIPIF--
a = $a;
}
public function __wakeup() {
echo "call wakeup\n";
$this->a[] = "end";
}
}
function main() {
$array = ["test"]; // array (not a reference, but should be copied on write)
$a = new Obj($array);
$b = new Obj($array);
$variable = [$a, $b];
$serialized = igbinary_serialize($variable);
printf("%s\n", bin2hex($serialized));
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
}
main();
--EXPECTF--
000000021402060017034f626a14011101611401060011047465737406011a0014010e010102
call wakeup
call wakeup
array(2) {
[0]=>
object(Obj)#%d (1) {
["a"]=>
array(2) {
[0]=>
string(4) "test"
[1]=>
string(3) "end"
}
}
[1]=>
object(Obj)#%d (1) {
["a"]=>
array(2) {
[0]=>
string(4) "test"
[1]=>
string(3) "end"
}
}
}
igbinary-2.0.5/tests/igbinary_054.phpt 0000644 0001750 0001750 00000002610 13177372464 016704 0 ustar tyson tyson --TEST--
__wakeup can add dynamic properties without affecting other objects
--SKIPIF--
--FILE--
a being a dynamic property.
function __construct($a) {
$this->a = $a;
}
public function __wakeup() {
echo "Calling __wakeup\n";
for ($i = 0; $i < 10000; $i++) {
$this->{'b' . $i} = 42;
}
}
}
function main() {
$array = array("roh"); // array (not a reference, but should be copied on write)
$a = new Obj($array);
$b = new Obj($array);
$c = new Obj(null);
$variable = array($a, $b, $c);
$serialized = igbinary_serialize($variable);
printf("%s\n", bin2hex($serialized));
$unserialized = igbinary_unserialize($serialized);
echo "Called igbinary_unserialize\n";
for ($a = 0; $a < 3; $a++) {
for ($i = 0; $i < 10000; $i++) {
if ($unserialized[$a]->{'b' . $i} !== 42) {
echo "Fail $a b$i\n";
return;
}
unset($unserialized[$a]->{'b' . $i});
}
}
var_dump($unserialized);
}
main();
--EXPECTF--
000000021403060017034f626a1401110161140106001103726f6806011a0014010e01010206021a0014010e0100
Calling __wakeup
Calling __wakeup
Calling __wakeup
Called igbinary_unserialize
array(3) {
[0]=>
object(Obj)#%d (1) {
["a"]=>
array(1) {
[0]=>
string(3) "roh"
}
}
[1]=>
object(Obj)#%d (1) {
["a"]=>
array(1) {
[0]=>
string(3) "roh"
}
}
[2]=>
object(Obj)#%d (1) {
["a"]=>
NULL
}
}
igbinary-2.0.5/tests/igbinary_055.phpt 0000644 0001750 0001750 00000001216 13177372464 016706 0 ustar tyson tyson --TEST--
__wakeup can replace a copy of the object referring to the root node.
--SKIPIF--
--FILE--
a = $a;
}
public function __wakeup() {
echo "Calling __wakeup\n";
$this->a = "replaced";
}
}
$a = new stdClass();
$a->obj = new Obj($a);;
$serialized = igbinary_serialize($a);
printf("%s\n", bin2hex($serialized));
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
--EXPECTF--
000000021708737464436c617373140111036f626a17034f626a14011101612200
Calling __wakeup
object(stdClass)#%d (1) {
["obj"]=>
object(Obj)#%d (1) {
["a"]=>
string(8) "replaced"
}
}
igbinary-2.0.5/tests/igbinary_057.phpt 0000644 0001750 0001750 00000001747 13177372464 016721 0 ustar tyson tyson --TEST--
Test serializing more strings than the capacity of the initial strings table.
--SKIPIF--
--FILE--
--EXPECT--
1432060011016106011101620602110163060311016406041101650605110166060611016706071101680608110169060911016a060a11016b060b11016c060c11016d060d11016e060e11016f060f11017006101101710611110172061211017306131101740614110175061511017606161101770617110178061811017906190e00061a0e01061b0e02061c0e03061d0e04061e0e05061f0e0606200e0706210e0806220e0906230e0a06240e0b06250e0c06260e0d06270e0e06280e0f06290e10062a0e11062b0e12062c0e13062d0e14062e0e15062f0e1606300e1706310e18
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y
igbinary-2.0.5/tests/igbinary_058.phpt 0000644 0001750 0001750 00000002707 13177372464 016717 0 ustar tyson tyson --TEST--
Should not call __destruct if __wakeup throws an exception
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
id = $id;
$this->throws = $throws;
$this->dynamic = "original";
}
public function __wakeup() {
printf("Calling __wakeup %s\n", $this->id);
$this->dynamic = "copy";
if ($this->throws) {
throw new Exception("__wakeup threw");
}
}
public function __destruct() {
printf("Calling __destruct %s dynamic=%s\n", $this->id, $this->dynamic);
}
}
function main() {
$a = new Thrower("a", true);
$serialized = igbinary_serialize($a);
try {
igbinary_unserialize($serialized);
} catch (Exception $e) {
printf("Caught %s\n", $e->getMessage());
}
$a = null;
print("Done a\n");
$b = new Thrower("b", false);
$serialized = igbinary_serialize($b);
$bCopy = igbinary_unserialize($serialized);
print("Unserialized b\n");
var_dump($bCopy);
$bCopy = null;
$b = null;
print("Done b\n");
}
main();
--EXPECT--
Calling __wakeup a
Caught __wakeup threw
Calling __destruct a dynamic=original
Done a
Calling __wakeup b
Unserialized b
object(Thrower)#2 (3) {
["id"]=>
string(1) "b"
["throws"]=>
bool(false)
["dynamic"]=>
string(4) "copy"
}
Calling __destruct b dynamic=copy
Calling __destruct b dynamic=original
Done b
igbinary-2.0.5/tests/igbinary_058b.phpt 0000644 0001750 0001750 00000002721 13177372464 017055 0 ustar tyson tyson --TEST--
Should not call __destruct if __wakeup throws an exception (in arrays)
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
id = $id;
$this->throws = $throws;
$this->dynamic = "original";
}
public function __wakeup() {
printf("Calling __wakeup %s\n", $this->id);
$this->dynamic = "copy";
if ($this->throws) {
throw new Exception("__wakeup threw for id " . $this->id);
}
}
public function __destruct() {
printf("Calling __destruct %s dynamic=%s\n", $this->id, $this->dynamic);
}
}
function main() {
$values = [
0 => new Thrower("a", false),
'foo' => 'last',
'key1' => new Thrower("b", false),
2 => new Thrower("c", true),
'last' => new Thrower("d", false),
];
$serialized = igbinary_serialize($values);
$values = null;
printf("Going to unserialize\n");
try {
igbinary_unserialize($serialized);
} catch (Exception $e) {
printf("Caught %s\n", $e->getMessage());
}
}
main();
--EXPECT--
Calling __destruct a dynamic=original
Calling __destruct b dynamic=original
Calling __destruct c dynamic=original
Calling __destruct d dynamic=original
Going to unserialize
Calling __wakeup a
Calling __wakeup b
Calling __wakeup c
Calling __destruct a dynamic=copy
Calling __destruct b dynamic=copy
Caught __wakeup threw for id c
igbinary-2.0.5/tests/igbinary_059.phpt 0000644 0001750 0001750 00000002365 13177372464 016720 0 ustar tyson tyson --TEST--
igbinary_unserialize should never convert from packed array to hash when references exist (Bug #48)
--SKIPIF--
--FILE--
= 16) is added (converted to a hash), causing a segfault.
foreach (array(0, 50) as $i) {
$inner = new stdClass();
$inner->a = $i;
$result[0][0][$i] = $inner;
$result[1][] = $inner;
}
$serialized = igbinary_serialize($result);
printf("%s\n", bin2hex(substr($serialized, 4)));
flush();
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
}
main();
?>
--EXPECTF--
1402060014010600140206001708737464436c6173731401110161060006321a0014010e010632060114020600220306012204
array(2) {
[0]=>
array(1) {
[0]=>
array(2) {
[0]=>
object(stdClass)#%d (1) {
["a"]=>
int(0)
}
[50]=>
object(stdClass)#%d (1) {
["a"]=>
int(50)
}
}
}
[1]=>
array(2) {
[0]=>
object(stdClass)#%d (1) {
["a"]=>
int(0)
}
[1]=>
object(stdClass)#%d (1) {
["a"]=>
int(50)
}
}
}
igbinary-2.0.5/tests/igbinary_060.phpt 0000644 0001750 0001750 00000002517 13177372464 016707 0 ustar tyson tyson --TEST--
Igbinary_unserialize_header warning
--SKIPIF--
--FILE--
c = $this->b . 'OnWakeup';
}
}
error_reporting(E_ALL);
// Start session
session_start();
// The serialization of DateTime varies in php5 and php 7.
$_SESSION['date'] = new \DateTime('@1234567890');
$a = new A();
$a->b = 'value';
$_SESSION['a'] = $a;
var_dump($_SESSION['date']->getTimestamp());
$mydata = session_encode();
unset($_SESSION['date']);
var_dump(session_decode($mydata));
var_dump($_SESSION['date']->getTimestamp());
var_dump($_SESSION['a']->c);
?>
--EXPECT--
int(1234567890)
bool(true)
int(1234567890)
string(13) "valueOnWakeup"
igbinary-2.0.5/tests/igbinary_062.phpt 0000644 0001750 0001750 00000002063 13177372464 016705 0 ustar tyson tyson --TEST--
igbinary should not call __wakeup() if Serializable::unserialize was used to unserialize the object data (like `unserialize`)
--FILE--
prop . "\n";
return $this->prop;
}
public function unserialize($data) {
echo "In unserialize $data\n";
$this->prop = $data;
}
public function __wakeup() {
echo "In __wakeup, unexpectedly\n";
}
}
function testA() {
$a = new A();
$a->prop = 'other';
$ser = serialize($a);
$b = unserialize($ser);
var_dump($b);
$c = new A();
$c->prop = 'igprop';
$serC = igbinary_serialize($c);
echo bin2hex($serC) . "\n";
$d = igbinary_unserialize($serC);
var_dump($d);
}
testA();
?>
--EXPECTF--
In serialize other
In unserialize other
object(A)#%d (1) {
["prop"]=>
string(5) "other"
}
In serialize igprop
000000021701411d06696770726f70
In unserialize igprop
object(A)#%d (1) {
["prop"]=>
string(6) "igprop"
}
igbinary-2.0.5/tests/igbinary_063_php72.phpt 0000644 0001750 0001750 00000002276 13177372464 017734 0 ustar tyson tyson --TEST--
Accessing unserialized numbers.
--SKIPIF--
--FILE--
'x', 1234 => 33);
var_dump($data);
$x = "1";
$y = 1;
$z = "1234";
$w = 1234;
var_dump(isset($data->{$x}) ? $data->{$x} : "unset");
error_reporting(0);
$str = igbinary_serialize($data);
$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
var_dump(isset($unserialized->{$x}) ? $unserialized->{$x} : "unset str");
var_dump(isset($unserialized->{$y}) ? $unserialized->{$y} : "unset int");
var_dump(isset($unserialized->{$z}) ? $unserialized->{$z} : "unset str 1234");
var_dump(isset($unserialized->{$w}) ? $unserialized->{$w} : "unset int 1234");
var_dump(isset($unserialized->{-1}) ? $unserialized->{-1} : "unset int -1");
?>
--EXPECT--
object(stdClass)#1 (5) {
["0"]=>
int(1)
["1"]=>
int(2)
["2"]=>
int(3)
["-1"]=>
string(1) "x"
["1234"]=>
int(33)
}
int(2)
object(stdClass)#2 (5) {
["0"]=>
int(1)
["1"]=>
int(2)
["2"]=>
int(3)
["-1"]=>
string(1) "x"
["1234"]=>
int(33)
}
int(2)
int(2)
int(33)
int(33)
string(1) "x"
igbinary-2.0.5/tests/igbinary_063_php7.phpt 0000644 0001750 0001750 00000002344 13177372464 017646 0 ustar tyson tyson --TEST--
Accessing unserialized numbers.
--SKIPIF--
= 70200 || PHP_VERSION_ID < 70000) {
echo "Skip php 7.1 or 7.0 required";
}
?>
--FILE--
'x', 1234 => 33);
var_dump($data);
$x = "1";
$y = 1;
$z = "1234";
$w = 1234;
var_dump(isset($data->{$x}) ? $data->{$x} : "unset");
error_reporting(0);
$str = igbinary_serialize($data);
$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
var_dump(isset($unserialized->{$x}) ? $unserialized->{$x} : "unset str");
var_dump(isset($unserialized->{$y}) ? $unserialized->{$y} : "unset int");
var_dump(isset($unserialized->{$z}) ? $unserialized->{$z} : "unset str 1234");
var_dump(isset($unserialized->{$w}) ? $unserialized->{$w} : "unset int 1234");
var_dump(isset($unserialized->{-1}) ? $unserialized->{-1} : "unset int -1");
?>
--EXPECT--
object(stdClass)#1 (5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[-1]=>
string(1) "x"
[1234]=>
int(33)
}
string(5) "unset"
object(stdClass)#2 (5) {
["0"]=>
int(1)
["1"]=>
int(2)
["2"]=>
int(3)
["-1"]=>
string(1) "x"
["1234"]=>
int(33)
}
int(2)
int(2)
int(33)
int(33)
string(1) "x"
igbinary-2.0.5/tests/igbinary_063.phpt 0000644 0001750 0001750 00000002316 13177372464 016707 0 ustar tyson tyson --TEST--
Accessing unserialized numbers.
--SKIPIF--
= 70000) {
echo "Skip php 5.6 or lower required";
}
?>
--FILE--
'x', 1234 => 33);
var_dump($data);
$x = "1";
$y = 1;
$z = "1234";
$w = 1234;
var_dump(isset($data->{$x}) ? $data->{$x} : "unset");
error_reporting(0);
$str = igbinary_serialize($data);
$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
var_dump(isset($unserialized->{$x}) ? $unserialized->{$x} : "unset str");
var_dump(isset($unserialized->{$y}) ? $unserialized->{$y} : "unset int");
var_dump(isset($unserialized->{$z}) ? $unserialized->{$z} : "unset str 1234");
var_dump(isset($unserialized->{$w}) ? $unserialized->{$w} : "unset int 1234");
var_dump(isset($unserialized->{-1}) ? $unserialized->{-1} : "unset int -1");
?>
--EXPECTF--
object(stdClass)#%d (5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[-1]=>
string(1) "x"
[1234]=>
int(33)
}
string(5) "unset"
object(stdClass)#%d (5) {
["0"]=>
int(1)
["1"]=>
int(2)
["2"]=>
int(3)
["-1"]=>
string(1) "x"
["1234"]=>
int(33)
}
int(2)
int(2)
int(33)
int(33)
string(1) "x"
igbinary-2.0.5/tests/igbinary_064.phpt 0000644 0001750 0001750 00000004243 13177372464 016711 0 ustar tyson tyson --TEST--
Works when there are hash collisions in strings when serializing.
--SKIPIF--
--FILE--
x = $x;
}
}
class Ez {
public $FyEz = 'EzEz';
}
class G8 {
public $FyG8;
}
$data = array(new Fy('G8G8'), new Fy('EzG8'), new Ez(), new G8(), new Ez(), 'G8' => new G8(), 'F8Ez' => new G8(), array(new G8()));
var_dump($data);
echo "\n";
$str = igbinary_serialize($data);
echo bin2hex($str) . "\n";
$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
echo "\n";
var_export(serialize($data) === serialize($unserialized));
?>
--EXPECT--
array(8) {
[0]=>
object(Fy)#1 (2) {
["EzFy"]=>
int(2)
["x"]=>
string(4) "G8G8"
}
[1]=>
object(Fy)#2 (2) {
["EzFy"]=>
int(2)
["x"]=>
string(4) "EzG8"
}
[2]=>
object(Ez)#3 (1) {
["FyEz"]=>
string(4) "EzEz"
}
[3]=>
object(G8)#4 (1) {
["FyG8"]=>
NULL
}
[4]=>
object(Ez)#5 (1) {
["FyEz"]=>
string(4) "EzEz"
}
["G8"]=>
object(G8)#6 (1) {
["FyG8"]=>
NULL
}
["F8Ez"]=>
object(G8)#7 (1) {
["FyG8"]=>
NULL
}
[5]=>
array(1) {
[0]=>
object(G8)#8 (1) {
["FyG8"]=>
NULL
}
}
}
00000002140806001702467914021104457a4679060211017811044738473806011a0014020e0106020e021104457a473806021702457a140111044679457a1104457a457a06031702473814011104467947380006041a0514010e060e070e081a0814010e090011044638457a1a0814010e09000605140106001a0814010e0900
array(8) {
[0]=>
object(Fy)#9 (2) {
["EzFy"]=>
int(2)
["x"]=>
string(4) "G8G8"
}
[1]=>
object(Fy)#10 (2) {
["EzFy"]=>
int(2)
["x"]=>
string(4) "EzG8"
}
[2]=>
object(Ez)#11 (1) {
["FyEz"]=>
string(4) "EzEz"
}
[3]=>
object(G8)#12 (1) {
["FyG8"]=>
NULL
}
[4]=>
object(Ez)#13 (1) {
["FyEz"]=>
string(4) "EzEz"
}
["G8"]=>
object(G8)#14 (1) {
["FyG8"]=>
NULL
}
["F8Ez"]=>
object(G8)#15 (1) {
["FyG8"]=>
NULL
}
[5]=>
array(1) {
[0]=>
object(G8)#16 (1) {
["FyG8"]=>
NULL
}
}
}
true
igbinary-2.0.5/tests/igbinary_bug54662.phpt 0000644 0001750 0001750 00000001103 13177372464 017554 0 ustar tyson tyson --TEST--
Nested objects cause segfault, php bug #54662
--SKIPIF--
--FILE--
append(new Storage);
$ser = igbinary_serialize($collection);
$new_collection = igbinary_unserialize($ser);
var_dump($new_collection[0]->storage);
--EXPECT--
string(8) "a string"
igbinary-2.0.5/tests/igbinary_bug72134.phpt 0000644 0001750 0001750 00000000776 13177372464 017565 0 ustar tyson tyson --TEST--
igbinary_unserialize causes segfault on 3rd call for objects with dynamic property
--FILE--
i = 1;
$igb = igbinary_serialize($value);
for ($i=0; $i < 30; $i++)
{
// This used to segfault at the third attempt
echo igbinary_unserialize($igb)->bar . PHP_EOL;
}
--EXPECT--
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
igbinary-2.0.5/tests/igbinary_unserialize_v1_compatible.phpt 0000644 0001750 0001750 00000005266 13177372464 023545 0 ustar tyson tyson --TEST--
Unserialize backwards compatible with v1.
--SKIPIF--
--FILE--
'b:1;',
'type' => 'boolean',
'description' => 'bool true',
'data' => 'AAAAAQU=',
'version' => 1,
),
array(
'var' => 'b:0;',
'type' => 'boolean',
'description' => 'bool false',
'data' => 'AAAAAQQ=',
'version' => 1,
),
array(
'var' => 'd:1.2881887378882661554513333612703718245029449462890625;',
'type' => 'double',
'description' => 'double',
'data' => 'AAAAAQw/9Jxry0Tj0Q==',
'version' => 1,
),
array(
'var' => 'i:29913;',
'type' => 'integer',
'description' => 'int',
'data' => 'AAAAAQh02Q==',
'version' => 1,
),
array(
'var' => 'N;',
'type' => 'NULL',
'description' => 'null',
'data' => 'AAAAAQA=',
'version' => 1,
),
array(
'var' => 's:0:"";',
'type' => 'string',
'description' => 'string',
'data' => 'AAAAAQ0=',
'version' => 1,
),
array(
'var' => 's:13:"asdf' . "\0" . 'asdfasdf";',
'type' => 'string',
'description' => 'string',
'data' => 'AAAAARENYXNkZgBhc2RmYXNkZg==',
'version' => 1,
),
array(
'var' => 'a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;}',
'type' => 'array',
'description' => 'array',
'data' => 'AAAAARQEBgAGAQYBBgIGAgYDBgMGBA==',
'version' => 1,
),
array(
'var' => 'O:8:"stdClass":4:{s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;s:1:"d";i:4;}',
'var_e' => (object)array("a"=>1, "b"=>2, "c"=>3, "d"=>4),
'type' => 'object',
'description' => 'object',
'data' => 'AAAAAhcIc3RkQ2xhc3MUBBEBYQYBEQFiBgIRAWMGAxEBZAYE',
'version' => 1,
),
array(
'var' => 'a:2:{i:0;a:3:{i:0;s:1:"a";i:1;s:1:"b";i:2;s:1:"c";}i:1;R:2;}',
'type' => 'array',
'description' => 'reference',
'data' => 'AAAAARQCBgAUAwYAEQFhBgERAWIGAhEBYwYBAQE=',
'version' => 1,
),
);
$all_passed = true;
foreach ($data as $item) {
if (isset($item['var_e'])) {
$var = $item['var_e'];
} else {
$var = unserialize($item['var']);
}
$unserialized = igbinary_unserialize(base64_decode($item['data']));
ob_start();
var_dump($var);
$dump_expected = ob_get_clean();
ob_start();
var_dump($unserialized);
$dump_actual = ob_get_clean();
// replace all object ids to 0
$dump_expected = preg_replace('/#\d+/', '#0', $dump_expected);
$dump_actual = preg_replace('/#\d+/', '#0', $dump_actual);
if ($dump_expected !== $dump_actual) {
if ($item['description'] == 'reference') {
echo "reference deserialization works, but the result is not a reference.\n";
continue;
}
echo "Differing unserialized: {$item['description']}\n";
echo "Expected:\n", $dump_expected, "\n";
echo "Actual:\n", $dump_actual, "\n";
}
}
echo $all_passed ? 'OK' : 'ERROR', "\n";
--EXPECT--
reference deserialization works, but the result is not a reference.
OK
igbinary-2.0.5/config.m4 0000644 0001750 0001750 00000006223 13177372464 014164 0 ustar tyson tyson dnl config.m4 for extension igbinary
dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.
dnl If your extension references something external, use with:
dnl PHP_ARG_WITH(igbinary, for igbinary support,
dnl Make sure that the comment is aligned:
dnl [ --with-igbinary Include igbinary support])
dnl Otherwise use enable:
PHP_ARG_ENABLE(igbinary, whether to enable igbinary support,
[ --enable-igbinary Enable igbinary support])
if test "$PHP_IGBINARY" != "no"; then
AC_CHECK_HEADERS([stdbool.h],, AC_MSG_ERROR([stdbool.h not exists]))
AC_CHECK_HEADERS([stddef.h],, AC_MSG_ERROR([stddef.h not exists]))
AC_CHECK_HEADERS([stdint.h],, AC_MSG_ERROR([stdint.h not exists]))
AC_MSG_CHECKING(PHP version)
AC_TRY_COMPILE([
#include <$phpincludedir/main/php_version.h>
],[
#if PHP_MAJOR_VERSION > 5
#error PHP > 5
#endif
],[
subdir=src/php5
PHP_IGBINARY_SRC_FILES="$subdir/igbinary.c $subdir/hash_si.c $subdir/hash_si_ptr.c"
AC_MSG_RESULT([PHP 5])
],[
subdir=src/php7
PHP_IGBINARY_SRC_FILES="$subdir/igbinary.c $subdir/hash_si.c $subdir/hash_si_ptr.c"
AC_MSG_RESULT([PHP 7])
])
AC_MSG_CHECKING([for APC/APCU includes])
if test -f "$phpincludedir/ext/apcu/apc_serializer.h"; then
apc_inc_path="$phpincludedir"
AC_MSG_RESULT([APCU in $apc_inc_path])
AC_DEFINE(HAVE_APCU_SUPPORT,1,[Whether to enable apcu support])
elif test "$subdir" == src/php5 && test -f "$phpincludedir/ext/apc/apc_serializer.h"; then
apc_inc_path="$phpincludedir"
AC_MSG_RESULT([APC in $apc_inc_path])
AC_DEFINE(HAVE_APC_SUPPORT,1,[Whether to enable apc support])
elif test "$subdir" == src/php5 && test -f "${srcdir}/$subdir/apc_serializer.h"; then
AC_MSG_RESULT([apc_serializer.h bundled])
AC_DEFINE(HAVE_APC_SUPPORT,1,[Whether to enable apc support])
AC_DEFINE(USE_BUNDLED_APC,1,[Whether to use bundled apc includes])
else
AC_MSG_RESULT([not found])
fi
AC_CHECK_SIZEOF([long])
dnl GCC
AC_MSG_CHECKING(compiler type)
if test ! -z "`$CC --version | grep -i CLANG`"; then
AC_MSG_RESULT(clang)
if test -z "`echo $CFLAGS | grep -- -O0`"; then
PHP_IGBINARY_CFLAGS="$CFLAGS -Wall -O2"
fi
elif test "$GCC" = yes; then
AC_MSG_RESULT(gcc)
if test -z "`echo $CFLAGS | grep -- '-O[0123]'`"; then
PHP_IGBINARY_CFLAGS="$CFLAGS -O2 -Wall -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wcast-align -Wshadow -Wwrite-strings -Wswitch -finline-limit=10000 --param large-function-growth=10000 --param inline-unit-growth=10000"
fi
elif test "$ICC" = yes; then
AC_MSG_RESULT(icc)
if test -z "`echo $CFLAGS | grep -- -O0`"; then
PHP_IGBINARY_CFLAGS="$CFLAGS -no-prec-div -O3 -x0 -unroll2"
fi
else
AC_MSG_RESULT(other)
fi
PHP_ADD_MAKEFILE_FRAGMENT(Makefile.bench)
PHP_INSTALL_HEADERS([ext/igbinary], [igbinary.h $subdir/igbinary.h php_igbinary.h $subdir/php_igbinary.h])
PHP_NEW_EXTENSION(igbinary, $PHP_IGBINARY_SRC_FILES, $ext_shared,, $PHP_IGBINARY_CFLAGS)
PHP_ADD_EXTENSION_DEP(igbinary, session, true)
PHP_ADD_BUILD_DIR($abs_builddir/$subdir, 1)
PHP_SUBST(IGBINARY_SHARED_LIBADD)
fi
igbinary-2.0.5/config.w32 0000644 0001750 0001750 00000004102 13177372464 014251 0 ustar tyson tyson // $Id$
// vim:ft=javascript
ARG_ENABLE("igbinary", "whether to enable igbinary support", "no");
if (PHP_IGBINARY == "yes") {
var dll = get_define('PHPDLL');
var is_php5 = null != dll.match(/^php5/);
var is_php7 = !is_php5 && null != dll.match(/^php7/)
if (CHECK_HEADER_ADD_INCLUDE("apc_serializer.h", "CFLAGS_IGBINARY", "..\\pecl\\apcu;ext\\apcu")) {
AC_DEFINE('HAVE_APCU_SUPPORT', 1, "Whether to enable apcu support");
if (!CHECK_HEADER_ADD_INCLUDE("apc_serializer.h", "CFLAGS_IGBINARY", "ext\\apcu")) {
// Workaround to allow configuring and making apcu and igbinary at the same time.
// If they aren't available in ext/apcu, expect them in ../pecl/apcu
AC_DEFINE('HAVE_APCU_HEADERS_IN_PECL', 1, "Whether or not apcu headers exist only in pecl folder")
}
} else if (is_php5 && CHECK_HEADER_ADD_INCLUDE("apc_serializer.h", "CFLAGS_IGBINARY", "..\\pecl\\apc;ext\\apc")) {
// Don't try ext/apc unless this is a php 5 build.
// For some reason, the header files still exist for pecl.php.net 7.0 builds.
AC_DEFINE('HAVE_APC_SUPPORT', 1, 'Whether to enable apc support')
}
var old_conf_dir = configure_module_dirname;
var php_igbinary_src_files;
var subdir;
/* Copied from solr config.w32 */
/* XXX tricky job here, override configure_module_dirname, define the basic extension,
then set it back*/
if (is_php5) {
subdir = "src\\php5"
php_igbinary_src_files = "igbinary.c hash_si.c hash_si_ptr.c"
} else if (is_php7) {
subdir = "src\\php7";
php_igbinary_src_files = "igbinary.c hash_si.c hash_si_ptr.c"
} else {
ERROR("Cannot match any known PHP version with '" + dll + "'");
}
configure_module_dirname = configure_module_dirname + "\\" + subdir;
EXTENSION("igbinary", php_igbinary_src_files);
configure_module_dirname = old_conf_dir;
AC_DEFINE('HAVE_IGBINARY', 1, 'Have igbinary support', false);
ADD_EXTENSION_DEP('igbinary', 'session');
PHP_INSTALL_HEADERS('ext/igbinary', 'igbinary.h php_igbinary.h ' + subdir + '\\igbinary.h ' + subdir + '\\php_igbinary.h');
}
igbinary-2.0.5/igbinary.h 0000644 0001750 0001750 00000000447 13177372464 014434 0 ustar tyson tyson #ifndef PHPEXT_IGBINARY_BASE_IGBINARY_H
#define PHPEXT_IGBINARY_BASE_IGBINARY_H
#include "php_version.h"
#if PHP_MAJOR_VERSION == 5
#include "src/php5/igbinary.h"
#elif PHP_MAJOR_VERSION == 7
#include "src/php7/igbinary.h"
#else
#error "Unsupported php version for igbinary build"
#endif
#endif
igbinary-2.0.5/php_igbinary.h 0000644 0001750 0001750 00000001555 13177372464 015304 0 ustar tyson tyson #ifndef PHPEXT_IGBINARY_BASE_PHP_IGBINARY_H
#define PHPEXT_IGBINARY_BASE_PHP_IGBINARY_H
#include "php_version.h"
#if PHP_MAJOR_VERSION == 5
#include "ext/igbinary/src/php5/php_igbinary.h"
#elif PHP_MAJOR_VERSION == 7
#include "ext/igbinary/src/php7/php_igbinary.h"
#else
#error "Unsupported php version for igbinary build"
#endif
/**
* The below line is redundant and identical to php5 and php7's line
* (and just mentioning phpext_ in a comment is sufficient).
* This block is only here to make php-src/build/print_include.awk include this file,
* when igbinary is placed in php-src/ext/igbinary/ (instead of compiled separately with `phpize; ...`)
*/
#ifndef phpext_igbinary_ptr
extern zend_module_entry igbinary_module_entry;
#define phpext_igbinary_ptr &igbinary_module_entry
#endif
/** End line needed for putting igbinary in php-src/ext/igbinary to work */
#endif
igbinary-2.0.5/src/php5/hash.h 0000644 0001750 0001750 00000007264 13177372464 015222 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef HASH_H
#define HASH_H
#include
#ifdef PHP_WIN32
# include "ig_win32.h"
#else
# include /* defines uint32_t etc */
#endif
#include
/** Key/value pair of hash_si.
* @author Oleg Grenrus
* @see hash_si
*/
struct hash_si_pair
{
char *key; /**< Pointer to key. */
size_t key_len; /**< Key length. */
uint32_t key_hash; /**< Key hash. */
uint32_t value; /**< Value. */
};
enum hash_si_code {
hash_si_code_inserted,
hash_si_code_exists,
hash_si_code_exception
};
struct hash_si_result
{
enum hash_si_code code;
uint32_t value;
};
/** Hash-array.
* Like c++ map.
* Current implementation uses linear probing.
* @author Oleg Grenrus
*/
struct hash_si {
size_t size; /**< Allocated size of array. */
size_t used; /**< Used size of array. */
struct hash_si_pair *data; /**< Pointer to array or pairs of data. */
};
/** Inits hash_si structure.
* @param h pointer to hash_si struct.
* @param size initial size of the hash array.
* @return 0 on success, 1 else.
*/
int hash_si_init (struct hash_si *h, size_t size);
/** Frees hash_si structure.
* Doesn't call free(h).
* @param h pointer to hash_si struct.
*/
void hash_si_deinit (struct hash_si *h);
/** Inserts value into hash_si.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param value Value.
* @return 0 on success, 1 or 2 else.
*/
/*
int hash_si_insert (struct hash_si *h, const char *key, size_t key_len, uint32_t value);
*/
/** Finds value from hash_si.
* Value returned thru value param.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Found value.
* @return 0 if found, 1 if not.
*/
/*
int hash_si_find (struct hash_si *h, const char *key, size_t key_len, uint32_t * value);
*/
/** Finds value from hash_si.
* Value returned thru value param.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Found value.
* @return 0 if found, 1 if not.
*/
struct hash_si_result hash_si_find_or_insert(struct hash_si *h, const char *key, size_t key_len, uint32_t value);
/** Remove value from hash_si.
* Removed value is available thru value param.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Removed value.
* @return 0 ivalue removed, 1 if not existed.
*/
/*
int hash_si_remove (struct hash_si *h, const char *key, size_t key_len, uint32_t * value);
*/
/** Travarses hash_si.
* Calls traverse_function on every item. Traverse function should not modify hash
* @param h Pointer to hash_si struct.
* @param traverse_function Function to call on every item of hash_si.
*/
/*
void hash_si_traverse (struct hash_si *h, int (*traverse_function) (const char *key, size_t key_len, uint32_t value));
*/
/** Returns size of hash_si.
* @param h Pointer to hash_si struct.
* @return Size of hash_si.
*/
size_t hash_si_size (struct hash_si *h);
/** Returns capacity of hash_si.
* @param h Pointer to hash_si struct.
* @return Capacity of hash_si.
*/
size_t hash_si_capacity (struct hash_si *h);
#endif /* HASH_H */
igbinary-2.0.5/src/php5/hash_ptr.h 0000644 0001750 0001750 00000006531 13177372464 016103 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
| This defines hash_si_ptr. |
| It is like hash_si, but the key is always a non-zero zend_uintptr_t |
+----------------------------------------------------------------------+
*/
#ifndef HASH_PTR_H
#define HASH_PTR_H
#include
#ifdef PHP_WIN32
# include "ig_win32.h"
#else
# include /* defines uint32_t etc */
#endif
#include
#include "zend_types.h"
// NULL converted to an integer, on sane platforms.
#define HASH_PTR_KEY_INVALID 0
/** Key/value pair of hash_si_ptr.
* @author Oleg Grenrus
* @see hash_si_ptr
*/
struct hash_si_ptr_pair
{
zend_uintptr_t key; /**< The key: The address of a pointer, casted to an int (won't be dereferenced). */
uint32_t value; /**< Value. */
};
/** Hash-array.
* Like c++ std::unordered_map, but does not allow HASH_PTR_KEY_INVALID as a key.
* Current implementation uses linear probing.
* @author Oleg Grenrus
*/
struct hash_si_ptr {
size_t size; /**< Allocated size of array. */
size_t used; /**< Used size of array. */
struct hash_si_ptr_pair *data; /**< Pointer to array or pairs of data. */
};
/** Inits hash_si_ptr structure.
* @param h pointer to hash_si_ptr struct.
* @param size initial size of the hash array.
* @return 0 on success, 1 else.
*/
int hash_si_ptr_init(struct hash_si_ptr *h, size_t size);
/** Frees hash_si_ptr structure.
* Doesn't call free(h).
* @param h pointer to hash_si_ptr struct.
*/
void hash_si_ptr_deinit(struct hash_si_ptr *h);
/** Inserts value into hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param value Value.
* @return 0 on success, 1 or 2 else.
*/
/*
int hash_si_ptr_insert (struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value);
*/
/** Finds value from hash_si_ptr.
* Value returned thru value param.
* @param h Pointer to hash_si_ptr struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Found value.
* @return 0 if found, 1 if not.
*/
/*
int hash_si_ptr_find (struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t * value);
*/
/** Returns size of hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
* @return Size of hash_si_ptr.
*/
size_t hash_si_ptr_size (struct hash_si_ptr *h);
/**
* If the key does not exist, add a mapping from key to value and returns SIZE_MAX
* If the key does exist, return the corresponding value
* @param h Pointer to hash_si_ptr struct.
* @param key key to look up or add
* @param value value to insert if it doesn't already exist
*
* @return SIZE_MAX or old, unmodified key
*/
size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value);
/** Returns capacity of hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
* @return Capacity of hash_si_ptr.
*/
size_t hash_si_ptr_capacity (struct hash_si_ptr *h);
#endif /* HASH_PTR_H */
igbinary-2.0.5/src/php5/hash_si.c 0000644 0001750 0001750 00000012331 13177372464 015677 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifdef PHP_WIN32
# include "ig_win32.h"
#endif
#include
#include
#include
#include
#include "hash.h"
#include "zend.h"
#include "igbinary_macros.h"
/* {{{ nextpow2 */
/** Next power of 2.
* @param n Integer.
* @return next to n power of 2 .
*/
inline static uint32_t nextpow2(uint32_t n) {
uint32_t m = 1;
while (m < n) {
m = m << 1;
}
return m;
}
/* }}} */
/* {{{ hash_si_init */
int hash_si_init(struct hash_si *h, size_t size) {
size = nextpow2(size);
h->size = size;
h->used = 0;
h->data = (struct hash_si_pair *) emalloc(sizeof(struct hash_si_pair) * size);
if (h->data == NULL) {
return 1;
}
memset(h->data, 0, sizeof(struct hash_si_pair) * size);
return 0;
}
/* }}} */
/* {{{ hash_si_deinit */
void hash_si_deinit(struct hash_si *h) {
size_t i;
for (i = 0; i < h->size; i++) {
if (h->data[i].key != NULL) {
efree(h->data[i].key);
}
}
efree(h->data);
h->size = 0;
h->used = 0;
}
/* }}} */
/* {{{ _hash_si_find */
/** Returns index of key, or where it should be.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param key_hash precomputed key hash of bytes of key (=zend_inline_hash_func(key, key_len))
* @return index.
*/
inline static size_t _hash_si_find(const struct hash_si *h, const char *key, const size_t key_len, const uint32_t key_hash) {
uint32_t hv;
size_t size;
size_t mask;
assert(h != NULL);
size = h->size;
mask = size - 1;
hv = key_hash & mask;
while (size > 0 &&
h->data[hv].key != NULL &&
(h->data[hv].key_hash != key_hash || h->data[hv].key_len != key_len || UNEXPECTED(memcmp(h->data[hv].key, key, key_len) != 0))) {
/* linear prob */
hv = (hv + 1) & mask;
size--;
}
return hv;
}
/* }}} */
/* {{{ hash_si_rehash */
/** Rehash/resize hash_si.
* @param h Pointer to hash_si struct.
*/
inline static void hash_si_rehash(struct hash_si *h) {
size_t i;
struct hash_si newh;
assert(h != NULL);
hash_si_init(&newh, h->size * 2);
for (i = 0; i < h->size; i++) {
const struct hash_si_pair *old_pair = &(h->data[i]);
if (old_pair->key != NULL) {
uint32_t hv = _hash_si_find(&newh, old_pair->key, old_pair->key_len, old_pair->key_hash);
newh.data[hv] = *old_pair;
}
}
efree(h->data);
h->data = newh.data;
h->size *= 2;
}
/* }}} */
/* {{{ hash_si_insert */
/*
int hash_si_insert(struct hash_si *h, const char *key, size_t key_len, uint32_t value) {
uint32_t hv;
if (h->size / 4 * 3 < h->used + 1) {
hash_si_rehash(h);
}
hv = _hash_si_find(h, key, key_len);
if (h->data[hv].key == NULL) {
h->data[hv].key = (char *) emalloc(key_len + 1);
if (h->data[hv].key == NULL) {
return 1;
}
memcpy(h->data[hv].key, key, key_len);
h->data[hv].key[key_len] = '\0';
h->data[hv].key_len = key_len;
h->used++;
} else {
return 2;
}
h->data[hv].value = value;
return 0;
}
*/
/* }}} */
/* {{{ hash_si_find */
/*
int hash_si_find(struct hash_si *h, const char *key, size_t key_len, uint32_t *value) {
uint32_t hv;
assert(h != NULL);
hv = _hash_si_find(h, key, key_len);
if (h->data[hv].key == NULL) {
return 1;
} else {
*value = h->data[hv].value;
return 0;
}
}
*/
/* }}} */
/* {{{ hash_si_find_or_insert */
struct hash_si_result hash_si_find_or_insert(struct hash_si *h, const char *key, size_t key_len, uint32_t value) {
uint32_t hv;
uint32_t key_hash;
struct hash_si_result result;
struct hash_si_pair *pair;
assert(h != NULL);
key_hash = zend_inline_hash_func(key, key_len);
hv = _hash_si_find(h, key, key_len, key_hash);
pair = &h->data[hv];
if (pair->key == NULL) {
char* copy = emalloc(key_len);
if (copy == NULL) {
result.code = hash_si_code_exception;
return result;
}
memcpy(copy, key, key_len);
pair->key = copy;
pair->key_len = key_len;
pair->key_hash = key_hash;
pair->value = value;
h->used++;
if (h->size / 4 * 3 < h->used) {
hash_si_rehash(h);
}
result.code = hash_si_code_inserted;
return result;
} else {
result.code = hash_si_code_exists;
result.value = h->data[hv].value;
return result;
}
}
/* }}} */
/* {{{ hash_si_traverse */
/*
void hash_si_traverse(struct hash_si *h, int (*traverse_function) (const char *key, size_t key_len, uint32_t value)) {
size_t i;
assert(h != NULL && traverse_function != NULL);
for (i = 0; i < h->size; i++) {
if (h->data[i].key != NULL && traverse_function(h->data[i].key, h->data[i].key_len, h->data[i].value) != 1) {
return;
}
}
}
*/
/* }}} */
/* {{{ hash_si_size */
size_t hash_si_size(struct hash_si *h) {
assert(h != NULL);
return h->used;
}
/* }}} */
/* {{{ hash_si_capacity */
size_t hash_si_capacity(struct hash_si *h) {
assert(h != NULL);
return h->size;
}
/* }}} */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
igbinary-2.0.5/src/php5/hash_si_ptr.c 0000644 0001750 0001750 00000012017 13177372464 016565 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
| This is a specialized hash map mapping uintprt_t to int32_t |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| Modified by Tyson Andre for fixed size, removing unused functions |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
# include
#endif
#include
#include
#include
#include
#include "hash_ptr.h"
#include "zend.h"
/* Function similar to zend_inline_hash_func. This is not identical. */
inline static uint32_t inline_hash_of_address(zend_uintptr_t ptr) {
register uint32_t hash = 5381;
/* Note: Hash the least significant bytes first - Those need to influence the final result as much as possible. */
hash = ((hash << 5) + hash) + (ptr & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 8) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 16) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 24) & 0xff);
#if UINTPTR_MAX > UINT32_MAX
hash = ((hash << 5) + hash) + ((ptr >> 32) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 40) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 48) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 56) & 0xff);
#endif
return hash;
}
/* {{{ nextpow2 */
/** Next power of 2.
* @param n Integer.
* @return next to n power of 2 .
*/
inline static uint32_t nextpow2(uint32_t n) {
uint32_t m = 1;
while (m < n) {
m = m << 1;
}
return m;
}
/* }}} */
/* {{{ hash_si_ptr_init */
int hash_si_ptr_init(struct hash_si_ptr *h, size_t size) {
size = nextpow2(size);
h->size = size;
h->used = 0;
h->data = (struct hash_si_ptr_pair*) malloc(sizeof(struct hash_si_ptr_pair) * size);
if (h->data == NULL) {
return 1;
}
memset(h->data, 0, sizeof(struct hash_si_ptr_pair) * size); /* Set everything to 0. sets keys to HASH_PTR_KEY_INVALID. */
return 0;
}
/* }}} */
/* {{{ hash_si_ptr_deinit */
void hash_si_ptr_deinit(struct hash_si_ptr *h) {
size_t i;
free(h->data);
h->data = NULL;
h->size = 0;
h->used = 0;
}
/* }}} */
/* {{{ _hash_si_ptr_find */
/** Returns index of key, or where it should be.
* @param h Pointer to hash_si_ptr struct.
* @param key Pointer to key.
* @return index.
*/
inline static size_t _hash_si_ptr_find(struct hash_si_ptr *h, const zend_uintptr_t key) {
uint32_t hv;
size_t size;
assert(h != NULL);
size = h->size;
hv = inline_hash_of_address(key) & (h->size-1);
while (size > 0 &&
h->data[hv].key != HASH_PTR_KEY_INVALID &&
h->data[hv].key != key) {
/* linear prob */
hv = (hv + 1) & (h->size-1);
size--;
}
return hv;
}
/* }}} */
/* }}} */
/* {{{ hash_si_ptr_rehash */
/** Rehash/resize hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
*/
inline static void hash_si_ptr_rehash(struct hash_si_ptr *h) {
uint32_t hv;
size_t i;
struct hash_si_ptr newh;
assert(h != NULL);
hash_si_ptr_init(&newh, h->size * 2);
for (i = 0; i < h->size; i++) {
if (h->data[i].key != HASH_PTR_KEY_INVALID) {
hv = _hash_si_ptr_find(&newh, h->data[i].key);
newh.data[hv].key = h->data[i].key;
newh.data[hv].value = h->data[i].value;
}
}
free(h->data);
h->data = newh.data;
h->size *= 2;
}
/* }}} */
/* {{{ hash_si_ptr_insert */
/*
int hash_si_ptr_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value) {
uint32_t hv;
if (h->size / 4 * 3 < h->used + 1) {
hash_si_ptr_rehash(h);
}
hv = _hash_si_ptr_find(h, key);
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
h->data[hv].key = key;
h->used++;
} else {
return 2;
}
h->data[hv].value = value;
return 0;
}
*/
/* }}} */
/* {{{ hash_si_ptr_find */
/*
int hash_si_ptr_find(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t *value) {
uint32_t hv;
assert(h != NULL);
hv = _hash_si_ptr_find(h, key);
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
return 1;
} else {
*value = h->data[hv].value;
return 0;
}
}
*/
/* }}} */
/* {{{ hash_si_ptr_find_or_insert */
size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value) {
uint32_t hv;
hv = _hash_si_ptr_find(h, key);
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
h->data[hv].key = key;
h->data[hv].value = value;
h->used++;
/* The size increased, so check if we need to expand the map */
if (h->size / 4 * 3 < h->used) {
hash_si_ptr_rehash(h);
}
return SIZE_MAX;
} else {
return h->data[hv].value;
}
}
/* }}} */
/* {{{ hash_si_ptr_size */
size_t hash_si_ptr_size(struct hash_si_ptr *h) {
assert(h != NULL);
return h->used;
}
/* }}} */
/* {{{ hash_si_ptr_capacity */
size_t hash_si_ptr_capacity(struct hash_si_ptr *h) {
assert(h != NULL);
return h->size;
}
/* }}} */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
igbinary-2.0.5/src/php5/igbinary.c 0000644 0001750 0001750 00000220773 13177372464 016100 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef PHP_WIN32
# include "ig_win32.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "zend_dynamic_array.h"
#include "zend_alloc.h"
#include "ext/standard/info.h"
#include "ext/standard/php_var.h"
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
# include "ext/session/php_session.h"
#endif /* HAVE_PHP_SESSION */
#include "ext/standard/php_incomplete_class.h"
#if defined(HAVE_APCU_SUPPORT)
# if defined(HAVE_APCU_HEADERS_IN_PECL)
# include "../pecl/apcu/apc_serializer.h"
# else
# include "ext/apcu/apc_serializer.h"
# endif
#elif defined(HAVE_APC_SUPPORT)
# if USE_BUNDLED_APC
# include "apc_serializer.h"
# else
# include "ext/apc/apc_serializer.h"
# endif
#endif /* HAVE_APCU_SUPPORT || HAVE_APC_SUPPORT */
#include "php_igbinary.h"
#include "igbinary.h"
#include
#include
#ifndef PHP_WIN32
# include
# include
# include
#endif
#include
#include "hash.h"
#include "hash_ptr.h"
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
/** Session serializer function prototypes. */
PS_SERIALIZER_FUNCS(igbinary);
#endif /* HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) */
#if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT)
/** Apc serializer function prototypes */
static int APC_SERIALIZER_NAME(igbinary) (APC_SERIALIZER_ARGS);
static int APC_UNSERIALIZER_NAME(igbinary) (APC_UNSERIALIZER_ARGS);
#endif
/* {{{ Types */
enum igbinary_type {
/* 00 */ igbinary_type_null, /**< Null. */
/* 01 */ igbinary_type_ref8, /**< Array reference. */
/* 02 */ igbinary_type_ref16, /**< Array reference. */
/* 03 */ igbinary_type_ref32, /**< Array reference. */
/* 04 */ igbinary_type_bool_false, /**< Boolean true. */
/* 05 */ igbinary_type_bool_true, /**< Boolean false. */
/* 06 */ igbinary_type_long8p, /**< Long 8bit positive. */
/* 07 */ igbinary_type_long8n, /**< Long 8bit negative. */
/* 08 */ igbinary_type_long16p, /**< Long 16bit positive. */
/* 09 */ igbinary_type_long16n, /**< Long 16bit negative. */
/* 0a */ igbinary_type_long32p, /**< Long 32bit positive. */
/* 0b */ igbinary_type_long32n, /**< Long 32bit negative. */
/* 0c */ igbinary_type_double, /**< Double. */
/* 0d */ igbinary_type_string_empty, /**< Empty string. */
/* 0e */ igbinary_type_string_id8, /**< String id. */
/* 0f */ igbinary_type_string_id16, /**< String id. */
/* 10 */ igbinary_type_string_id32, /**< String id. */
/* 11 */ igbinary_type_string8, /**< String. */
/* 12 */ igbinary_type_string16, /**< String. */
/* 13 */ igbinary_type_string32, /**< String. */
/* 14 */ igbinary_type_array8, /**< Array. */
/* 15 */ igbinary_type_array16, /**< Array. */
/* 16 */ igbinary_type_array32, /**< Array. */
/* 17 */ igbinary_type_object8, /**< Object. */
/* 18 */ igbinary_type_object16, /**< Object. */
/* 19 */ igbinary_type_object32, /**< Object. */
/* 1a */ igbinary_type_object_id8, /**< Object string id. */
/* 1b */ igbinary_type_object_id16, /**< Object string id. */
/* 1c */ igbinary_type_object_id32, /**< Object string id. */
/* 1d */ igbinary_type_object_ser8, /**< Object serialized data. */
/* 1e */ igbinary_type_object_ser16, /**< Object serialized data. */
/* 1f */ igbinary_type_object_ser32, /**< Object serialized data. */
/* 20 */ igbinary_type_long64p, /**< Long 64bit positive. */
/* 21 */ igbinary_type_long64n, /**< Long 64bit negative. */
/* 22 */ igbinary_type_objref8, /**< Object reference. */
/* 23 */ igbinary_type_objref16, /**< Object reference. */
/* 24 */ igbinary_type_objref32, /**< Object reference. */
/* 25 */ igbinary_type_ref, /**< Simple reference */
};
/** Serializer data.
* @author Oleg Grenrus
*/
struct igbinary_serialize_data {
uint8_t *buffer; /**< Buffer. */
size_t buffer_size; /**< Buffer size. */
size_t buffer_capacity; /**< Buffer capacity. */
bool scalar; /**< Serializing scalar. */
bool compact_strings; /**< Check for duplicate strings. */
struct hash_si strings; /**< Hash of already serialized strings. */
struct hash_si_ptr objects; /**< Hash of already serialized objects. */
int string_count; /**< Serialized string count, used for back referencing */
int error; /**< Error number. Not used. */
struct igbinary_memory_manager mm; /**< Memory management functions. */
};
/** String/len pair for the igbinary_unserializer_data.
* @author Oleg Grenrus
* @see igbinary_unserialize_data.
*/
struct igbinary_unserialize_string_pair {
char *data; /**< Data. */
size_t len; /**< Data length. */
};
/** Unserializer data.
* @author Oleg Grenrus
*/
struct igbinary_unserialize_data {
uint8_t *buffer; /**< Buffer. */
size_t buffer_size; /**< Buffer size. */
size_t buffer_offset; /**< Current read offset. */
struct igbinary_unserialize_string_pair *strings; /**< Unserialized strings. */
size_t strings_count; /**< Unserialized string count. */
size_t strings_capacity; /**< Unserialized string array capacity. */
void **references; /**< Unserialized Arrays/Objects. */
size_t references_count; /**< Unserialized array/objects count. */
size_t references_capacity; /**< Unserialized array/object array capacity. */
int error; /**< Error number. Not used. */
smart_str string0_buf; /**< Temporary buffer for strings */
};
/* }}} */
/* {{{ Memory allocator wrapper prototypes */
static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context);
static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context);
static inline void igbinary_mm_wrapper_free(void *ptr, void *context);
/* }}} */
/* {{{ Serializing functions prototypes */
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager TSRMLS_DC);
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer TSRMLS_DC);
inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd TSRMLS_DC);
inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i TSRMLS_DC);
inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i TSRMLS_DC);
inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i TSRMLS_DC);
inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i TSRMLS_DC);
inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd TSRMLS_DC);
inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b TSRMLS_DC);
inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, long l TSRMLS_DC);
inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d TSRMLS_DC);
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, char *s, size_t len TSRMLS_DC);
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len TSRMLS_DC);
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class TSRMLS_DC);
inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object TSRMLS_DC);
inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *ht, zend_class_entry *ce, bool incomplete_class TSRMLS_DC);
inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, const char *name, size_t name_len TSRMLS_DC);
inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC);
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC);
/* }}} */
/* {{{ Unserializing functions prototypes */
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd TSRMLS_DC);
inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, long *ret TSRMLS_DC);
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret TSRMLS_DC);
inline static int igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC);
inline static int igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC);
inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, int object TSRMLS_DC);
inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC);
inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, zend_class_entry *ce TSRMLS_DC);
inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC);
static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval **z TSRMLS_DC);
/* }}} */
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_serialize, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ igbinary_functions[] */
/** Exported php functions. */
zend_function_entry igbinary_functions[] = {
PHP_FE(igbinary_serialize, arginfo_igbinary_serialize)
PHP_FE(igbinary_unserialize, arginfo_igbinary_unserialize)
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ igbinary dependencies */
#if ZEND_MODULE_API_NO >= 20050922
static const zend_module_dep igbinary_module_deps[] = {
ZEND_MOD_REQUIRED("standard")
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
ZEND_MOD_REQUIRED("session")
#endif
#if defined(HAVE_APCU_SUPPORT)
ZEND_MOD_OPTIONAL("apcu")
#elif defined(HAVE_APC_SUPPORT)
ZEND_MOD_OPTIONAL("apc")
#endif
{NULL, NULL, NULL}
};
#endif
/* }}} */
/* {{{ igbinary_module_entry */
zend_module_entry igbinary_module_entry = {
#if ZEND_MODULE_API_NO >= 20050922
STANDARD_MODULE_HEADER_EX, NULL,
igbinary_module_deps,
#elif ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"igbinary",
igbinary_functions,
PHP_MINIT(igbinary),
PHP_MSHUTDOWN(igbinary),
NULL,
NULL,
PHP_MINFO(igbinary),
#if ZEND_MODULE_API_NO >= 20010901
PHP_IGBINARY_VERSION, /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
/* }}} */
ZEND_DECLARE_MODULE_GLOBALS(igbinary)
/* {{{ ZEND_GET_MODULE */
#ifdef COMPILE_DL_IGBINARY
ZEND_GET_MODULE(igbinary)
#endif
/* }}} */
/* {{{ INI entries */
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("igbinary.compact_strings", "1", PHP_INI_ALL, OnUpdateBool, compact_strings, zend_igbinary_globals, igbinary_globals)
PHP_INI_END()
/* }}} */
/* {{{ php_igbinary_init_globals */
static void php_igbinary_init_globals(zend_igbinary_globals *igbinary_globals) {
igbinary_globals->compact_strings = 1;
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(igbinary) {
(void) type;
(void) module_number;
ZEND_INIT_MODULE_GLOBALS(igbinary, php_igbinary_init_globals, NULL);
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
php_session_register_serializer("igbinary",
PS_SERIALIZER_ENCODE_NAME(igbinary),
PS_SERIALIZER_DECODE_NAME(igbinary));
#endif
#if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT)
apc_register_serializer("igbinary",
APC_SERIALIZER_NAME(igbinary),
APC_UNSERIALIZER_NAME(igbinary),
NULL TSRMLS_CC);
#endif
REGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(igbinary) {
(void) type;
(void) module_number;
#ifdef ZTS
ts_free_id(igbinary_globals_id);
#endif
/*
* unregister serializer?
*/
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(igbinary) {
(void) zend_module;
php_info_print_table_start();
php_info_print_table_row(2, "igbinary support", "enabled");
php_info_print_table_row(2, "igbinary version", PHP_IGBINARY_VERSION);
#if defined(HAVE_APCU_SUPPORT)
php_info_print_table_row(2, "igbinary APCU serializer ABI", APC_SERIALIZER_ABI);
#elif defined(HAVE_APC_SUPPORT)
php_info_print_table_row(2, "igbinary APC serializer ABI", APC_SERIALIZER_ABI);
#else
php_info_print_table_row(2, "igbinary APC serializer ABI", "no");
#endif
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
php_info_print_table_row(2, "igbinary session support", "yes");
#else
php_info_print_table_row(2, "igbinary session support", "no");
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ Memory allocator wrappers */
static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context)
{
return emalloc(size);
}
static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context)
{
return erealloc(ptr, size);
}
static inline void igbinary_mm_wrapper_free(void *ptr, void *context)
{
efree(ptr);
}
/* }}} */
/* {{{ int igbinary_serialize(uint8_t**, size_t*, zval*) */
IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z TSRMLS_DC) {
return igbinary_serialize_ex(ret, ret_len, z, NULL TSRMLS_CC);
}
/* }}} */
/* {{{ int igbinary_serialize_ex(uint8_t**, size_t*, zval*, igbinary_memory_manager*) */
IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager TSRMLS_DC) {
struct igbinary_serialize_data igsd;
uint8_t *tmpbuf;
if (igbinary_serialize_data_init(&igsd, Z_TYPE_P(z) != IS_OBJECT && Z_TYPE_P(z) != IS_ARRAY, memory_manager TSRMLS_CC)) {
zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
return 1;
}
if (igbinary_serialize_header(&igsd TSRMLS_CC) != 0) {
zend_error(E_WARNING, "igbinary_serialize: cannot write header");
igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
return 1;
}
if (igbinary_serialize_zval(&igsd, z TSRMLS_CC) != 0) {
igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
return 1;
}
/* Explicit nul termination */
if (igbinary_serialize8(&igsd, 0 TSRMLS_CC) != 0) {
igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
return 1;
}
/* shrink buffer to the real length, ignore errors */
tmpbuf = (uint8_t *) igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context);
if (tmpbuf != NULL) {
igsd.buffer = tmpbuf;
}
/* Set return values */
*ret_len = igsd.buffer_size - 1;
*ret = igsd.buffer;
igbinary_serialize_data_deinit(&igsd, 0 TSRMLS_CC);
return 0;
}
/* }}} */
/* {{{ int igbinary_unserialize(const uint8_t *, size_t, zval **) */
IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval **z TSRMLS_DC) {
struct igbinary_unserialize_data igsd;
igbinary_unserialize_data_init(&igsd TSRMLS_CC);
igsd.buffer = (uint8_t *) buf;
igsd.buffer_size = buf_len;
if (igbinary_unserialize_header(&igsd TSRMLS_CC)) {
igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
return 1;
}
if (igbinary_unserialize_zval(&igsd, z TSRMLS_CC)) {
igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
return 1;
}
igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
return 0;
}
/* }}} */
/* {{{ proto string igbinary_unserialize(mixed value) */
PHP_FUNCTION(igbinary_unserialize) {
char *string;
int string_len;
(void) return_value_ptr;
(void) this_ptr;
(void) return_value_used;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
RETURN_NULL();
}
if (string_len <= 0) {
RETURN_FALSE;
}
if (igbinary_unserialize((uint8_t *) string, string_len, &return_value TSRMLS_CC) != 0) {
RETURN_NULL();
}
}
/* }}} */
/* {{{ proto mixed igbinary_serialize(string value) */
PHP_FUNCTION(igbinary_serialize) {
zval *z;
uint8_t *string;
size_t string_len;
(void) return_value_ptr;
(void) this_ptr;
(void) return_value_used;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &z) == FAILURE) {
RETURN_NULL();
}
if (igbinary_serialize(&string, &string_len, z TSRMLS_CC) != 0) {
RETURN_NULL();
}
RETVAL_STRINGL((char *)string, string_len, 0);
}
/* }}} */
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
/* {{{ Serializer encode function */
PS_SERIALIZER_ENCODE_FUNC(igbinary)
{
struct igbinary_serialize_data igsd;
uint8_t *tmpbuf;
zval *session_vars = PS(http_session_vars);
HashTable *h = HASH_OF(session_vars);
long num_elements = h ? zend_hash_num_elements(h) : 0;
if (num_elements == 0) {
// Return the empty string for the empty array.
smart_str buf = {0};
smart_str_0(&buf);
if (newlen) {
*newlen = 0;
}
*newstr = buf.c;
return SUCCESS;
}
if (igbinary_serialize_data_init(&igsd, false, NULL TSRMLS_CC)) {
zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
return FAILURE;
}
if (igbinary_serialize_header(&igsd TSRMLS_CC) != 0) {
zend_error(E_WARNING, "igbinary_serialize: cannot write header");
igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
return FAILURE;
}
if (igbinary_serialize_array(&igsd, session_vars, false, false TSRMLS_CC) != 0) {
igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
return FAILURE;
}
if (igbinary_serialize8(&igsd, 0 TSRMLS_CC) != 0) {
igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
return FAILURE;
}
/* shrink buffer to the real length, ignore errors */
tmpbuf = (uint8_t *)igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context);
if (tmpbuf != NULL) {
igsd.buffer = tmpbuf;
}
*newstr = (char *)igsd.buffer;
if (newlen) {
*newlen = igsd.buffer_size - 1;
}
igbinary_serialize_data_deinit(&igsd, 0 TSRMLS_CC);
return SUCCESS;
}
/* }}} */
/* {{{ Serializer decode function */
PS_SERIALIZER_DECODE_FUNC(igbinary) {
HashPosition tmp_hash_pos;
HashTable *tmp_hash;
char *key_str;
ulong key_long;
int tmp_int;
uint key_len;
zval *z;
zval **d;
struct igbinary_unserialize_data igsd;
if (!val || vallen==0)
return SUCCESS;
if (igbinary_unserialize_data_init(&igsd TSRMLS_CC) != 0) {
return FAILURE;
}
igsd.buffer = (uint8_t *)val;
igsd.buffer_size = vallen;
if (igbinary_unserialize_header(&igsd TSRMLS_CC)) {
igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
return FAILURE;
}
ALLOC_INIT_ZVAL(z);
if (igbinary_unserialize_zval(&igsd, &z TSRMLS_CC)) {
igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
zval_dtor(z);
FREE_ZVAL(z);
return FAILURE;
}
igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
tmp_hash = HASH_OF(z);
zend_hash_internal_pointer_reset_ex(tmp_hash, &tmp_hash_pos);
while (zend_hash_get_current_data_ex(tmp_hash, (void *) &d, &tmp_hash_pos) == SUCCESS) {
tmp_int = zend_hash_get_current_key_ex(tmp_hash, &key_str, &key_len, &key_long, 0, &tmp_hash_pos);
switch (tmp_int) {
case HASH_KEY_IS_LONG:
/* ??? */
break;
case HASH_KEY_IS_STRING:
php_set_session_var(key_str, key_len-1, *d, NULL TSRMLS_CC);
php_add_session_var(key_str, key_len-1 TSRMLS_CC);
break;
}
zend_hash_move_forward_ex(tmp_hash, &tmp_hash_pos);
}
zval_dtor(z);
FREE_ZVAL(z);
return SUCCESS;
}
/* }}} */
#endif /* HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) */
#if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT)
/* {{{ apc_serialize function */
static int APC_SERIALIZER_NAME(igbinary) ( APC_SERIALIZER_ARGS ) {
(void)config;
if (igbinary_serialize(buf, buf_len, (zval *)value TSRMLS_CC) == 0) {
/* flipped semantics */
return 1;
}
return 0;
}
/* }}} */
/* {{{ apc_unserialize function */
static int APC_UNSERIALIZER_NAME(igbinary) ( APC_UNSERIALIZER_ARGS ) {
(void)config;
if (igbinary_unserialize(buf, buf_len, value TSRMLS_CC) == 0) {
/* flipped semantics */
return 1;
}
zval_dtor(*value);
(*value)->type = IS_NULL;
return 0;
}
/* }}} */
#endif
/* {{{ igbinary_serialize_data_init */
/** Inits igbinary_serialize_data. */
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager TSRMLS_DC) {
int r = 0;
if (memory_manager == NULL) {
igsd->mm.alloc = igbinary_mm_wrapper_malloc;
igsd->mm.realloc = igbinary_mm_wrapper_realloc;
igsd->mm.free = igbinary_mm_wrapper_free;
igsd->mm.context = NULL;
} else {
igsd->mm = *memory_manager;
}
igsd->buffer = NULL;
igsd->buffer_size = 0;
igsd->buffer_capacity = 32;
igsd->string_count = 0;
igsd->error = 0;
igsd->buffer = (uint8_t *) igsd->mm.alloc(igsd->buffer_capacity, igsd->mm.context);
if (igsd->buffer == NULL) {
return 1;
}
igsd->scalar = scalar;
if (!igsd->scalar) {
hash_si_init(&igsd->strings, 16);
hash_si_ptr_init(&igsd->objects, 16);
}
igsd->compact_strings = (bool)IGBINARY_G(compact_strings);
return r;
}
/* }}} */
/* {{{ igbinary_serialize_data_deinit */
/** Deinits igbinary_serialize_data. */
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer TSRMLS_DC) {
if (free_buffer && igsd->buffer) {
igsd->mm.free(igsd->buffer, igsd->mm.context);
}
if (!igsd->scalar) {
hash_si_deinit(&igsd->strings);
hash_si_ptr_deinit(&igsd->objects);
}
}
/* }}} */
/* {{{ igbinary_serialize_header */
/** Serializes header. */
inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd TSRMLS_DC) {
return igbinary_serialize32(igsd, IGBINARY_FORMAT_VERSION TSRMLS_CC); /* version */
}
/* }}} */
/* {{{ igbinary_serialize_resize */
/** Expands igbinary_serialize_data. */
inline static int igbinary_serialize_resize(struct igbinary_serialize_data *igsd, size_t size TSRMLS_DC) {
if (igsd->buffer_size + size < igsd->buffer_capacity) {
return 0;
}
while (igsd->buffer_size + size >= igsd->buffer_capacity) {
igsd->buffer_capacity *= 2;
}
igsd->buffer = (uint8_t *) igsd->mm.realloc(igsd->buffer, igsd->buffer_capacity, igsd->mm.context);
if (igsd->buffer == NULL)
return 1;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize8 */
/** Serialize 8bit value. */
inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i TSRMLS_DC) {
if (UNEXPECTED(igbinary_serialize_resize(igsd, 1 TSRMLS_CC))) {
return 1;
}
igsd->buffer[igsd->buffer_size++] = i;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize16 */
/** Serialize 16bit value. */
inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i TSRMLS_DC) {
uint8_t* append_buffer;
if (UNEXPECTED(igbinary_serialize_resize(igsd, 2 TSRMLS_CC))) {
return 1;
}
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = (uint8_t) (i >> 8 & 0xff);
append_buffer[1] = (uint8_t) (i & 0xff);
igsd->buffer_size += 2;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize32 */
/** Serialize 32bit value. */
inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i TSRMLS_DC) {
uint8_t* append_buffer;
if (UNEXPECTED(igbinary_serialize_resize(igsd, 4 TSRMLS_CC))) {
return 1;
}
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = (uint8_t) (i >> 24 & 0xff);
append_buffer[1] = (uint8_t) (i >> 16 & 0xff);
append_buffer[2] = (uint8_t) (i >> 8 & 0xff);
append_buffer[3] = (uint8_t) (i & 0xff);
igsd->buffer_size += 4;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize64 */
/** Serialize 64bit value. */
inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i TSRMLS_DC) {
uint8_t* append_buffer;
if (UNEXPECTED(igbinary_serialize_resize(igsd, 8 TSRMLS_CC))) {
return 1;
}
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = (uint8_t) (i >> 56 & 0xff);
append_buffer[1] = (uint8_t) (i >> 48 & 0xff);
append_buffer[2] = (uint8_t) (i >> 40 & 0xff);
append_buffer[3] = (uint8_t) (i >> 32 & 0xff);
append_buffer[4] = (uint8_t) (i >> 24 & 0xff);
append_buffer[5] = (uint8_t) (i >> 16 & 0xff);
append_buffer[6] = (uint8_t) (i >> 8 & 0xff);
append_buffer[7] = (uint8_t) (i & 0xff);
igsd->buffer_size += 8;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_null */
/** Serializes null. */
inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd TSRMLS_DC) {
return igbinary_serialize8(igsd, igbinary_type_null TSRMLS_CC);
}
/* }}} */
/* {{{ igbinary_serialize_bool */
/** Serializes bool. */
inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b TSRMLS_DC) {
return igbinary_serialize8(igsd, (uint8_t) (b ? igbinary_type_bool_true : igbinary_type_bool_false) TSRMLS_CC);
}
/* }}} */
/* {{{ igbinary_serialize_long */
/** Serializes long. */
inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, long l TSRMLS_DC) {
long k = l >= 0 ? l : -l;
bool p = l >= 0 ? true : false;
/* -LONG_MIN is 0 otherwise. */
if (l == LONG_MIN) {
#if SIZEOF_LONG == 8
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long64n TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize64(igsd, (uint64_t) 0x8000000000000000 TSRMLS_CC) != 0) {
return 1;
}
#elif SIZEOF_LONG == 4
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long32n TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) 0x80000000 TSRMLS_CC) != 0) {
return 1;
}
#else
#error "Strange sizeof(long)."
#endif
return 0;
}
if (k <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long8p : igbinary_type_long8n) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) k TSRMLS_CC) != 0) {
return 1;
}
} else if (k <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long16p : igbinary_type_long16n) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) k TSRMLS_CC) != 0) {
return 1;
}
#if SIZEOF_LONG == 8
} else if (k <= 0xffffffff) {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) k TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long64p : igbinary_type_long64n) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize64(igsd, (uint64_t) k TSRMLS_CC) != 0) {
return 1;
}
}
#elif SIZEOF_LONG == 4
} else {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) k TSRMLS_CC) != 0) {
return 1;
}
}
#else
#error "Strange sizeof(long)."
#endif
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_double */
/** Serializes double. */
inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d TSRMLS_DC) {
union {
double d;
uint64_t u;
} u;
if (igbinary_serialize8(igsd, igbinary_type_double TSRMLS_CC) != 0) {
return 1;
}
u.d = d;
return igbinary_serialize64(igsd, u.u TSRMLS_CC);
}
/* }}} */
/* {{{ igbinary_serialize_string */
/** Serializes string.
* Serializes each string once, after first time uses pointers.
*/
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, char *s, size_t len TSRMLS_DC) {
if (len == 0) {
if (igbinary_serialize8(igsd, igbinary_type_string_empty TSRMLS_CC) != 0) {
return 1;
}
return 0;
}
if (!igsd->scalar && igsd->compact_strings) {
struct hash_si_result result = hash_si_find_or_insert(&igsd->strings, s, len, igsd->string_count);
if (result.code == hash_si_code_exists) {
uint32_t value = result.value;
if (value <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id8 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) value TSRMLS_CC) != 0) {
return 1;
}
} else if (value <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id16 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) value TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id32 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) value TSRMLS_CC) != 0) {
return 1;
}
}
return 0;
} else if (EXPECTED(result.code == hash_si_code_inserted)) {
/* Fall through to igbinary_serialize_chararray */
} else {
return 1; /* Failed to allocate copy of string */
}
}
igsd->string_count++; /* A new string is being serialized - update count so that duplicate class names can be used. */
if (igbinary_serialize_chararray(igsd, s, len TSRMLS_CC) != 0) {
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_chararray */
/** Serializes string data. */
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len TSRMLS_DC) {
if (len <= 0xff) {
if (igbinary_serialize8(igsd, igbinary_type_string8 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, len TSRMLS_CC) != 0) {
return 1;
}
} else if (len <= 0xffff) {
if (igbinary_serialize8(igsd, igbinary_type_string16 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, len TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, igbinary_type_string32 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, len TSRMLS_CC) != 0) {
return 1;
}
}
if (igbinary_serialize_resize(igsd, len TSRMLS_CC)) {
return 1;
}
memcpy(igsd->buffer+igsd->buffer_size, s, len);
igsd->buffer_size += len;
return 0;
}
/* }}} */
/* {{{ igbinay_serialize_array */
/** Serializes array or objects inner properties. */
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class TSRMLS_DC) {
HashTable *h;
HashPosition pos;
size_t n;
zval **d;
char *key;
uint key_len;
int key_type;
ulong key_index;
/* hash */
h = object ? Z_OBJPROP_P(z) : HASH_OF(z);
/* hash size */
n = h ? zend_hash_num_elements(h) : 0;
/* incomplete class magic member */
if (n > 0 && incomplete_class) {
--n;
}
if (!object && igbinary_serialize_array_ref(igsd, z, object TSRMLS_CC) == 0) {
return 0;
}
if (n <= 0xff) {
if (igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, n TSRMLS_CC) != 0) {
return 1;
}
} else if (n <= 0xffff) {
if (igbinary_serialize8(igsd, igbinary_type_array16 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, n TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, igbinary_type_array32 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, n TSRMLS_CC) != 0) {
return 1;
}
}
if (n == 0) {
return 0;
}
/* serialize properties. */
zend_hash_internal_pointer_reset_ex(h, &pos);
for (;; zend_hash_move_forward_ex(h, &pos)) {
key_type = zend_hash_get_current_key_ex(h, &key, &key_len, &key_index, 0, &pos);
/* last */
if (key_type == HASH_KEY_NON_EXISTANT) {
break;
}
/* skip magic member in incomplete classes */
if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
continue;
}
switch (key_type) {
case HASH_KEY_IS_LONG:
if (igbinary_serialize_long(igsd, key_index TSRMLS_CC) != 0) {
return 1;
}
break;
case HASH_KEY_IS_STRING:
if (igbinary_serialize_string(igsd, key, key_len-1 TSRMLS_CC) != 0) {
return 1;
}
break;
default:
zend_error(E_ERROR, "igbinary_serialize_array: key is not string nor array");
/* not reached */
return 1;
}
/* we should still add element even if it's not OK,
* since we already wrote the length of the array before */
if (zend_hash_get_current_data_ex(h, (void *) &d, &pos) != SUCCESS || d == NULL) {
if (igbinary_serialize_null(igsd TSRMLS_CC)) {
return 1;
}
} else {
if (igbinary_serialize_zval(igsd, *d TSRMLS_CC)) {
return 1;
}
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_array_ref */
/** Serializes array reference. */
inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object TSRMLS_DC) {
/* Integer representation of pointer to a zend_object or zval */
size_t t;
zend_uintptr_t key;
if (object && Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_class_entry) {
key = (zend_uintptr_t) zend_objects_get_address(z TSRMLS_CC);
} else {
key = (zend_uintptr_t) z;
}
t = hash_si_ptr_find_or_insert(&igsd->objects, key, igsd->objects.used);
if (t == SIZE_MAX) {
return 1;
} else {
enum igbinary_type type;
if (t <= 0xff) {
type = object ? igbinary_type_objref8 : igbinary_type_ref8;
if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) t TSRMLS_CC) != 0) {
return 1;
}
} else if (t <= 0xffff) {
type = object ? igbinary_type_objref16 : igbinary_type_ref16;
if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) t TSRMLS_CC) != 0) {
return 1;
}
} else {
type = object ? igbinary_type_objref32 : igbinary_type_ref32;
if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) t TSRMLS_CC) != 0) {
return 1;
}
}
return 0;
}
return 1;
}
/* }}} */
/* {{{ igbinary_serialize_array_sleep */
/** Serializes object's properties array with __sleep -function. */
inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *h, zend_class_entry *ce, bool incomplete_class TSRMLS_DC) {
HashPosition pos;
size_t n = zend_hash_num_elements(h);
zval **d;
zval **v;
char *key;
uint key_len;
int key_type;
ulong key_index;
/* Decrease array size by one, because of magic member (with class name) */
if (n > 0 && incomplete_class) {
--n;
}
/* Serialize array id. */
if (n <= 0xff) {
if (igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, n TSRMLS_CC) != 0) {
return 1;
}
} else if (n <= 0xffff) {
if (igbinary_serialize8(igsd, igbinary_type_array16 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, n TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, igbinary_type_array32 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, n TSRMLS_CC) != 0) {
return 1;
}
}
if (n == 0) {
return 0;
}
zend_hash_internal_pointer_reset_ex(h, &pos);
for (;; zend_hash_move_forward_ex(h, &pos)) {
key_type = zend_hash_get_current_key_ex(h, &key, &key_len, &key_index, 0, &pos);
/* last */
if (key_type == HASH_KEY_NON_EXISTANT) {
break;
}
/* skip magic member in incomplete classes */
if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
continue;
}
if (zend_hash_get_current_data_ex(h, (void *) &d, &pos) != SUCCESS || d == NULL || Z_TYPE_PP(d) != IS_STRING) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only "
"containing the names of instance-variables to "
"serialize");
/* we should still add element even if it's not OK,
* since we already wrote the length of the array before
* serialize null as key-value pair */
if (igbinary_serialize_null(igsd TSRMLS_CC) != 0) {
return 1;
}
} else {
if (zend_hash_find(Z_OBJPROP_P(z), Z_STRVAL_PP(d), Z_STRLEN_PP(d) + 1, (void *) &v) == SUCCESS) {
if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
return 1;
}
} else if (ce) {
char *prot_name = NULL;
char *priv_name = NULL;
int prop_name_length;
do {
/* try private */
zend_mangle_property_name(&priv_name, &prop_name_length, ce->name, ce->name_length,
Z_STRVAL_PP(d), Z_STRLEN_PP(d), ce->type & ZEND_INTERNAL_CLASS);
if (zend_hash_find(Z_OBJPROP_P(z), priv_name, prop_name_length+1, (void *) &v) == SUCCESS) {
if (igbinary_serialize_string(igsd, priv_name, prop_name_length TSRMLS_CC) != 0) {
efree(priv_name);
return 1;
}
efree(priv_name);
if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
return 1;
}
break;
}
efree(priv_name);
/* try protected */
zend_mangle_property_name(&prot_name, &prop_name_length, "*", 1,
Z_STRVAL_PP(d), Z_STRLEN_PP(d), ce->type & ZEND_INTERNAL_CLASS);
if (zend_hash_find(Z_OBJPROP_P(z), prot_name, prop_name_length+1, (void *) &v) == SUCCESS) {
if (igbinary_serialize_string(igsd, prot_name, prop_name_length TSRMLS_CC) != 0) {
efree(prot_name);
return 1;
}
efree(prot_name);
if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
return 1;
}
break;
}
efree(prot_name);
/* no win */
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", Z_STRVAL_PP(d));
if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize_null(igsd TSRMLS_CC) != 0) {
return 1;
}
} while (0);
} else {
// if all else fails, just serialize the value in anyway.
if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
return 1;
}
}
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_object_name */
/** Serialize object name. */
inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, const char *class_name, size_t name_len TSRMLS_DC) {
struct hash_si_result result = hash_si_find_or_insert(&igsd->strings, class_name, name_len, igsd->string_count);
if (result.code == hash_si_code_inserted) {
igsd->string_count += 1;
if (name_len <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object8 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) name_len TSRMLS_CC) != 0) {
return 1;
}
} else if (name_len <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object16 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) name_len TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object32 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) name_len TSRMLS_CC) != 0) {
return 1;
}
}
if (igbinary_serialize_resize(igsd, name_len TSRMLS_CC)) {
return 1;
}
memcpy(igsd->buffer+igsd->buffer_size, class_name, name_len);
igsd->buffer_size += name_len;
} else if (EXPECTED(result.code == hash_si_code_exists)) {
/* already serialized string */
uint32_t value = result.value;
if (value <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id8 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) value TSRMLS_CC) != 0) {
return 1;
}
} else if (value <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id16 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) value TSRMLS_CC) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id32 TSRMLS_CC) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) value TSRMLS_CC) != 0) {
return 1;
}
}
} else {
return 1; /* Failed to allocate copy of string */
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_object */
/** Serialize object.
* @see ext/standard/var.c
* */
inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC) {
zend_class_entry *ce;
zval f;
zval *h = NULL;
int r = 0;
unsigned char *serialized_data = NULL;
zend_uint serialized_len;
PHP_CLASS_ATTRIBUTES;
if (igbinary_serialize_array_ref(igsd, z, true TSRMLS_CC) == 0) {
return r;
}
ce = Z_OBJCE_P(z);
/* custom serializer */
if (ce && ce->serialize != NULL) {
if (ce->serialize(z, &serialized_data, &serialized_len, (zend_serialize_data *)NULL TSRMLS_CC) == SUCCESS && !EG(exception)) {
if (igbinary_serialize_object_name(igsd, ce->name, ce->name_length TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (serialized_len <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser8 TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) serialized_len TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
} else if (serialized_len <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser16 TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) serialized_len TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser32 TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) serialized_len TSRMLS_CC) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
}
if (igbinary_serialize_resize(igsd, serialized_len TSRMLS_CC)) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
memcpy(igsd->buffer+igsd->buffer_size, serialized_data, serialized_len);
igsd->buffer_size += serialized_len;
} else if (EG(exception)) {
/* exception, return failure */
r = 1;
} else {
/* Serialization callback failed, assume null output */
r = igbinary_serialize_null(igsd TSRMLS_CC);
}
if (serialized_data) {
efree(serialized_data);
}
return r;
}
/* serialize class name */
PHP_SET_CLASS_ATTRIBUTES(z);
if (igbinary_serialize_object_name(igsd, class_name, name_len TSRMLS_CC) != 0) {
PHP_CLEANUP_CLASS_ATTRIBUTES();
return 1;
}
PHP_CLEANUP_CLASS_ATTRIBUTES();
if (ce && ce != PHP_IC_ENTRY && zend_hash_exists(&ce->function_table, "__sleep", sizeof("__sleep"))) {
/* function name string */
INIT_PZVAL(&f);
ZVAL_STRINGL(&f, "__sleep", sizeof("__sleep") - 1, 0);
/* calling z->__sleep */
r = call_user_function_ex(CG(function_table), &z, &f, &h, 0, 0, 1, NULL TSRMLS_CC);
if (r == SUCCESS && !EG(exception)) {
r = 0;
if (h) {
if (Z_TYPE_P(h) == IS_ARRAY) {
r = igbinary_serialize_array_sleep(igsd, z, HASH_OF(h), ce, incomplete_class TSRMLS_CC);
} else {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only "
"containing the names of instance-variables to "
"serialize");
/* empty array */
r = igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC);
if (r == 0) {
r = igbinary_serialize8(igsd, 0 TSRMLS_CC);
}
}
}
} else {
r = 1;
}
/* cleanup */
if (h) {
zval_ptr_dtor(&h);
}
return r;
} else {
return igbinary_serialize_array(igsd, z, true, incomplete_class TSRMLS_CC);
}
}
/* }}} */
/* {{{ igbinary_serialize_zval */
/** Serialize zval. */
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC) {
if (Z_ISREF_P(z)) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_ref TSRMLS_CC) != 0) {
return 1;
}
/* Complex types serialize a reference, scalars do not... */
/* FIXME: Absolutely wrong level to check this. */
switch (Z_TYPE_P(z)) {
case IS_RESOURCE:
case IS_STRING:
case IS_LONG:
case IS_NULL:
case IS_BOOL:
case IS_DOUBLE:
/* Serialize a reference if zval already added */
if (igbinary_serialize_array_ref(igsd, z, false TSRMLS_CC) == 0) {
return 0;
}
/* otherwise fall through */
}
}
switch (Z_TYPE_P(z)) {
case IS_RESOURCE:
return igbinary_serialize_null(igsd TSRMLS_CC);
case IS_OBJECT:
return igbinary_serialize_object(igsd, z TSRMLS_CC);
case IS_ARRAY:
return igbinary_serialize_array(igsd, z, false, false TSRMLS_CC);
case IS_STRING:
return igbinary_serialize_string(igsd, Z_STRVAL_P(z), Z_STRLEN_P(z) TSRMLS_CC);
case IS_LONG:
return igbinary_serialize_long(igsd, Z_LVAL_P(z) TSRMLS_CC);
case IS_NULL:
return igbinary_serialize_null(igsd TSRMLS_CC);
case IS_BOOL:
return igbinary_serialize_bool(igsd, Z_LVAL_P(z) ? 1 : 0 TSRMLS_CC);
case IS_DOUBLE:
return igbinary_serialize_double(igsd, Z_DVAL_P(z) TSRMLS_CC);
default:
zend_error(E_ERROR, "igbinary_serialize_zval: zval has unknown type %d", (int)Z_TYPE_P(z));
/* not reached */
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_data_init */
/** Inits igbinary_unserialize_data_init. */
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
smart_str empty_str = { 0 };
igsd->buffer = NULL;
igsd->buffer_size = 0;
igsd->buffer_offset = 0;
igsd->strings = NULL;
igsd->strings_count = 0;
igsd->strings_capacity = 4;
igsd->string0_buf = empty_str;
igsd->error = 0;
igsd->references = NULL;
igsd->references_count = 0;
igsd->references_capacity = 4;
igsd->references = (void **) emalloc(sizeof(void *) * igsd->references_capacity);
if (igsd->references == NULL) {
return 1;
}
igsd->strings = (struct igbinary_unserialize_string_pair *) emalloc(sizeof(struct igbinary_unserialize_string_pair) * igsd->strings_capacity);
if (igsd->strings == NULL) {
efree(igsd->references);
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_data_deinit */
/** Deinits igbinary_unserialize_data_init. */
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
if (igsd->strings) {
efree(igsd->strings);
}
if (igsd->references) {
efree(igsd->references);
}
smart_str_free(&igsd->string0_buf);
return;
}
/* }}} */
/* {{{ igbinary_unserialize_header_emit_warning */
/* Precondition: igsd->buffer_size >= 4 */
inline static void igbinary_unserialize_header_emit_warning(struct igbinary_unserialize_data *igsd, int version) {
int i;
char buf[9], *it;
for (i = 0; i < 4; i++) {
if (!isprint((int)igsd->buffer[i])) {
if (version != 0 && (version & 0xff000000) == version) {
// Check if high order byte was somehow set instead of low order byte
zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: %u, should be %u or %u (wrong endianness?)", (unsigned int) version, 0x00000001, (unsigned int) IGBINARY_FORMAT_VERSION);
return;
}
// Binary data, or a version number from a future release.
zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: %u, should be %u or %u", (unsigned int) version, 0x00000001, (unsigned int) IGBINARY_FORMAT_VERSION);
return;
}
}
for (it = buf, i = 0; i < 4; i++) {
char c = igsd->buffer[i];
if (c == '"' || c == '\\') {
*it++ = '\\';
}
*it++ = c;
}
*it = '\0';
zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: \"%s\"..., should begin with a binary version header of \"\\x00\\x00\\x00\\x01\" or \"\\x00\\x00\\x00\\x%02x\"", buf, (int)IGBINARY_FORMAT_VERSION);
}
/* }}} */
/* {{{ igbinary_unserialize_header */
/** Unserialize header. Check for version. */
inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
uint32_t version;
if (igsd->buffer_offset + 4 >= igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_header: expected at least 5 bytes of data, got %u byte(s)", (unsigned int) igsd->buffer_size);
return 1;
}
version = igbinary_unserialize32(igsd TSRMLS_CC);
/* Support older version 1 and the current format 2 */
if (version == IGBINARY_FORMAT_VERSION || version == 0x00000001) {
return 0;
} else {
igbinary_unserialize_header_emit_warning(igsd, version);
return 1;
}
}
/* }}} */
/* {{{ igbinary_unserialize8 */
/** Unserialize 8bit value. */
inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
uint8_t ret = 0;
ret = igsd->buffer[igsd->buffer_offset++];
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize16 */
/** Unserialize 16bit value. */
inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
const uint8_t* buffer_ptr = &igsd->buffer[igsd->buffer_offset];
uint16_t ret =
((uint16_t) (buffer_ptr[0]) << 8) |
((uint16_t) (buffer_ptr[1]));
igsd->buffer_offset += 2;
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize32 */
/** Unserialize 32bit value. */
inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
const uint8_t* buffer_ptr = &igsd->buffer[igsd->buffer_offset];
uint32_t ret =
((uint32_t) (buffer_ptr[0]) << 24) |
((uint32_t) (buffer_ptr[1]) << 16) |
((uint32_t) (buffer_ptr[2]) << 8) |
((uint32_t) (buffer_ptr[3]));
igsd->buffer_offset += 4;
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize64 */
/** Unserialize 64bit value. */
inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
const uint8_t* buffer_ptr = &igsd->buffer[igsd->buffer_offset];
uint64_t ret =
((uint64_t) (buffer_ptr[0]) << 56) |
((uint64_t) (buffer_ptr[1]) << 48) |
((uint64_t) (buffer_ptr[2]) << 40) |
((uint64_t) (buffer_ptr[3]) << 32) |
((uint64_t) (buffer_ptr[4]) << 24) |
((uint64_t) (buffer_ptr[5]) << 16) |
((uint64_t) (buffer_ptr[6]) << 8) |
((uint64_t) (buffer_ptr[7]) << 0);
igsd->buffer_offset += 8;
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize_long */
/** Unserializes long */
inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, long *ret TSRMLS_DC) {
uint32_t tmp32;
#if SIZEOF_LONG == 8
uint64_t tmp64;
#endif
if (t == igbinary_type_long8p || t == igbinary_type_long8n) {
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
*ret = (long) (t == igbinary_type_long8n ? -1 : 1) * igbinary_unserialize8(igsd TSRMLS_CC);
} else if (t == igbinary_type_long16p || t == igbinary_type_long16n) {
if (igsd->buffer_offset + 2 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
*ret = (long) (t == igbinary_type_long16n ? -1 : 1) * igbinary_unserialize16(igsd TSRMLS_CC);
} else if (t == igbinary_type_long32p || t == igbinary_type_long32n) {
if (igsd->buffer_offset + 4 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
/* check for boundaries */
tmp32 = igbinary_unserialize32(igsd TSRMLS_CC);
#if SIZEOF_LONG == 4
if (tmp32 > 0x80000000 || (tmp32 == 0x80000000 && t == igbinary_type_long32p)) {
zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform?");
tmp32 = 0; /* t == igbinary_type_long32p ? LONG_MAX : LONG_MIN; */
}
#endif
*ret = (long) (t == igbinary_type_long32n ? -1 : 1) * tmp32;
} else if (t == igbinary_type_long64p || t == igbinary_type_long64n) {
#if SIZEOF_LONG == 8
if (igsd->buffer_offset + 8 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
/* check for boundaries */
tmp64 = igbinary_unserialize64(igsd TSRMLS_CC);
if (tmp64 > 0x8000000000000000 || (tmp64 == 0x8000000000000000 && t == igbinary_type_long64p)) {
zend_error(E_WARNING, "igbinary_unserialize_long: too big 64bit long.");
tmp64 = 0; /* t == igbinary_type_long64p ? LONG_MAX : LONG_MIN */;
}
*ret = (long) (t == igbinary_type_long64n ? -1 : 1) * tmp64;
#elif SIZEOF_LONG == 4
/* can't put 64bit long into 32bit one, placeholder zero */
*ret = 0;
igbinary_unserialize64(igsd TSRMLS_CC);
zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform");
#else
#error "Strange sizeof(long)."
#endif
} else {
*ret = 0;
zend_error(E_WARNING, "igbinary_unserialize_long: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_double */
/** Unserializes double. */
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret TSRMLS_DC) {
union {
double d;
uint64_t u;
} u;
(void) t;
if (igsd->buffer_offset + 8 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_double: end-of-data");
return 1;
}
u.u = igbinary_unserialize64(igsd TSRMLS_CC);
*ret = u.d;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_string */
/** Unserializes string. Unserializes both actual string or by string id. */
inline static int igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC) {
size_t i;
if (t == igbinary_type_string_id8 || t == igbinary_type_object_id8) {
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
return 1;
}
i = igbinary_unserialize8(igsd TSRMLS_CC);
} else if (t == igbinary_type_string_id16 || t == igbinary_type_object_id16) {
if (igsd->buffer_offset + 2 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
return 1;
}
i = igbinary_unserialize16(igsd TSRMLS_CC);
} else if (t == igbinary_type_string_id32 || t == igbinary_type_object_id32) {
if (igsd->buffer_offset + 4 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
return 1;
}
i = igbinary_unserialize32(igsd TSRMLS_CC);
} else {
zend_error(E_WARNING, "igbinary_unserialize_string: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
if (i >= igsd->strings_count) {
zend_error(E_WARNING, "igbinary_unserialize_string: string index is out-of-bounds");
return 1;
}
*s = igsd->strings[i].data;
*len = igsd->strings[i].len;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_chararray */
/** Unserializes chararray of string. */
inline static int igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC) {
size_t l;
if (t == igbinary_type_string8 || t == igbinary_type_object8) {
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return 1;
}
l = igbinary_unserialize8(igsd TSRMLS_CC);
if (igsd->buffer_offset + l > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return 1;
}
} else if (t == igbinary_type_string16 || t == igbinary_type_object16) {
if (igsd->buffer_offset + 2 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return 1;
}
l = igbinary_unserialize16(igsd TSRMLS_CC);
if (igsd->buffer_offset + l > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return 1;
}
} else if (t == igbinary_type_string32 || t == igbinary_type_object32) {
if (igsd->buffer_offset + 4 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return 1;
}
l = igbinary_unserialize32(igsd TSRMLS_CC);
if (igsd->buffer_offset + l > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return 1;
}
} else {
zend_error(E_WARNING, "igbinary_unserialize_chararray: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
if (igsd->strings_count + 1 > igsd->strings_capacity) {
while (igsd->strings_count + 1 > igsd->strings_capacity) {
igsd->strings_capacity *= 2;
}
igsd->strings = (struct igbinary_unserialize_string_pair *) erealloc(igsd->strings, sizeof(struct igbinary_unserialize_string_pair) * igsd->strings_capacity);
if (igsd->strings == NULL) {
return 1;
}
}
igsd->strings[igsd->strings_count].data = (char *) (igsd->buffer + igsd->buffer_offset);
igsd->strings[igsd->strings_count].len = l;
igsd->buffer_offset += l;
if (igsd->strings[igsd->strings_count].data == NULL) {
return 1;
}
*len = igsd->strings[igsd->strings_count].len;
*s = igsd->strings[igsd->strings_count].data;
igsd->strings_count += 1;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_array */
/** Unserializes array. */
inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, int object TSRMLS_DC) {
size_t n;
size_t i;
zval *v = NULL;
/* zval *old_v; */
char *key;
size_t key_len = 0;
long key_index = 0;
enum igbinary_type key_type;
HashTable *h;
if (t == igbinary_type_array8) {
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd TSRMLS_CC);
} else if (t == igbinary_type_array16) {
if (igsd->buffer_offset + 2 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd TSRMLS_CC);
} else if (t == igbinary_type_array32) {
if (igsd->buffer_offset + 4 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd TSRMLS_CC);
} else {
zend_error(E_WARNING, "igbinary_unserialize_array: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
// n cannot be larger than the number of minimum "objects" in the array
if (n > igsd->buffer_size - igsd->buffer_offset) {
zend_error(E_WARNING, "%s: data size %zu smaller that requested array length %zu.", "igbinary_unserialize_array", igsd->buffer_size - igsd->buffer_offset, n);
return 1;
}
if (!object) {
Z_TYPE_PP(z) = IS_ARRAY;
ALLOC_HASHTABLE(Z_ARRVAL_PP(z));
zend_hash_init(Z_ARRVAL_PP(z), n + 1, NULL, ZVAL_PTR_DTOR, 0);
/* references */
if (igsd->references_count + 1 >= igsd->references_capacity) {
while (igsd->references_count + 1 >= igsd->references_capacity) {
igsd->references_capacity *= 2;
}
igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity);
if (igsd->references == NULL)
return 1;
}
igsd->references[igsd->references_count++] = (void *) *z;
}
/* empty array */
if (n == 0) {
return 0;
}
h = HASH_OF(*z);
for (i = 0; i < n; i++) {
key = NULL;
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
zval_dtor(*z);
ZVAL_NULL(*z);
return 1;
}
key_type = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC);
switch (key_type) {
case igbinary_type_long8p:
case igbinary_type_long8n:
case igbinary_type_long16p:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
if (igbinary_unserialize_long(igsd, key_type, &key_index TSRMLS_CC)) {
zval_dtor(*z);
ZVAL_NULL(*z);
return 1;
}
break;
case igbinary_type_string_id8:
case igbinary_type_string_id16:
case igbinary_type_string_id32:
if (igbinary_unserialize_string(igsd, key_type, &key, &key_len TSRMLS_CC)) {
zval_dtor(*z);
ZVAL_NULL(*z);
return 1;
}
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
if (igbinary_unserialize_chararray(igsd, key_type, &key, &key_len TSRMLS_CC)) {
zval_dtor(*z);
ZVAL_NULL(*z);
return 1;
}
break;
case igbinary_type_string_empty:
key = "";
key_len = 0;
break;
case igbinary_type_null:
continue;
default:
zend_error(E_WARNING, "igbinary_unserialize_array: unknown key type '%02x', position %zu", key_type, igsd->buffer_offset);
zval_dtor(*z);
ZVAL_NULL(*z);
return 1;
}
ALLOC_INIT_ZVAL(v);
if (igbinary_unserialize_zval(igsd, &v TSRMLS_CC)) {
zval_dtor(*z);
ZVAL_NULL(*z);
zval_ptr_dtor(&v);
return 1;
}
if (key) {
/* Keys must include a terminating null. */
/* Ensure buffer starts at the beginning. */
igsd->string0_buf.len = 0;
smart_str_appendl(&igsd->string0_buf, key, key_len);
smart_str_0(&igsd->string0_buf);
/*
if (zend_symtable_find(h, key, key_len + 1, (void **)&old_v) == SUCCESS) {
var_push_dtor(var_hash, old_v);
}
*/
zend_symtable_update(h, igsd->string0_buf.c, igsd->string0_buf.len + 1, &v, sizeof(v), NULL);
} else {
/*
if (zend_hash_index_find(h, key_index, (void **)&old_v) == SUCCESS) {
var_push_dtor(var_hash, old_v);
}
*/
/* PHP 5 can access object number properties only by string. */
if (UNEXPECTED(object)) {
char id[32], *p;
int len;
p = smart_str_print_long(id + sizeof(id) - 1, (long) key_index);
len = id + sizeof(id) - 1 - p;
/*if (zend_symtable_find(h, key, key_len + 1, (void **)&old_v) == SUCCESS) {
var_push_dtor(var_hash, old_v);
} */
zend_hash_update(h, p, len + 1, &v, sizeof(v), NULL); /* See process_nested_data from ext/standard/var_unserializer.re */
} else {
zend_hash_index_update(h, key_index, &v, sizeof(v), NULL);
}
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object_ser */
/** Unserializes object's property array of objects implementing Serializable -interface. */
inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, zend_class_entry *ce TSRMLS_DC) {
size_t n;
int ret;
php_unserialize_data_t var_hash;
if (ce->unserialize == NULL) {
zend_error(E_WARNING, "Class %s has no unserializer", ce->name);
return 1;
}
if (t == igbinary_type_object_ser8) {
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd TSRMLS_CC);
} else if (t == igbinary_type_object_ser16) {
if (igsd->buffer_offset + 2 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd TSRMLS_CC);
} else if (t == igbinary_type_object_ser32) {
if (igsd->buffer_offset + 4 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd TSRMLS_CC);
} else {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
if (igsd->buffer_offset + n > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
PHP_VAR_UNSERIALIZE_INIT(var_hash);
ret = ce->unserialize(z, ce,
(const unsigned char*)(igsd->buffer + igsd->buffer_offset), n,
(zend_unserialize_data *)&var_hash TSRMLS_CC);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
if (ret != SUCCESS || EG(exception)) {
return 1;
}
igsd->buffer_offset += n;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object */
/** Unserialize object.
* @see ext/standard/var_unserializer.c
*/
inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC) {
zend_class_entry *ce;
zend_class_entry **pce;
zval *h = NULL;
zval f;
char *name = NULL;
size_t name_len = 0;
int r;
bool incomplete_class = false;
bool is_from_serialized_data = false;
zval *user_func;
zval *retval_ptr;
zval **args[1];
zval *arg_func_name;
if (t == igbinary_type_object8 || t == igbinary_type_object16 || t == igbinary_type_object32) {
if (igbinary_unserialize_chararray(igsd, t, &name, &name_len TSRMLS_CC)) {
return 1;
}
} else if (t == igbinary_type_object_id8 || t == igbinary_type_object_id16 || t == igbinary_type_object_id32) {
if (igbinary_unserialize_string(igsd, t, &name, &name_len TSRMLS_CC)) {
return 1;
}
} else {
zend_error(E_WARNING, "igbinary_unserialize_object: unknown object type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
do {
/* Try to find class directly */
if (zend_lookup_class(name, name_len, &pce TSRMLS_CC) == SUCCESS) {
ce = *pce;
break;
}
/* Check for unserialize callback */
if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
incomplete_class = 1;
ce = PHP_IC_ENTRY;
break;
}
/* Call unserialize callback */
MAKE_STD_ZVAL(user_func);
ZVAL_STRING(user_func, PG(unserialize_callback_func), 1);
args[0] = &arg_func_name;
MAKE_STD_ZVAL(arg_func_name);
ZVAL_STRING(arg_func_name, name, 1);
if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", name);
incomplete_class = 1;
ce = PHP_IC_ENTRY;
zval_ptr_dtor(&user_func);
zval_ptr_dtor(&arg_func_name);
break;
}
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
/* The callback function may have defined the class */
if (zend_lookup_class(name, name_len, &pce TSRMLS_CC) == SUCCESS) {
ce = *pce;
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", name);
incomplete_class = true;
ce = PHP_IC_ENTRY;
}
zval_ptr_dtor(&user_func);
zval_ptr_dtor(&arg_func_name);
} while (0);
/* previous user function call may have raised an exception */
if (EG(exception)) {
return 1;
}
object_init_ex(*z, ce);
/* reference */
if (igsd->references_count + 1 >= igsd->references_capacity) {
while (igsd->references_count + 1 >= igsd->references_capacity) {
igsd->references_capacity *= 2;
}
igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity);
if (igsd->references == NULL)
return 1;
}
igsd->references[igsd->references_count++] = (void *) *z;
/* store incomplete class name */
if (incomplete_class) {
php_store_class_name(*z, name, name_len);
}
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
t = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC);
switch (t) {
case igbinary_type_array8:
case igbinary_type_array16:
case igbinary_type_array32:
r = igbinary_unserialize_array(igsd, t, z, 1 TSRMLS_CC);
break;
case igbinary_type_object_ser8:
case igbinary_type_object_ser16:
case igbinary_type_object_ser32:
is_from_serialized_data = true;
r = igbinary_unserialize_object_ser(igsd, t, z, ce TSRMLS_CC);
break;
default:
zend_error(E_WARNING, "igbinary_unserialize_object: unknown object inner type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
if (r) {
return r;
}
if (!is_from_serialized_data && Z_OBJCE_PP(z) != PHP_IC_ENTRY && zend_hash_exists(&Z_OBJCE_PP(z)->function_table, "__wakeup", sizeof("__wakeup"))) {
INIT_PZVAL(&f);
ZVAL_STRINGL(&f, "__wakeup", sizeof("__wakeup") - 1, 0);
call_user_function_ex(CG(function_table), z, &f, &h, 0, 0, 1, NULL TSRMLS_CC);
if (h) {
zval_ptr_dtor(&h);
}
if (EG(exception)) {
r = 1;
}
}
return r;
}
/* }}} */
/* {{{ igbinary_unserialize_ref */
/** Unserializes array or object by reference. */
inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC) {
size_t n;
if (t == igbinary_type_ref8 || t == igbinary_type_objref8) {
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd TSRMLS_CC);
} else if (t == igbinary_type_ref16 || t == igbinary_type_objref16) {
if (igsd->buffer_offset + 2 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd TSRMLS_CC);
} else if (t == igbinary_type_ref32 || t == igbinary_type_objref32) {
if (igsd->buffer_offset + 4 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd TSRMLS_CC);
} else {
zend_error(E_WARNING, "igbinary_unserialize_ref: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
if (n >= igsd->references_count) {
zend_error(E_WARNING, "igbinary_unserialize_ref: invalid reference");
return 1;
}
if (*z != NULL) {
zval_ptr_dtor(z);
}
*z = igsd->references[n];
Z_ADDREF_PP(z);
if (t == igbinary_type_objref8 || t == igbinary_type_objref16 || t == igbinary_type_objref32) {
Z_SET_ISREF_TO_PP(z, false);
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_zval */
/** Unserialize zval. */
static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval **z TSRMLS_DC) {
enum igbinary_type t;
long tmp_long;
double tmp_double;
char *tmp_chararray;
size_t tmp_size_t;
if (igsd->buffer_offset + 1 > igsd->buffer_size) {
zend_error(E_WARNING, "igbinary_unserialize_zval: end-of-data");
return 1;
}
t = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC);
switch (t) {
case igbinary_type_ref:
if (igbinary_unserialize_zval(igsd, z TSRMLS_CC)) {
return 1;
}
/* Scalar types should be added to the references hash */
/* unless they're already added */
/* in references list: marked as ref */
if (!Z_ISREF_PP(z)) switch (Z_TYPE_PP(z)) {
case IS_STRING:
case IS_LONG:
case IS_NULL:
case IS_DOUBLE:
case IS_BOOL:
/* reference */
if (igsd->references_count + 1 >= igsd->references_capacity) {
while (igsd->references_count + 1 >= igsd->references_capacity) {
igsd->references_capacity *= 2;
}
igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity);
if (igsd->references == NULL)
return 1;
}
igsd->references[igsd->references_count++] = (void *) *z;
}
Z_SET_ISREF_TO_PP(z, true);
break;
case igbinary_type_objref8:
case igbinary_type_objref16:
case igbinary_type_objref32:
case igbinary_type_ref8:
case igbinary_type_ref16:
case igbinary_type_ref32:
if (igbinary_unserialize_ref(igsd, t, z TSRMLS_CC)) {
return 1;
}
break;
case igbinary_type_object8:
case igbinary_type_object16:
case igbinary_type_object32:
case igbinary_type_object_id8:
case igbinary_type_object_id16:
case igbinary_type_object_id32:
if (igbinary_unserialize_object(igsd, t, z TSRMLS_CC)) {
return 1;
}
break;
case igbinary_type_array8:
case igbinary_type_array16:
case igbinary_type_array32:
if (igbinary_unserialize_array(igsd, t, z, 0 TSRMLS_CC)) {
return 1;
}
break;
case igbinary_type_string_empty:
ZVAL_EMPTY_STRING(*z);
break;
case igbinary_type_string_id8:
case igbinary_type_string_id16:
case igbinary_type_string_id32:
if (igbinary_unserialize_string(igsd, t, &tmp_chararray, &tmp_size_t TSRMLS_CC)) {
return 1;
}
ZVAL_STRINGL(*z, tmp_chararray, tmp_size_t, 1);
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
if (igbinary_unserialize_chararray(igsd, t, &tmp_chararray, &tmp_size_t TSRMLS_CC)) {
return 1;
}
ZVAL_STRINGL(*z, tmp_chararray, tmp_size_t, 1);
break;
case igbinary_type_long8p:
case igbinary_type_long8n:
case igbinary_type_long16p:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
if (igbinary_unserialize_long(igsd, t, &tmp_long TSRMLS_CC)) {
return 1;
}
ZVAL_LONG(*z, tmp_long);
break;
case igbinary_type_null:
ZVAL_NULL(*z);
break;
case igbinary_type_bool_false:
ZVAL_BOOL(*z, 0);
break;
case igbinary_type_bool_true:
ZVAL_BOOL(*z, 1);
break;
case igbinary_type_double:
if (igbinary_unserialize_double(igsd, t, &tmp_double TSRMLS_CC)) {
return 1;
}
ZVAL_DOUBLE(*z, tmp_double);
break;
default:
zend_error(E_WARNING, "igbinary_unserialize_zval: unknown type '%02x', position %zu", t, igsd->buffer_offset);
return 1;
}
return 0;
}
/* }}} */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
igbinary-2.0.5/src/php5/igbinary.h 0000644 0001750 0001750 00000005144 13177372464 016076 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef IGBINARY_H
#define IGBINARY_H
#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
# include
#endif
/* Forward declarations */
struct zval;
/* Constants / macro constants */
/** Binary protocol version of igbinary. */
#define IGBINARY_FORMAT_VERSION 0x00000002
#define PHP_IGBINARY_VERSION "2.0.5"
/* Macros */
#ifdef PHP_WIN32
# if defined(IGBINARY_EXPORTS) || (!defined(COMPILE_DL_IGBINARY))
# define IGBINARY_API __declspec(dllexport)
# elif defined(COMPILE_DL_IGBINARY)
# define IGBINARY_API __declspec(dllimport)
# else
# define IGBINARY_API /* nothing special */
# endif
#elif defined(__GNUC__) && __GNUC__ >= 4
# define IGBINARY_API __attribute__ ((visibility("default")))
#else
# define IGBINARY_API /* nothing special */
#endif
/** Struct that contains pointers to memory allocation and deallocation functions.
* @see igbinary_serialize_data
*/
struct igbinary_memory_manager {
void *(*alloc)(size_t size, void *context);
void *(*realloc)(void *ptr, size_t new_size, void *context);
void (*free)(void *ptr, void *context);
void *context;
};
/** Serialize zval.
* Return buffer is allocated by this function with emalloc.
* @param[out] ret Return buffer
* @param[out] ret_len Size of return buffer
* @param[in] z Variable to be serialized
* @return 0 on success, 1 elsewhere.
*/
IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z TSRMLS_DC);
/** Serialize zval.
* Return buffer is allocated by this function with emalloc.
* @param[out] ret Return buffer
* @param[out] ret_len Size of return buffer
* @param[in] z Variable to be serialized
* @param[in] memory_manager Pointer to the structure that contains memory allocation functions.
* @return 0 on success, 1 elsewhere.
*/
IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager TSRMLS_DC);
/** Unserialize to zval.
* @param[in] buf Buffer with serialized data.
* @param[in] buf_len Buffer length.
* @param[out] z Unserialized zval
* @return 0 on success, 1 elsewhere.
*/
IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval **z TSRMLS_DC);
#endif /* IGBINARY_H */
igbinary-2.0.5/src/php5/igbinary_macros.h 0000644 0001750 0001750 00000001377 13177372464 017446 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef PHP_IGBINARY_MACROS_H
#define PHP_IGBINARY_MACROS_H
/* Require zend.h first, so that we are absolutely importing this header doesn't override EXPECTED or UNEXPECTED. */
#include "zend.h"
/* PHP 5.2 doesn't define EXPECTED or UNEXPECTED in Zend/zend.h. */
#ifndef EXPECTED
# define EXPECTED(expr) (expr)
#endif
#ifndef UNEXPECTED
# define UNEXPECTED(expr) (expr)
#endif
#endif
igbinary-2.0.5/src/php5/php_igbinary.h 0000644 0001750 0001750 00000004652 13177372464 016750 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef PHP_IGBINARY_H
#define PHP_IGBINARY_H
#include "php.h"
/** Module entry of igbinary. */
extern zend_module_entry igbinary_module_entry;
#define phpext_igbinary_ptr &igbinary_module_entry
#ifdef PHP_WIN32
#define PHP_IGBINARY_API __declspec(dllexport)
#else
#define PHP_IGBINARY_API
#endif
ZEND_BEGIN_MODULE_GLOBALS(igbinary)
zend_bool compact_strings;
ZEND_END_MODULE_GLOBALS(igbinary)
#ifdef ZTS
#include "TSRM.h"
#endif
#include "ext/standard/php_smart_str.h"
/** Module init function. */
PHP_MINIT_FUNCTION(igbinary);
/** Module shutdown function. */
PHP_MSHUTDOWN_FUNCTION(igbinary);
/** Request init function. */
PHP_RINIT_FUNCTION(igbinary);
/** Request shutdown function. */
PHP_RSHUTDOWN_FUNCTION(igbinary);
/** Module info function for phpinfo(). */
PHP_MINFO_FUNCTION(igbinary);
/** string igbinary_serialize(mixed value).
* Returns the binary serialized value.
*/
PHP_FUNCTION(igbinary_serialize);
/** mixed igbinary_unserialize(string data).
* Unserializes the given inputstring (value).
*/
PHP_FUNCTION(igbinary_unserialize);
#ifdef ZTS
#define IGBINARY_G(v) TSRMG(igbinary_globals_id, zend_igbinary_globals *, v)
#else
#define IGBINARY_G(v) (igbinary_globals.v)
#endif
/** Backport macros from php 5.3 */
#ifndef Z_ISREF_P
#define Z_ISREF_P(pz) PZVAL_IS_REF(pz)
#endif
#ifndef Z_ISREF_PP
#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz))
#endif
#ifndef Z_SET_ISREF_TO_P
#define Z_SET_ISREF_TO_P(pz, isref) (Z_ISREF_P(pz) = (isref))
#endif
#ifndef Z_SET_ISREF_TO_PP
#define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref)
#endif
#ifndef Z_ADDREF_P
#define Z_ADDREF_P(pz) ZVAL_ADDREF(pz)
#endif
#ifndef Z_ADDREF_PP
#define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz))
#endif
/** Add macros missing from php 5.2 */
#include "igbinary_macros.h"
#endif /* PHP_IGBINARY_H */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 0
* End:
* vim600: noet sw=2 ts=2 fdm=marker
* vim<600: noet sw=2 ts=2
*/
igbinary-2.0.5/src/php5/ig_win32.h 0000644 0001750 0001750 00000001056 13177372464 015711 0 ustar tyson tyson #ifndef _IG_WIN32_H
#define _IG_WIN32_H
#if PHP_WIN32
# include "win32/php_stdint.h"
# if defined(_MSC_VER) && _MSC_VER >= 1800
# include
# else
# ifndef inline
# define inline __inline
# endif
# ifndef __cplusplus
# if !0
typedef enum { false = 0, true = 1 } _Bool;
# define bool _Bool
# endif
# else
typedef bool _Bool;
# define bool _Bool
# endif
# define false 0
# define true 1
# define __bool_true_false_are_defined 1
# endif /* __MSC_VER */
#endif /* PHP_WIN32 */
#endif /* _IG_WIN32_H */
igbinary-2.0.5/src/php5/apc_serializer.h 0000644 0001750 0001750 00000006475 13177372464 017276 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| APC |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2011 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gopal Vijayaraghavan |
+----------------------------------------------------------------------+
*/
/* $Id: $ */
#ifndef APC_SERIALIZER_H
#define APC_SERIALIZER_H
/* this is a shipped .h file, do not include any other header in this file */
#define APC_SERIALIZER_NAME(module) module##_apc_serializer
#define APC_UNSERIALIZER_NAME(module) module##_apc_unserializer
#define APC_SERIALIZER_ARGS unsigned char **buf, size_t *buf_len, const zval *value, void *config TSRMLS_DC
#define APC_UNSERIALIZER_ARGS zval **value, unsigned char *buf, size_t buf_len, void *config TSRMLS_DC
typedef int (*apc_serialize_t)(APC_SERIALIZER_ARGS);
typedef int (*apc_unserialize_t)(APC_UNSERIALIZER_ARGS);
typedef int (*apc_register_serializer_t)(const char* name,
apc_serialize_t serialize,
apc_unserialize_t unserialize,
void *config TSRMLS_DC);
/*
* ABI version for constant hooks. Increment this any time you make any changes
* to any function in this file.
*/
#define APC_SERIALIZER_ABI "0"
#define APC_SERIALIZER_CONSTANT "\000apc_register_serializer-" APC_SERIALIZER_ABI
#if !defined(APC_UNUSED)
# if defined(__GNUC__)
# define APC_UNUSED __attribute__((unused))
# else
# define APC_UNUSED
# endif
#endif
static APC_UNUSED int apc_register_serializer(const char* name,
apc_serialize_t serialize,
apc_unserialize_t unserialize,
void *config TSRMLS_DC)
{
zval *apc_magic_constant = NULL;
(void)config;
ALLOC_INIT_ZVAL(apc_magic_constant);
if (zend_get_constant(APC_SERIALIZER_CONSTANT, sizeof(APC_SERIALIZER_CONSTANT)-1, apc_magic_constant TSRMLS_CC)) {
if(apc_magic_constant) {
apc_register_serializer_t register_func = (apc_register_serializer_t)(Z_LVAL_P(apc_magic_constant));
if(register_func) {
zval_dtor(apc_magic_constant);
return register_func(name, serialize, unserialize, NULL TSRMLS_CC);
}
}
}
zval_dtor(apc_magic_constant);
return 0;
}
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4 sts=4
*/
igbinary-2.0.5/src/php7/hash.h 0000644 0001750 0001750 00000007435 13177372464 015224 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef HASH_H
#define HASH_H
#include
#ifdef PHP_WIN32
# include "ig_win32.h"
#else
# include /* defines uint32_t etc */
#endif
#include
#include "zend_types.h"
/** Key/value pair of hash_si.
* @author Oleg Grenrus
* @see hash_si
*/
struct hash_si_pair
{
zend_string* key_zstr; /* Contains key, key length, and key hash */
uint32_t key_hash; /**< Copy of ZSTR_H(key_zstr). Avoid dereferencing key_zstr if hashes are different. */
uint32_t value; /**< Value. */
};
enum hash_si_code {
hash_si_code_inserted,
hash_si_code_exists,
hash_si_code_exception
};
struct hash_si_result
{
enum hash_si_code code;
uint32_t value;
};
/** Hash-array.
* Like c++ unordered_map.
* Current implementation uses linear probing (with interval 1, 3, 5, or 7).
* @author Oleg Grenrus
*/
struct hash_si {
size_t mask; /**< Bitmask for the array. size == mask+1 */
size_t used; /**< Used size of array. */
struct hash_si_pair *data; /**< Pointer to array or pairs of data. */
};
/** Inits hash_si structure.
* @param h pointer to hash_si struct.
* @param size initial size of the hash array.
* @return 0 on success, 1 else.
*/
int hash_si_init (struct hash_si *h, size_t size);
/** Frees hash_si structure.
* Doesn't call free(h).
* @param h pointer to hash_si struct.
*/
void hash_si_deinit (struct hash_si *h);
/** Inserts value into hash_si.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param value Value.
* @return 0 on success, 1 or 2 else.
*/
/*
int hash_si_insert (struct hash_si *h, const char *key, size_t key_len, uint32_t value);
*/
/** Finds value from hash_si.
* Value returned thru value param.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Found value.
* @return 0 if found, 1 if not.
*/
/*
int hash_si_find (struct hash_si *h, const char *key, size_t key_len, uint32_t * value);
*/
/** Finds value from hash_si.
* Value returned thru value param.
* @param h Pointer to hash_si struct.
* @param key zend_string with key
* @param[out] value Found value.
* @return 0 if found, 1 if not.
*/
struct hash_si_result hash_si_find_or_insert(struct hash_si *h, zend_string *key, uint32_t value);
/** Remove value from hash_si.
* Removed value is available thru value param.
* @param h Pointer to hash_si struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Removed value.
* @return 0 ivalue removed, 1 if not existed.
*/
/*
int hash_si_remove (struct hash_si *h, const char *key, size_t key_len, uint32_t * value);
*/
/** Travarses hash_si.
* Calls traverse_function on every item. Traverse function should not modify hash
* @param h Pointer to hash_si struct.
* @param traverse_function Function to call on every item of hash_si.
*/
/*
void hash_si_traverse (struct hash_si *h, int (*traverse_function) (const char *key, size_t key_len, uint32_t value));
*/
/** Returns size of hash_si.
* @param h Pointer to hash_si struct.
* @return Size of hash_si.
*/
size_t hash_si_size (struct hash_si *h);
/** Returns capacity of hash_si.
* @param h Pointer to hash_si struct.
* @return Capacity of hash_si.
*/
size_t hash_si_capacity (struct hash_si *h);
#endif /* HASH_H */
igbinary-2.0.5/src/php7/hash_ptr.h 0000644 0001750 0001750 00000006531 13177372464 016105 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
| This defines hash_si_ptr. |
| It is like hash_si, but the key is always a non-zero zend_uintptr_t |
+----------------------------------------------------------------------+
*/
#ifndef HASH_PTR_H
#define HASH_PTR_H
#include
#ifdef PHP_WIN32
# include "ig_win32.h"
#else
# include /* defines uint32_t etc */
#endif
#include
#include "zend_types.h"
// NULL converted to an integer, on sane platforms.
#define HASH_PTR_KEY_INVALID 0
/** Key/value pair of hash_si_ptr.
* @author Oleg Grenrus
* @see hash_si_ptr
*/
struct hash_si_ptr_pair
{
zend_uintptr_t key; /**< The key: The address of a pointer, casted to an int (won't be dereferenced). */
uint32_t value; /**< Value. */
};
/** Hash-array.
* Like c++ std::unordered_map, but does not allow HASH_PTR_KEY_INVALID as a key.
* Current implementation uses linear probing.
* @author Oleg Grenrus
*/
struct hash_si_ptr {
size_t size; /**< Allocated size of array. */
size_t used; /**< Used size of array. */
struct hash_si_ptr_pair *data; /**< Pointer to array or pairs of data. */
};
/** Inits hash_si_ptr structure.
* @param h pointer to hash_si_ptr struct.
* @param size initial size of the hash array.
* @return 0 on success, 1 else.
*/
int hash_si_ptr_init(struct hash_si_ptr *h, size_t size);
/** Frees hash_si_ptr structure.
* Doesn't call free(h).
* @param h pointer to hash_si_ptr struct.
*/
void hash_si_ptr_deinit(struct hash_si_ptr *h);
/** Inserts value into hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param value Value.
* @return 0 on success, 1 or 2 else.
*/
/*
int hash_si_ptr_insert (struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value);
*/
/** Finds value from hash_si_ptr.
* Value returned thru value param.
* @param h Pointer to hash_si_ptr struct.
* @param key Pointer to key.
* @param key_len Key length.
* @param[out] value Found value.
* @return 0 if found, 1 if not.
*/
/*
int hash_si_ptr_find (struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t * value);
*/
/** Returns size of hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
* @return Size of hash_si_ptr.
*/
size_t hash_si_ptr_size (struct hash_si_ptr *h);
/**
* If the key does not exist, add a mapping from key to value and returns SIZE_MAX
* If the key does exist, return the corresponding value
* @param h Pointer to hash_si_ptr struct.
* @param key key to look up or add
* @param value value to insert if it doesn't already exist
*
* @return SIZE_MAX or old, unmodified key
*/
size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value);
/** Returns capacity of hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
* @return Capacity of hash_si_ptr.
*/
size_t hash_si_ptr_capacity (struct hash_si_ptr *h);
#endif /* HASH_PTR_H */
igbinary-2.0.5/src/php7/hash_si.c 0000644 0001750 0001750 00000015032 13177372464 015702 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifdef PHP_WIN32
# include "ig_win32.h"
#endif
#include
#include
#include
#include
#include "hash.h"
#include "zend.h"
/* {{{ nextpow2 */
/** Next power of 2.
* @param n Integer.
* @return next to n power of 2 .
*/
inline static uint32_t nextpow2(uint32_t n) {
uint32_t m = 1;
while (m < n) {
m = m << 1;
}
return m;
}
/* }}} */
/* {{{ hash_si_init */
int hash_si_init(struct hash_si *h, size_t size) {
size = nextpow2(size);
h->mask = size - 1;
h->used = 0;
h->data = (struct hash_si_pair *) emalloc(sizeof(struct hash_si_pair) * size);
if (h->data == NULL) {
return 1;
}
memset(h->data, 0, sizeof(struct hash_si_pair) * size);
return 0;
}
/* }}} */
/* {{{ hash_si_deinit */
void hash_si_deinit(struct hash_si *h) {
size_t i;
for (i = 0; i <= h->mask; i++) {
if (h->data[i].key_zstr != NULL) {
zend_string_release(h->data[i].key_zstr);
}
}
efree(h->data);
h->mask = 0;
h->used = 0;
}
/* }}} */
/* {{{ _hash_si_find */
/** Returns index of key, or where it should be.
* @param h Pointer to hash_si struct.
* @param key_zstr Pointer to key. (Will initialize ZSTR_H(key_zstr) if not already initialized)
* @return index.
*/
inline static struct hash_si_pair *_hash_si_find(const struct hash_si *h, const zend_string *key_zstr, const uint32_t key_hash) {
size_t mask;
struct hash_si_pair *it;
const struct hash_si_pair *last_element;
uint32_t increment;
uint32_t elem_key_hash;
assert(h != NULL);
mask = h->mask;
it = &(h->data[key_hash & mask]);
elem_key_hash = it->key_hash;
if (elem_key_hash == 0) {
/* This slot is empty - PHP guarantees hashes are non-zero */
return it;
}
if (key_hash == elem_key_hash) {
const zend_string *elem_key_zstr = it->key_zstr;
if (key_zstr == elem_key_zstr || (
ZSTR_LEN(key_zstr) == ZSTR_LEN(elem_key_zstr) &&
EXPECTED(!memcmp(ZSTR_VAL(key_zstr), ZSTR_VAL(elem_key_zstr), ZSTR_LEN(elem_key_zstr))))) {
/* We found an identical key. */
return it;
}
}
increment = ((key_hash >> 16) & 6) | 1; /* An odd number < size to increment by (1, 3, 5, or 7). Avoid clumping. */
last_element = h->data + mask;
/* Continue scanning, we'll reach an empty element eventually (odd number increment over a hash table of size (2^n) will traverse the entire map). */
while (1) {
it += increment;
if (it > last_element) {
it -= (mask + 1);
}
elem_key_hash = it->key_hash;
if (elem_key_hash == 0) {
/* This slot is empty - PHP guarantees hashes are non-zero */
return it;
}
if (key_hash == elem_key_hash) {
const zend_string *elem_key_zstr = it->key_zstr;
if (EXPECTED(key_zstr == elem_key_zstr || (
ZSTR_LEN(key_zstr) == ZSTR_LEN(elem_key_zstr) &&
EXPECTED(!memcmp(ZSTR_VAL(key_zstr), ZSTR_VAL(elem_key_zstr), ZSTR_LEN(elem_key_zstr)))))) {
/* We found an identical key. */
return it;
}
}
/* linear probing by increment if we found a different key */
}
}
/* }}} */
/* {{{ hash_si_rehash */
/** Rehash/resize hash_si.
* @param h Pointer to hash_si struct.
*/
inline static void hash_si_rehash(struct hash_si *h) {
size_t i;
size_t size;
struct hash_si newh;
struct hash_si_pair *data;
struct hash_si_pair *new_data;
assert(h != NULL);
size = h->mask + 1;
hash_si_init(&newh, size * 2);
data = h->data;
new_data = newh.data;
for (i = 0; i < size; i++) {
const struct hash_si_pair *old_pair = &data[i];
const zend_string *key_zstr = old_pair->key_zstr;
if (key_zstr != NULL) {
/* We already computed the hash, avoid recomputing it. */
struct hash_si_pair *new_data_entry = _hash_si_find((const struct hash_si*) &newh, key_zstr, old_pair->key_hash);
*new_data_entry = *old_pair;
}
}
efree(h->data);
h->data = new_data;
h->mask = size * 2 - 1;
}
/* }}} */
/* {{{ hash_si_insert */
/*
int hash_si_insert(struct hash_si *h, const char *key, size_t key_len, uint32_t value) {
uint32_t hv;
if (h->size / 4 * 3 < h->used + 1) {
hash_si_rehash(h);
}
hv = _hash_si_find(h, key, key_len);
if (h->data[hv].key == NULL) {
h->data[hv].key = (char *) emalloc(key_len + 1);
if (h->data[hv].key == NULL) {
return 1;
}
memcpy(h->data[hv].key, key, key_len);
h->data[hv].key[key_len] = '\0';
h->data[hv].key_len = key_len;
h->used++;
} else {
return 2;
}
h->data[hv].value = value;
return 0;
}
*/
/* }}} */
/* {{{ hash_si_find */
/*
int hash_si_find(struct hash_si *h, const char *key, size_t key_len, uint32_t *value) {
uint32_t hv;
assert(h != NULL);
hv = _hash_si_find(h, key, key_len);
if (h->data[hv].key == NULL) {
return 1;
} else {
*value = h->data[hv].value;
return 0;
}
}
*/
/* }}} */
/* {{{ hash_si_find_or_insert */
struct hash_si_result hash_si_find_or_insert(struct hash_si *h, zend_string *key_zstr, uint32_t value) {
struct hash_si_result result;
struct hash_si_pair *pair;
uint32_t key_hash = ZSTR_HASH(key_zstr);
pair = _hash_si_find(h, key_zstr, key_hash);
if (pair->key_zstr == NULL) {
zend_string_addref(key_zstr);
/* Having already computed the hash in the zend_string, insert that into the hash table */
pair->key_zstr = key_zstr;
pair->key_hash = key_hash;
pair->value = value;
h->used++;
if (h->mask * 3 / 4 < h->used) {
hash_si_rehash(h);
}
result.code = hash_si_code_inserted;
return result;
} else {
result.code = hash_si_code_exists;
result.value = pair->value;
return result;
}
}
/* }}} */
/* {{{ hash_si_traverse */
/*
void hash_si_traverse(struct hash_si *h, int (*traverse_function) (const char *key, size_t key_len, uint32_t value)) {
size_t i;
assert(h != NULL && traverse_function != NULL);
for (i = 0; i < h->size; i++) {
if (h->data[i].key != NULL && traverse_function(h->data[i].key, h->data[i].key_len, h->data[i].value) != 1) {
return;
}
}
}
*/
/* }}} */
/* {{{ hash_si_size */
size_t hash_si_size(struct hash_si *h) {
assert(h != NULL);
return h->used;
}
/* }}} */
/* {{{ hash_si_capacity */
size_t hash_si_capacity(struct hash_si *h) {
assert(h != NULL);
return h->mask + 1;
}
/* }}} */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
igbinary-2.0.5/src/php7/hash_si_ptr.c 0000644 0001750 0001750 00000012011 13177372464 016561 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
| This is a specialized hash map mapping uintprt_t to int32_t |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| Modified by Tyson Andre for fixed size, removing unused functions |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
# include
#endif
#include
#include
#include
#include
#include "hash_ptr.h"
#include "zend.h"
/* Function similar to zend_inline_hash_func. This is not identical. */
inline static uint32_t inline_hash_of_address(zend_uintptr_t ptr) {
register uint32_t hash = Z_UL(5381);
/* Note: Hash the least significant bytes first - Those need to influence the final result as much as possible. */
hash = ((hash << 5) + hash) + (ptr & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 8) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 16) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 24) & 0xff);
#if UINTPTR_MAX > UINT32_MAX
hash = ((hash << 5) + hash) + ((ptr >> 32) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 40) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 48) & 0xff);
hash = ((hash << 5) + hash) + ((ptr >> 56) & 0xff);
#endif
return hash;
}
/* {{{ nextpow2 */
/** Next power of 2.
* @param n Integer.
* @return next to n power of 2 .
*/
inline static uint32_t nextpow2(uint32_t n) {
uint32_t m = 1;
while (m < n) {
m = m << 1;
}
return m;
}
/* }}} */
/* {{{ hash_si_ptr_init */
int hash_si_ptr_init(struct hash_si_ptr *h, size_t size) {
size = nextpow2(size);
h->size = size;
h->used = 0;
h->data = (struct hash_si_ptr_pair*) malloc(sizeof(struct hash_si_ptr_pair) * size);
if (h->data == NULL) {
return 1;
}
memset(h->data, 0, sizeof(struct hash_si_ptr_pair) * size); /* Set everything to 0. sets keys to HASH_PTR_KEY_INVALID. */
return 0;
}
/* }}} */
/* {{{ hash_si_ptr_deinit */
void hash_si_ptr_deinit(struct hash_si_ptr *h) {
free(h->data);
h->data = NULL;
h->size = 0;
h->used = 0;
}
/* }}} */
/* {{{ _hash_si_ptr_find */
/** Returns index of key, or where it should be.
* @param h Pointer to hash_si_ptr struct.
* @param key Pointer to key.
* @return index.
*/
inline static size_t _hash_si_ptr_find(struct hash_si_ptr *h, const zend_uintptr_t key) {
uint32_t hv;
size_t size;
assert(h != NULL);
size = h->size;
hv = inline_hash_of_address(key) & (h->size-1);
while (size > 0 &&
h->data[hv].key != HASH_PTR_KEY_INVALID &&
h->data[hv].key != key) {
/* linear prob */
hv = (hv + 1) & (h->size-1);
size--;
}
return hv;
}
/* }}} */
/* }}} */
/* {{{ hash_si_ptr_rehash */
/** Rehash/resize hash_si_ptr.
* @param h Pointer to hash_si_ptr struct.
*/
inline static void hash_si_ptr_rehash(struct hash_si_ptr *h) {
uint32_t hv;
size_t i;
struct hash_si_ptr newh;
assert(h != NULL);
hash_si_ptr_init(&newh, h->size * 2);
for (i = 0; i < h->size; i++) {
if (h->data[i].key != HASH_PTR_KEY_INVALID) {
hv = _hash_si_ptr_find(&newh, h->data[i].key);
newh.data[hv].key = h->data[i].key;
newh.data[hv].value = h->data[i].value;
}
}
free(h->data);
h->data = newh.data;
h->size *= 2;
}
/* }}} */
/* {{{ hash_si_ptr_insert */
/*
int hash_si_ptr_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value) {
uint32_t hv;
if (h->size / 4 * 3 < h->used + 1) {
hash_si_ptr_rehash(h);
}
hv = _hash_si_ptr_find(h, key);
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
h->data[hv].key = key;
h->used++;
} else {
return 2;
}
h->data[hv].value = value;
return 0;
}
*/
/* }}} */
/* {{{ hash_si_ptr_find */
/*
int hash_si_ptr_find(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t *value) {
uint32_t hv;
assert(h != NULL);
hv = _hash_si_ptr_find(h, key);
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
return 1;
} else {
*value = h->data[hv].value;
return 0;
}
}
*/
/* }}} */
/* {{{ hash_si_ptr_find_or_insert */
size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const zend_uintptr_t key, uint32_t value) {
uint32_t hv;
hv = _hash_si_ptr_find(h, key);
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
h->data[hv].key = key;
h->data[hv].value = value;
h->used++;
/* The size increased, so check if we need to expand the map */
if (h->size / 4 * 3 < h->used) {
hash_si_ptr_rehash(h);
}
return SIZE_MAX;
} else {
return h->data[hv].value;
}
}
/* }}} */
/* {{{ hash_si_ptr_size */
size_t hash_si_ptr_size(struct hash_si_ptr *h) {
assert(h != NULL);
return h->used;
}
/* }}} */
/* {{{ hash_si_ptr_capacity */
size_t hash_si_ptr_capacity(struct hash_si_ptr *h) {
assert(h != NULL);
return h->size;
}
/* }}} */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
igbinary-2.0.5/src/php7/igbinary.c 0000644 0001750 0001750 00000247503 13177372464 016102 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef PHP_WIN32
# include "ig_win32.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "zend_alloc.h"
#include "ext/standard/info.h"
#include "ext/standard/php_var.h"
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
# include "ext/session/php_session.h"
#endif
#include "ext/standard/php_incomplete_class.h"
/* Note: there are no checks for APC (project from which APCU was forked) */
#if defined(HAVE_APCU_SUPPORT)
# include "ext/apcu/apc_serializer.h"
#endif /* HAVE_APCU_SUPPORT */
#include "php_igbinary.h"
#include "igbinary.h"
#include
#include
#ifndef PHP_WIN32
# include
# include
# include
#endif
#include
#include "hash.h"
#include "hash_ptr.h"
#include "zend_alloc.h"
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
/** Session serializer function prototypes. */
PS_SERIALIZER_FUNCS(igbinary);
#endif /* HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) */
#if defined(HAVE_APCU_SUPPORT)
/** Apc serializer function prototypes */
static int APC_SERIALIZER_NAME(igbinary) (APC_SERIALIZER_ARGS);
static int APC_UNSERIALIZER_NAME(igbinary) (APC_UNSERIALIZER_ARGS);
#endif
/* {{{ Types */
enum igbinary_type {
/* 00 */ igbinary_type_null, /**< Null. */
/* 01 */ igbinary_type_ref8, /**< Array reference. */
/* 02 */ igbinary_type_ref16, /**< Array reference. */
/* 03 */ igbinary_type_ref32, /**< Array reference. */
/* 04 */ igbinary_type_bool_false, /**< Boolean true. */
/* 05 */ igbinary_type_bool_true, /**< Boolean false. */
/* 06 */ igbinary_type_long8p, /**< Long 8bit positive. */
/* 07 */ igbinary_type_long8n, /**< Long 8bit negative. */
/* 08 */ igbinary_type_long16p, /**< Long 16bit positive. */
/* 09 */ igbinary_type_long16n, /**< Long 16bit negative. */
/* 0a */ igbinary_type_long32p, /**< Long 32bit positive. */
/* 0b */ igbinary_type_long32n, /**< Long 32bit negative. */
/* 0c */ igbinary_type_double, /**< Double. */
/* 0d */ igbinary_type_string_empty, /**< Empty string. */
/* 0e */ igbinary_type_string_id8, /**< String id. */
/* 0f */ igbinary_type_string_id16, /**< String id. */
/* 10 */ igbinary_type_string_id32, /**< String id. */
/* 11 */ igbinary_type_string8, /**< String. */
/* 12 */ igbinary_type_string16, /**< String. */
/* 13 */ igbinary_type_string32, /**< String. */
/* 14 */ igbinary_type_array8, /**< Array. */
/* 15 */ igbinary_type_array16, /**< Array. */
/* 16 */ igbinary_type_array32, /**< Array. */
/* 17 */ igbinary_type_object8, /**< Object. */
/* 18 */ igbinary_type_object16, /**< Object. */
/* 19 */ igbinary_type_object32, /**< Object. */
/* 1a */ igbinary_type_object_id8, /**< Object string id. */
/* 1b */ igbinary_type_object_id16, /**< Object string id. */
/* 1c */ igbinary_type_object_id32, /**< Object string id. */
/* 1d */ igbinary_type_object_ser8, /**< Object serialized data. */
/* 1e */ igbinary_type_object_ser16, /**< Object serialized data. */
/* 1f */ igbinary_type_object_ser32, /**< Object serialized data. */
/* 20 */ igbinary_type_long64p, /**< Long 64bit positive. */
/* 21 */ igbinary_type_long64n, /**< Long 64bit negative. */
/* 22 */ igbinary_type_objref8, /**< Object reference. */
/* 23 */ igbinary_type_objref16, /**< Object reference. */
/* 24 */ igbinary_type_objref32, /**< Object reference. */
/* 25 */ igbinary_type_ref, /**< Simple reference */
};
/** Serializer data.
* @author Oleg Grenrus
*/
struct igbinary_serialize_data {
uint8_t *buffer; /**< Buffer. */
size_t buffer_size; /**< Buffer size. */
size_t buffer_capacity; /**< Buffer capacity. */
bool scalar; /**< Serializing scalar. */
bool compact_strings; /**< Check for duplicate strings. */
struct hash_si strings; /**< Hash of already serialized strings. */
struct hash_si_ptr references; /**< Hash of already serialized potential references. (non-NULL uintptr_t => int32_t) */
int references_id; /**< Number of things that the unserializer might think are references. >= length of references */
int string_count; /**< Serialized string count, used for back referencing */
int error; /**< Error number. Not used. */
struct igbinary_memory_manager mm; /**< Memory management functions. */
};
/*
Object {
reference {scalar, object, array, null} (convert to reference, share reference in zval_ref)
object {} (convert to zend_object, share zend_object* in reference)
array {} (convert to zend_array, share zend_array* in reference)
}
*/
enum zval_ref_type {
IG_REF_IS_REFERENCE, // Points to zend_reference
IG_REF_IS_OBJECT, // Points to zend_object
IG_REF_IS_ARRAY, // Points to zend_object
};
struct igbinary_value_ref {
// We reuse temporary values for object properties that are references or arrays.
union {
zend_reference *reference;
zend_object *object;
zend_array *array;
} reference;
enum zval_ref_type type;
};
/** Unserializer data.
* @author Oleg Grenrus
*/
struct igbinary_unserialize_data {
const uint8_t *buffer; /**< Buffer. */
const uint8_t *buffer_end; /**< Buffer size. */
const uint8_t *buffer_ptr; /**< Current read offset. */
zend_string **strings; /**< Unserialized strings. */
size_t strings_count; /**< Unserialized string count. */
size_t strings_capacity; /**< Unserialized string array capacity. */
struct igbinary_value_ref *references; /**< Unserialized Arrays/Objects/References */
size_t references_count; /**< Unserialized array/objects count. */
size_t references_capacity; /**< Unserialized array/object array capacity. */
zend_object **wakeup; /**< objects for calls to __wakeup. */
size_t wakeup_count; /**< count of objects in array for calls to __wakeup */
size_t wakeup_capacity; /**< capacity of objects in array for calls to __wakeup */
int error; /**< Error number. Not used. */
smart_string string0_buf; /**< Temporary buffer for strings */
};
#define IGB_REF_VAL_2(igsd, n) ((igsd)->references[(n)])
#define IGB_NEEDS_MORE_DATA(igsd, n) UNEXPECTED((size_t)((igsd)->buffer_end - (igsd)->buffer_ptr) < (n))
#define IGB_REMAINING_BYTES(igsd) ((unsigned int)((igsd)->buffer_end - (igsd)->buffer_ptr))
#define IGB_BUFFER_OFFSET(igsd) ((unsigned int)((igsd)->buffer_ptr - (igsd)->buffer))
#define WANT_CLEAR (0)
#define WANT_REF (1<<1)
/* }}} */
/* {{{ Memory allocator wrapper prototypes */
static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context);
static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context);
static inline void igbinary_mm_wrapper_free(void *ptr, void *context);
/* }}} */
/* {{{ Serializing functions prototypes */
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager);
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer);
inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd);
inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i);
inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i);
inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i);
inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i);
inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd);
inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b);
inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, zend_long l);
inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d);
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, zend_string *s);
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len);
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class);
inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object);
inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *ht, zend_class_entry *ce, bool incomplete_class);
inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, zend_string *name);
inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z);
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z);
/* }}} */
/* {{{ Unserializing functions prototypes */
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd);
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd);
inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd);
inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd);
inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd);
inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd);
inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd);
inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zend_long *ret);
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret);
inline static zend_string * igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t);
inline static zend_string * igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t);
inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags);
inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags);
inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, zend_class_entry *ce);
inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags);
inline static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval *const z, int flags);
/* }}} */
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_serialize, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ igbinary_functions[] */
/** Exported php functions. */
zend_function_entry igbinary_functions[] = {
PHP_FE(igbinary_serialize, arginfo_igbinary_serialize)
PHP_FE(igbinary_unserialize, arginfo_igbinary_unserialize)
PHP_FE_END
};
/* }}} */
/* {{{ igbinary dependencies */
static const zend_module_dep igbinary_module_deps[] = {
ZEND_MOD_REQUIRED("standard")
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
ZEND_MOD_REQUIRED("session")
#endif
#if defined(HAVE_APCU_SUPPORT)
ZEND_MOD_OPTIONAL("apcu")
#endif
ZEND_MOD_END
};
/* }}} */
/* {{{ igbinary_module_entry */
zend_module_entry igbinary_module_entry = {
#if ZEND_MODULE_API_NO >= 20050922
STANDARD_MODULE_HEADER_EX, NULL,
igbinary_module_deps,
#elif ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"igbinary",
igbinary_functions,
PHP_MINIT(igbinary),
PHP_MSHUTDOWN(igbinary),
NULL,
NULL,
PHP_MINFO(igbinary),
#if ZEND_MODULE_API_NO >= 20010901
PHP_IGBINARY_VERSION, /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
/* }}} */
ZEND_DECLARE_MODULE_GLOBALS(igbinary)
/* {{{ ZEND_GET_MODULE */
#ifdef COMPILE_DL_IGBINARY
ZEND_GET_MODULE(igbinary)
#endif
/* }}} */
/* {{{ INI entries */
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("igbinary.compact_strings", "1", PHP_INI_ALL, OnUpdateBool, compact_strings, zend_igbinary_globals, igbinary_globals)
PHP_INI_END()
/* }}} */
/* {{{ php_igbinary_init_globals */
static void php_igbinary_init_globals(zend_igbinary_globals *igbinary_globals) {
igbinary_globals->compact_strings = 1;
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(igbinary) {
(void) type;
(void) module_number;
ZEND_INIT_MODULE_GLOBALS(igbinary, php_igbinary_init_globals, NULL);
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
php_session_register_serializer("igbinary",
PS_SERIALIZER_ENCODE_NAME(igbinary),
PS_SERIALIZER_DECODE_NAME(igbinary));
#endif
#if defined(HAVE_APCU_SUPPORT)
apc_register_serializer("igbinary",
APC_SERIALIZER_NAME(igbinary),
APC_UNSERIALIZER_NAME(igbinary),
NULL);
#endif
REGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(igbinary) {
(void) type;
(void) module_number;
#ifdef ZTS
ts_free_id(igbinary_globals_id);
#endif
/*
* Clean up ini entries.
* Aside: It seems like the php_session_register_serializer unserializes itself, since MSHUTDOWN in ext/wddx/wddx.c doesn't exist?
*/
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(igbinary) {
(void) zend_module;
php_info_print_table_start();
php_info_print_table_row(2, "igbinary support", "enabled");
php_info_print_table_row(2, "igbinary version", PHP_IGBINARY_VERSION);
#if defined(HAVE_APCU_SUPPORT)
php_info_print_table_row(2, "igbinary APCU serializer ABI", APC_SERIALIZER_ABI);
#else
php_info_print_table_row(2, "igbinary APC serializer ABI", "no");
#endif
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
php_info_print_table_row(2, "igbinary session support", "yes");
#else
php_info_print_table_row(2, "igbinary session support", "no");
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ igsd management */
/* Append to list of references to take out later. Returns SIZE_MAX on allocation error. */
static inline size_t igsd_append_ref(struct igbinary_unserialize_data *igsd, struct igbinary_value_ref v)
{
size_t ref_n;
if (igsd->references_count + 1 >= igsd->references_capacity) {
while (igsd->references_count + 1 >= igsd->references_capacity) {
igsd->references_capacity *= 2;
}
struct igbinary_value_ref *new_references = erealloc(igsd->references, sizeof(igsd->references[0]) * igsd->references_capacity);
if (new_references == NULL) {
return SIZE_MAX;
}
igsd->references = new_references;
}
ref_n = igsd->references_count++;
IGB_REF_VAL_2(igsd, ref_n) = v;
return ref_n;
}
static inline int igsd_defer_wakeup(struct igbinary_unserialize_data *igsd, zend_object* object) {
if (igsd->wakeup_count >= igsd->wakeup_capacity) {
if (igsd->wakeup_capacity == 0) {
igsd->wakeup_capacity = 2;
igsd->wakeup = emalloc(sizeof(igsd->wakeup[0]) * igsd->wakeup_capacity);
} else {
igsd->wakeup_capacity *= 2;
igsd->wakeup = erealloc(igsd->wakeup, sizeof(igsd->wakeup[0]) * igsd->wakeup_capacity);
if (igsd->wakeup == NULL) {
return 1;
}
}
}
igsd->wakeup[igsd->wakeup_count++] = object;
return 0;
}
/* }}} */
/* {{{ igbinary_finish_wakeup }}} */
static int igbinary_finish_wakeup(struct igbinary_unserialize_data* igsd) {
if (igsd->wakeup_count == 0) { /* nothing to do */
return 0;
}
zval fname;
size_t i;
ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
for (i = 0; i < igsd->wakeup_count; i++) {
zval retval; /* return value of __wakeup */
zval rval;
zend_object *obj = igsd->wakeup[i];
ZVAL_OBJ(&rval, obj);
if (call_user_function_ex(CG(function_table), &rval, &fname, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) {
GC_FLAGS(obj) |= IS_OBJ_DESTRUCTOR_CALLED;
}
zval_ptr_dtor(&retval);
if (EG(exception)) {
size_t j;
zval_dtor(&fname);
/* Don't call __destruct for any of the objects which __wakeup wasn't called on yet, either */
for (j = i + 1; j < igsd->wakeup_count; j++) {
GC_FLAGS(igsd->wakeup[j]) |= IS_OBJ_DESTRUCTOR_CALLED;
}
return 1;
}
}
zval_dtor(&fname);
return 0;
}
/* {{{ Memory allocator wrappers */
static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context)
{
(void)context;
return emalloc(size);
}
static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context)
{
(void)context;
return erealloc(ptr, size);
}
static inline void igbinary_mm_wrapper_free(void *ptr, void *context)
{
(void)context;
efree(ptr);
}
/* }}} */
/* {{{ int igbinary_serialize(uint8_t**, size_t*, zval*) */
IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z) {
return igbinary_serialize_ex(ret, ret_len, z, NULL);
}
/* }}} */
/* {{{ int igbinary_serialize_ex(uint8_t**, size_t*, zval*, igbinary_memory_manager*) */
IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager) {
struct igbinary_serialize_data igsd;
uint8_t *tmpbuf;
// While we can't get passed references through the PHP_FUNCTIONs igbinary declares, third party code can call us igbinary's methods with references.
// See https://github.com/php-memcached-dev/php-memcached/issues/326
if (Z_TYPE_P(z) == IS_INDIRECT) {
z = Z_INDIRECT_P(z);
}
ZVAL_DEREF(z);
if (igbinary_serialize_data_init(&igsd, Z_TYPE_P(z) != IS_OBJECT && Z_TYPE_P(z) != IS_ARRAY, memory_manager)) {
zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
return 1;
}
if (igbinary_serialize_header(&igsd) != 0) {
zend_error(E_WARNING, "igbinary_serialize: cannot write header");
igbinary_serialize_data_deinit(&igsd, 1);
return 1;
}
if (igbinary_serialize_zval(&igsd, z) != 0) {
igbinary_serialize_data_deinit(&igsd, 1);
return 1;
}
/* Explicit nul termination */
if (igbinary_serialize8(&igsd, 0) != 0) {
igbinary_serialize_data_deinit(&igsd, 1);
return 1;
}
/* shrink buffer to the real length, ignore errors */
tmpbuf = (uint8_t *) igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context);
if (tmpbuf != NULL) {
igsd.buffer = tmpbuf;
}
/* Set return values */
*ret_len = igsd.buffer_size - 1;
*ret = igsd.buffer;
igbinary_serialize_data_deinit(&igsd, 0);
return 0;
}
/* }}} */
/* {{{ int igbinary_unserialize(const uint8_t *, size_t, zval **) */
IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval *z) {
struct igbinary_unserialize_data igsd;
igbinary_unserialize_data_init(&igsd);
igsd.buffer = buf;
igsd.buffer_ptr = buf;
igsd.buffer_end = buf + buf_len;
if (igbinary_unserialize_header(&igsd)) {
igbinary_unserialize_data_deinit(&igsd);
return 1;
}
if (igbinary_unserialize_zval(&igsd, z, WANT_CLEAR)) {
igbinary_unserialize_data_deinit(&igsd);
return 1;
}
if (igbinary_finish_wakeup(&igsd)) {
igbinary_unserialize_data_deinit(&igsd);
return 1;
}
igbinary_unserialize_data_deinit(&igsd);
return 0;
}
/* }}} */
/* {{{ proto string igbinary_unserialize(mixed value) */
PHP_FUNCTION(igbinary_unserialize) {
char *string = NULL;
size_t string_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &string, &string_len) == FAILURE) {
RETURN_NULL();
}
if (string_len <= 0) {
RETURN_FALSE;
}
if (igbinary_unserialize((uint8_t *) string, string_len, return_value) != 0) {
/* FIXME: is this a good place? a catch all */
zval_ptr_dtor(return_value);
RETURN_NULL();
}
}
/* }}} */
/* {{{ proto mixed igbinary_serialize(string value) */
PHP_FUNCTION(igbinary_serialize) {
zval *z;
uint8_t *string;
size_t string_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &z) == FAILURE) {
RETURN_NULL();
}
if (igbinary_serialize(&string, &string_len, z) != 0) {
RETURN_NULL();
}
RETVAL_STRINGL((char *)string, string_len);
efree(string);
}
/* }}} */
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
/* {{{ Serializer encode function */
PS_SERIALIZER_ENCODE_FUNC(igbinary)
{
zval* session_vars;
zend_string *result;
struct igbinary_serialize_data igsd;
session_vars = &(PS(http_session_vars));
if (Z_ISREF_P(session_vars)) {
session_vars = Z_REFVAL_P(session_vars);
}
if (Z_TYPE_P(session_vars) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(session_vars)) == 0) {
return ZSTR_EMPTY_ALLOC();
}
if (igbinary_serialize_data_init(&igsd, false, NULL)) {
zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
return ZSTR_EMPTY_ALLOC();
}
if (igbinary_serialize_header(&igsd) != 0) {
zend_error(E_WARNING, "igbinary_serialize: cannot write header");
igbinary_serialize_data_deinit(&igsd, 1);
return ZSTR_EMPTY_ALLOC();
}
if (igbinary_serialize_array(&igsd, session_vars, false, false) != 0) {
igbinary_serialize_data_deinit(&igsd, 1);
zend_error(E_WARNING, "igbinary_serialize: cannot serialize session variables");
return ZSTR_EMPTY_ALLOC();
}
/* Copy the buffer to a new zend_string */
/* TODO: Clean up igsd->mm, and make this a pointer swap instead? It's only used for building up the serialization data buffer. */
result = zend_string_init((const char*)igsd.buffer, igsd.buffer_size, 0);
igbinary_serialize_data_deinit(&igsd, 1);
return result;
}
/* }}} */
/* {{{ Serializer decode function */
/* This is similar to PS_SERIALIZER_DECODE_FUNC(php) from ext/session/session.c */
PS_SERIALIZER_DECODE_FUNC(igbinary) {
HashTable *tmp_hash;
zval z;
zval *d;
zend_string *key;
struct igbinary_unserialize_data igsd;
if (!val || vallen==0) {
return SUCCESS;
}
if (igbinary_unserialize_data_init(&igsd) != 0) {
return FAILURE;
}
igsd.buffer = (const uint8_t*) val;
igsd.buffer_ptr = igsd.buffer;
igsd.buffer_end = igsd.buffer + vallen;
if (igbinary_unserialize_header(&igsd)) {
igbinary_unserialize_data_deinit(&igsd);
return FAILURE;
}
if (igbinary_unserialize_zval(&igsd, &z, WANT_CLEAR)) {
igbinary_unserialize_data_deinit(&igsd);
return FAILURE;
}
if (igbinary_finish_wakeup(&igsd)) {
igbinary_unserialize_data_deinit(&igsd);
return FAILURE;
}
igbinary_unserialize_data_deinit(&igsd);
tmp_hash = HASH_OF(&z);
if (tmp_hash == NULL) {
zval_ptr_dtor(&z);
return FAILURE;
}
ZEND_HASH_FOREACH_STR_KEY_VAL(tmp_hash, key, d) {
if (key == NULL) { /* array key is a number, how? Skip it. */
/* ??? */
continue;
}
if (php_set_session_var(key, d, NULL)) { /* Added to session successfully */
/* Refcounted types such as arrays, objects, references need to have references incremented manually, so that zval_ptr_dtor doesn't clean up pointers they include. */
/* Non-refcounted types have the data copied. */
Z_TRY_ADDREF_P(d);
}
} ZEND_HASH_FOREACH_END();
zval_ptr_dtor(&z);
return SUCCESS;
}
/* }}} */
#endif /* HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) */
#if defined(HAVE_APCU_SUPPORT)
/* {{{ apc_serialize function */
static int APC_SERIALIZER_NAME(igbinary) ( APC_SERIALIZER_ARGS ) {
(void)config;
if (igbinary_serialize(buf, buf_len, (zval *)value) == 0) {
/* flipped semantics */
return 1;
}
return 0;
}
/* }}} */
/* {{{ apc_unserialize function */
static int APC_UNSERIALIZER_NAME(igbinary) ( APC_UNSERIALIZER_ARGS ) {
(void)config;
if (igbinary_unserialize(buf, buf_len, value) == 0) {
/* flipped semantics - Succeeded. */
return 1;
}
/* Failed. free return value */
zval_ptr_dtor(value);
ZVAL_NULL(value); /* and replace the incomplete value with null just in case APCU uses it in the future */
return 0;
}
/* }}} */
#endif
/* {{{ igbinary_serialize_data_init */
/** Inits igbinary_serialize_data. */
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager) {
int r = 0;
if (memory_manager == NULL) {
igsd->mm.alloc = igbinary_mm_wrapper_malloc;
igsd->mm.realloc = igbinary_mm_wrapper_realloc;
igsd->mm.free = igbinary_mm_wrapper_free;
igsd->mm.context = NULL;
} else {
igsd->mm = *memory_manager;
}
igsd->buffer = NULL;
igsd->buffer_size = 0;
igsd->buffer_capacity = 32;
igsd->string_count = 0;
igsd->error = 0;
igsd->buffer = (uint8_t *) igsd->mm.alloc(igsd->buffer_capacity, igsd->mm.context);
if (igsd->buffer == NULL) {
return 1;
}
igsd->scalar = scalar;
if (!igsd->scalar) {
hash_si_init(&igsd->strings, 16);
hash_si_ptr_init(&igsd->references, 16);
igsd->references_id = 0;
}
igsd->compact_strings = (bool)IGBINARY_G(compact_strings);
return r;
}
/* }}} */
/* {{{ igbinary_serialize_data_deinit */
/** Deinits igbinary_serialize_data. */
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer) {
if (free_buffer && igsd->buffer) {
igsd->mm.free(igsd->buffer, igsd->mm.context);
}
if (!igsd->scalar) {
hash_si_deinit(&igsd->strings);
hash_si_ptr_deinit(&igsd->references);
}
}
/* }}} */
/* {{{ igbinary_serialize_header */
/** Serializes header. */
inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd) {
return igbinary_serialize32(igsd, IGBINARY_FORMAT_VERSION); /* version */
}
/* }}} */
/* {{{ igbinary_serialize_resize */
/** Expands igbinary_serialize_data. */
inline static int igbinary_serialize_resize(struct igbinary_serialize_data *igsd, size_t size) {
if (igsd->buffer_size + size < igsd->buffer_capacity) {
return 0;
}
while (igsd->buffer_size + size >= igsd->buffer_capacity) {
igsd->buffer_capacity *= 2;
}
igsd->buffer = (uint8_t *) igsd->mm.realloc(igsd->buffer, igsd->buffer_capacity, igsd->mm.context);
if (igsd->buffer == NULL)
return 1;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize8 */
/** Serialize 8bit value. */
inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i) {
if (UNEXPECTED(igbinary_serialize_resize(igsd, 1))) {
return 1;
}
igsd->buffer[igsd->buffer_size++] = i;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize16 */
/** Serialize 16bit value. */
inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i) {
uint8_t* append_buffer;
if (UNEXPECTED(igbinary_serialize_resize(igsd, 2))) {
return 1;
}
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = (uint8_t) (i >> 8 & 0xff);
append_buffer[1] = (uint8_t) (i & 0xff);
igsd->buffer_size += 2;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize32 */
/** Serialize 32bit value. */
inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i) {
uint8_t* append_buffer;
if (UNEXPECTED(igbinary_serialize_resize(igsd, 4))) {
return 1;
}
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = (uint8_t) (i >> 24 & 0xff);
append_buffer[1] = (uint8_t) (i >> 16 & 0xff);
append_buffer[2] = (uint8_t) (i >> 8 & 0xff);
append_buffer[3] = (uint8_t) (i & 0xff);
igsd->buffer_size += 4;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize64 */
/** Serialize 64bit value. */
inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i) {
uint8_t* append_buffer;
if (UNEXPECTED(igbinary_serialize_resize(igsd, 8))) {
return 1;
}
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = (uint8_t) (i >> 56 & 0xff);
append_buffer[1] = (uint8_t) (i >> 48 & 0xff);
append_buffer[2] = (uint8_t) (i >> 40 & 0xff);
append_buffer[3] = (uint8_t) (i >> 32 & 0xff);
append_buffer[4] = (uint8_t) (i >> 24 & 0xff);
append_buffer[5] = (uint8_t) (i >> 16 & 0xff);
append_buffer[6] = (uint8_t) (i >> 8 & 0xff);
append_buffer[7] = (uint8_t) (i & 0xff);
igsd->buffer_size += 8;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_null */
/** Serializes null. */
inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd) {
return igbinary_serialize8(igsd, igbinary_type_null);
}
/* }}} */
/* {{{ igbinary_serialize_bool */
/** Serializes bool. */
inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b) {
return igbinary_serialize8(igsd, (uint8_t) (b ? igbinary_type_bool_true : igbinary_type_bool_false));
}
/* }}} */
/* {{{ igbinary_serialize_long */
/** Serializes zend_long. */
inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, zend_long l) {
zend_long k = l >= 0 ? l : -l;
bool p = l >= 0;
/* -ZEND_LONG_MIN is 0 otherwise. */
if (l == ZEND_LONG_MIN) {
#if SIZEOF_ZEND_LONG == 8
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long64n) != 0) {
return 1;
}
if (igbinary_serialize64(igsd, (uint64_t) 0x8000000000000000) != 0) {
return 1;
}
#elif SIZEOF_ZEND_LONG == 4
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long32n) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) 0x80000000) != 0) {
return 1;
}
#else
#error "Strange sizeof(zend_long)."
#endif
return 0;
}
if (k <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long8p : igbinary_type_long8n)) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) k) != 0) {
return 1;
}
} else if (k <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long16p : igbinary_type_long16n)) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) k) != 0) {
return 1;
}
#if SIZEOF_ZEND_LONG == 8
} else if (k <= 0xffffffff) {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n)) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) k) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long64p : igbinary_type_long64n)) != 0) {
return 1;
}
if (igbinary_serialize64(igsd, (uint64_t) k) != 0) {
return 1;
}
}
#elif SIZEOF_ZEND_LONG == 4
} else {
if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n)) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) k) != 0) {
return 1;
}
}
#else
#error "Strange sizeof(zend_long)."
#endif
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_double */
/** Serializes double. */
inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d) {
union {
double d;
uint64_t u;
} u;
if (igbinary_serialize8(igsd, igbinary_type_double) != 0) {
return 1;
}
u.d = d;
return igbinary_serialize64(igsd, u.u);
}
/* }}} */
/* {{{ igbinary_serialize_string */
/** Serializes string.
* Serializes each string once, after first time uses pointers.
*/
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, zend_string *s) {
const size_t len = ZSTR_LEN(s);
if (len == 0) {
if (igbinary_serialize8(igsd, igbinary_type_string_empty) != 0) {
return 1;
}
return 0;
}
if (!igsd->scalar && igsd->compact_strings) {
struct hash_si_result result = hash_si_find_or_insert(&igsd->strings, s, igsd->string_count);
if (result.code == hash_si_code_exists) {
uint32_t value = result.value;
if (value <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id8) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) value) != 0) {
return 1;
}
} else if (value <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id16) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) value) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id32) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) value) != 0) {
return 1;
}
}
return 0;
} else if (EXPECTED(result.code == hash_si_code_inserted)) {
/* Fall through to igbinary_serialize_chararray */
} else {
return 1; /* Failed to allocate copy of string */
}
}
igsd->string_count++; /* A new string is being serialized - update count so that duplicate class names can be used. */
if (igbinary_serialize_chararray(igsd, ZSTR_VAL(s), len) != 0) {
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_chararray */
/** Serializes string data. */
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len) {
if (len <= 0xff) {
if (igbinary_serialize8(igsd, igbinary_type_string8) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, len) != 0) {
return 1;
}
} else if (len <= 0xffff) {
if (igbinary_serialize8(igsd, igbinary_type_string16) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, len) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, igbinary_type_string32) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, len) != 0) {
return 1;
}
}
if (igbinary_serialize_resize(igsd, len)) {
return 1;
}
memcpy(igsd->buffer+igsd->buffer_size, s, len);
igsd->buffer_size += len;
return 0;
}
/* }}} */
/* {{{ igbinay_serialize_array */
/** Serializes array or objects inner properties. */
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class) {
/* If object=true: z is IS_OBJECT */
/* If object=false: z is either IS_ARRAY, or IS_REFERENCE pointing to an IS_ARRAY. */
HashTable *h;
size_t n;
zval *d;
zval *z_original;
zend_string *key;
zend_long key_index;
z_original = z;
ZVAL_DEREF(z);
/* hash */
h = object ? Z_OBJPROP_P(z) : HASH_OF(z);
/* hash size */
n = h ? zend_hash_num_elements(h) : 0;
/* incomplete class magic member */
if (n > 0 && incomplete_class) {
--n;
}
/* if it is an array or a reference to an array, then add a reference unique to that **reference** to that array */
if (!object && igbinary_serialize_array_ref(igsd, z_original, false) == 0) {
return 0;
}
if (n <= 0xff) {
if (igbinary_serialize8(igsd, igbinary_type_array8) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, n) != 0) {
return 1;
}
} else if (n <= 0xffff) {
if (igbinary_serialize8(igsd, igbinary_type_array16) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, n) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, igbinary_type_array32) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, n) != 0) {
return 1;
}
}
if (n == 0) {
return 0;
}
/* serialize properties. */
ZEND_HASH_FOREACH_KEY_VAL(h, key_index, key, d) {
/* skip magic member in incomplete classes */
if (incomplete_class && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) {
continue;
}
if (key == NULL) {
/* Key is numeric */
if (igbinary_serialize_long(igsd, key_index) != 0) {
return 1;
}
} else {
/* Key is string */
if (igbinary_serialize_string(igsd, key) != 0) {
return 1;
}
}
if (d == NULL) {
php_error_docref(NULL, E_NOTICE, "Received NULL value from hash.");
return 1;
}
/* https://wiki.php.net/phpng-int - This is a weak pointer, completely different from a PHP reference (&$foo has a type of IS_REFERENCE) */
if (Z_TYPE_P(d) == IS_INDIRECT) {
d = Z_INDIRECT_P(d);
}
/* we should still add element even if it's not OK,
* since we already wrote the length of the array before */
if (Z_TYPE_P(d) == IS_UNDEF) {
if (igbinary_serialize_null(igsd)) {
return 1;
}
} else {
if (igbinary_serialize_zval(igsd, d)) {
return 1;
}
}
} ZEND_HASH_FOREACH_END();
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_array_ref */
/** Serializes array reference (or reference in an object). Returns 0 on success. */
inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object) {
size_t t;
zend_uintptr_t key; /* The address of the pointer to the zend_refcounted struct or other struct */
static int INVALID_KEY; /* Not used, but we take the pointer of this knowing other zvals wont share it*/
/* Similar to php_var_serialize_intern's first part, as well as php_add_var_hash, for printing R: (reference) or r:(object) */
/* However, it differs from the built in serialize() in that references to objects are preserved when serializing and unserializing? (TODO check, test for backwards compatibility) */
zend_bool is_ref = Z_ISREF_P(z);
/* Do I have to dereference object references so that reference ids will be the same as in php5? */
/* If I do, then more tests fail. */
/* is_ref || IS_OBJECT implies it has a unique refcounted struct */
if (object && Z_TYPE_P(z) == IS_OBJECT) {
key = (zend_uintptr_t) Z_OBJ_HANDLE_P(z); /* expand object handle(uint32_t), cast to 32-bit/64-bit pointer */
} else if (is_ref) {
/* NOTE: PHP removed switched from `zval*` to `zval` for the values stored in HashTables. If an array has two references to the same ZVAL, then those references will have different zvals. We use Z_COUNTED_P(ref), which will be the same iff the references are the same */
/* IS_REF implies there is a unique reference counting pointer for the reference */
key = (zend_uintptr_t) Z_COUNTED_P(z);
} else if (Z_TYPE_P(z) == IS_ARRAY) {
if (Z_REFCOUNTED_P(z)) {
key = (zend_uintptr_t) Z_COUNTED_P(z);
} else { /* Not sure if this could be a constant */
key = (zend_uintptr_t) z;
}
} else {
/* Nothing else is going to reference this when this is serialized, this isn't ref counted or an object, shouldn't be reached. */
/* Increment the reference id for the deserializer, give up. */
++igsd->references_id;
php_error_docref(NULL, E_NOTICE, "igbinary_serialize_array_ref expected either object or reference (param object=%s), got neither (zend_type=%d)", object ? "true" : "false", (int)Z_TYPE_P(z));
return 1;
}
/* FIXME hack? If the top-level element was an array, we assume that it can't be a reference when we serialize it, */
/* because that's the way it was serialized in php5. */
/* Does this work with different forms of recursive arrays? */
if (igsd->references_id == 0 && !object) {
key = (zend_uintptr_t)&INVALID_KEY;
}
t = hash_si_ptr_find_or_insert(&igsd->references, key, igsd->references_id);
if (t == SIZE_MAX) {
igsd->references_id++;
return 1;
} else {
enum igbinary_type type;
if (t <= 0xff) {
type = object ? igbinary_type_objref8 : igbinary_type_ref8;
if (igbinary_serialize8(igsd, (uint8_t) type) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) t) != 0) {
return 1;
}
} else if (t <= 0xffff) {
type = object ? igbinary_type_objref16 : igbinary_type_ref16;
if (igbinary_serialize8(igsd, (uint8_t) type) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) t) != 0) {
return 1;
}
} else {
type = object ? igbinary_type_objref32 : igbinary_type_ref32;
if (igbinary_serialize8(igsd, (uint8_t) type) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) t) != 0) {
return 1;
}
}
return 0;
}
return 1;
}
/* }}} */
/* {{{ igbinary_serialize_array_sleep */
/** Serializes object's properties array with __sleep -function. */
inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *h, zend_class_entry *ce, bool incomplete_class) {
HashTable *object_properties;
size_t n = zend_hash_num_elements(h);
zval *d;
zval *v;
zend_string *key;
/* Decrease array size by one, because of magic member (with class name) */
if (n > 0 && incomplete_class) {
--n;
}
/* Serialize array id. */
if (n <= 0xff) {
if (igbinary_serialize8(igsd, igbinary_type_array8) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, n) != 0) {
return 1;
}
} else if (n <= 0xffff) {
if (igbinary_serialize8(igsd, igbinary_type_array16) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, n) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, igbinary_type_array32) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, n) != 0) {
return 1;
}
}
if (n == 0) {
return 0;
}
object_properties = Z_OBJPROP_P(z);
ZEND_HASH_FOREACH_STR_KEY_VAL(h, key, d) {
/* skip magic member in incomplete classes */
if (incomplete_class && key != NULL && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) {
continue;
}
if (d == NULL || Z_TYPE_P(d) != IS_STRING) {
php_error_docref(NULL, E_NOTICE, "__sleep should return an array only "
"containing the names of instance-variables to "
"serialize");
/* we should still add element even if it's not OK,
* since we already wrote the length of the array before
* serialize null as key-value pair */
if (igbinary_serialize_null(igsd) != 0) {
return 1;
}
} else {
zend_string *prop_name = Z_STR_P(d);
if ((v = zend_hash_find(object_properties, prop_name)) != NULL) {
if (igbinary_serialize_string(igsd, prop_name) != 0) {
return 1;
}
if (Z_TYPE_P(v) == IS_INDIRECT) {
v = Z_INDIRECT_P(v);
}
if (igbinary_serialize_zval(igsd, v) != 0) {
return 1;
}
} else if (ce) {
zend_string *mangled_prop_name;
v = NULL;
do {
/* try private */
// TODO: check for FAILURE
mangled_prop_name = zend_mangle_property_name(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), ce->type & ZEND_INTERNAL_CLASS);
v = zend_hash_find(object_properties, mangled_prop_name);
/* try protected */
if (v == NULL) {
zend_string_release(mangled_prop_name);
mangled_prop_name = zend_mangle_property_name("*", 1,
ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), ce->type & ZEND_INTERNAL_CLASS);
v = zend_hash_find(object_properties, mangled_prop_name);
}
/* Neither property exist */
if (v == NULL) {
zend_string_release(mangled_prop_name);
php_error_docref(NULL, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", Z_STRVAL_P(d));
if (igbinary_serialize_string(igsd, Z_STR_P(d)) != 0) {
return 1;
}
if (igbinary_serialize_null(igsd) != 0) {
return 1;
}
break;
}
if (Z_TYPE_P(v) == IS_INDIRECT) {
v = Z_INDIRECT_P(v);
}
if (igbinary_serialize_string(igsd, mangled_prop_name) != 0) {
zend_string_release(mangled_prop_name);
return 1;
}
zend_string_release(mangled_prop_name);
if (igbinary_serialize_zval(igsd, v) != 0) {
return 1;
}
} while (0);
} else {
/* if all else fails, just serialize the value in anyway. */
if (igbinary_serialize_string(igsd, Z_STR_P(d)) != 0) {
return 1;
}
if (Z_TYPE_P(v) == IS_INDIRECT) {
v = Z_INDIRECT_P(v);
}
if (igbinary_serialize_zval(igsd, v) != 0) {
return 1;
}
}
}
} ZEND_HASH_FOREACH_END();
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_object_name */
/** Serialize object name. */
inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, zend_string *class_name) {
struct hash_si_result result = hash_si_find_or_insert(&igsd->strings, class_name, igsd->string_count);
if (result.code == hash_si_code_inserted) {
const size_t name_len = ZSTR_LEN(class_name);
igsd->string_count += 1;
if (name_len <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object8) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) name_len) != 0) {
return 1;
}
} else if (name_len <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object16) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) name_len) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object32) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) name_len) != 0) {
return 1;
}
}
if (igbinary_serialize_resize(igsd, name_len)) {
return 1;
}
memcpy(igsd->buffer+igsd->buffer_size, ZSTR_VAL(class_name), name_len);
igsd->buffer_size += name_len;
} else if (EXPECTED(result.code == hash_si_code_exists)) {
/* already serialized string */
uint32_t value = result.value;
if (value <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id8) != 0) {
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) value) != 0) {
return 1;
}
} else if (value <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id16) != 0) {
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) value) != 0) {
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id32) != 0) {
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) value) != 0) {
return 1;
}
}
} else {
return 1; /* Failed to allocate copy of string */
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_object */
/** Serialize object.
* @see ext/standard/var.c
* */
inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z) {
PHP_CLASS_ATTRIBUTES;
zend_class_entry *ce;
zval f;
zval h;
int r = 0;
unsigned char *serialized_data = NULL;
size_t serialized_len;
if (igbinary_serialize_array_ref(igsd, z, true) == 0) {
return 0;
}
ce = Z_OBJCE_P(z);
/* custom serializer */
if (ce && ce->serialize != NULL) {
if (ce->serialize(z, &serialized_data, &serialized_len, (zend_serialize_data *)NULL) == SUCCESS && !EG(exception)) {
if (igbinary_serialize_object_name(igsd, ce->name) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (serialized_len <= 0xff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser8) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (igbinary_serialize8(igsd, (uint8_t) serialized_len) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
} else if (serialized_len <= 0xffff) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser16) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (igbinary_serialize16(igsd, (uint16_t) serialized_len) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
} else {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser32) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
if (igbinary_serialize32(igsd, (uint32_t) serialized_len) != 0) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
}
if (igbinary_serialize_resize(igsd, serialized_len)) {
if (serialized_data) {
efree(serialized_data);
}
return 1;
}
memcpy(igsd->buffer+igsd->buffer_size, serialized_data, serialized_len);
igsd->buffer_size += serialized_len;
} else if (EG(exception)) {
/* exception, return failure */
r = 1;
} else {
/* Serialization callback failed, assume null output */
r = igbinary_serialize_null(igsd);
}
if (serialized_data) {
efree(serialized_data);
}
return r;
}
/* serialize class name */
PHP_SET_CLASS_ATTRIBUTES(z);
if (igbinary_serialize_object_name(igsd, class_name) != 0) {
PHP_CLEANUP_CLASS_ATTRIBUTES();
return 1;
}
PHP_CLEANUP_CLASS_ATTRIBUTES();
if (ce && ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep") - 1)) {
/* function name string */
ZVAL_STRINGL(&f, "__sleep", sizeof("__sleep") - 1);
ZVAL_UNDEF(&h);
/* calling z->__sleep */
r = call_user_function_ex(CG(function_table), z, &f, &h, 0, 0, 1, NULL);
zval_dtor(&f);
if (r == SUCCESS && !EG(exception)) {
r = 0;
if (Z_TYPE(h) == IS_UNDEF) {
/* FIXME: is this ok? */
/* Valid, but skip */
} else if (HASH_OF(&h)) {
r = igbinary_serialize_array_sleep(igsd, z, HASH_OF(&h), ce, incomplete_class);
} else {
php_error_docref(NULL, E_NOTICE, "__sleep should return an array only "
"containing the names of instance-variables to "
"serialize");
/* empty array */
r = igbinary_serialize8(igsd, igbinary_type_array8);
if (r == 0) {
r = igbinary_serialize8(igsd, 0);
}
}
} else {
r = 1;
}
/* cleanup */
zval_ptr_dtor(&h);
return r;
} else {
return igbinary_serialize_array(igsd, z, true, incomplete_class);
}
}
/* }}} */
/* {{{ igbinary_serialize_zval */
/** Serialize zval. */
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z) {
if (Z_ISREF_P(z)) {
if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_ref) != 0) {
return 1;
}
switch (Z_TYPE_P(Z_REFVAL_P(z))) {
case IS_ARRAY:
return igbinary_serialize_array(igsd, z, false, false);
case IS_OBJECT:
break; /* Fall through */
default:
/* Serialize a reference if zval already added */
if (igbinary_serialize_array_ref(igsd, z, false) == 0) {
return 0;
}
/* Fall through */
}
ZVAL_DEREF(z);
}
switch (Z_TYPE_P(z)) {
case IS_RESOURCE:
return igbinary_serialize_null(igsd);
case IS_OBJECT:
return igbinary_serialize_object(igsd, z);
case IS_ARRAY:
/* if is_ref, then php5 would have called igbinary_serialize_array_ref */
return igbinary_serialize_array(igsd, z, false, false);
case IS_STRING:
return igbinary_serialize_string(igsd, Z_STR_P(z));
case IS_LONG:
return igbinary_serialize_long(igsd, Z_LVAL_P(z));
case IS_NULL:
return igbinary_serialize_null(igsd);
case IS_UNDEF:
// As of php 7.1.3, started seeing "zval has unknown type 0"
zend_error(E_WARNING, "igbinary_serialize_zval: zval has unexpected type IS_UNDEF(0)");
return igbinary_serialize_null(igsd);
case IS_TRUE:
return igbinary_serialize_bool(igsd, 1);
case IS_FALSE:
return igbinary_serialize_bool(igsd, 0);
case IS_DOUBLE:
return igbinary_serialize_double(igsd, Z_DVAL_P(z));
default:
zend_error(E_ERROR, "igbinary_serialize_zval: zval has unknown type %d", (int)Z_TYPE_P(z));
/* not reached */
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_data_init */
/** Inits igbinary_unserialize_data_init. */
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd) {
smart_string empty_str = { 0 };
igsd->buffer = NULL;
igsd->buffer_end = NULL;
igsd->buffer_ptr = NULL;
igsd->strings = NULL;
igsd->strings_count = 0;
igsd->strings_capacity = 4;
igsd->string0_buf = empty_str;
igsd->error = 0;
igsd->references = NULL;
igsd->references_count = 0;
igsd->references_capacity = 4;
igsd->references = emalloc(sizeof(igsd->references[0]) * igsd->references_capacity);
if (igsd->references == NULL) {
return 1;
}
igsd->strings = (zend_string **) emalloc(sizeof(zend_string *) * igsd->strings_capacity);
if (igsd->strings == NULL) {
efree(igsd->references);
igsd->references = NULL;
return 1;
}
/** Don't bother allocating zvals which __wakeup, probably not common */
igsd->wakeup = NULL;
igsd->wakeup_count = 0;
igsd->wakeup_capacity = 0;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_data_deinit */
/** Deinits igbinary_unserialize_data_init. */
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd) {
if (igsd->strings) {
size_t i;
for (i = 0; i < igsd->strings_count; i++) {
zend_string *s = igsd->strings[i];
#if ZEND_DEBUG
ZEND_ASSERT(GC_REFCOUNT(s) >= 1);
#endif
zend_string_release(s);
}
efree(igsd->strings);
igsd->strings = NULL;
}
if (igsd->references) {
efree(igsd->references);
igsd->references = NULL;
}
if (igsd->wakeup) {
/*
size_t i;
size_t n = igsd->wakeup_count;
for (i = 0; i < n; i++) {
convert_to_null(&igsd->wakeup[i]);
}
*/
efree(igsd->wakeup);
}
smart_string_free(&igsd->string0_buf);
return;
}
/* }}} */
/* {{{ igbinary_unserialize_header_emit_warning */
/* Precondition: igsd->buffer_size >= 4 */
inline static void igbinary_unserialize_header_emit_warning(struct igbinary_unserialize_data *igsd, int version) {
int i;
char buf[9], *it;
for (i = 0; i < 4; i++) {
if (!isprint((int)igsd->buffer[i])) {
if (version != 0 && (((unsigned int)version) & 0xff000000) == (unsigned int)version) {
// Check if high order byte was set instead of low order byte
zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: %u, should be %u or %u (wrong endianness?)", (unsigned int) version, 0x00000001, (unsigned int) IGBINARY_FORMAT_VERSION);
return;
}
// Binary data, or a version number from a future release.
zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: %u, should be %u or %u", (unsigned int) version, 0x00000001, (unsigned int) IGBINARY_FORMAT_VERSION);
return;
}
}
for (it = buf, i = 0; i < 4; i++) {
char c = igsd->buffer[i];
if (c == '"' || c == '\\') {
*it++ = '\\';
}
*it++ = c;
}
*it = '\0';
zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: \"%s\"..., should begin with a binary version header of \"\\x00\\x00\\x00\\x01\" or \"\\x00\\x00\\x00\\x%02x\"", buf, (int)IGBINARY_FORMAT_VERSION);
}
/* }}} */
/* {{{ igbinary_unserialize_header */
/** Unserialize header. Check for version. */
inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd) {
uint32_t version;
if (IGB_NEEDS_MORE_DATA(igsd, 5)) {
zend_error(E_WARNING, "igbinary_unserialize_header: expected at least 5 bytes of data, got %u byte(s)", IGB_REMAINING_BYTES(igsd));
return 1;
}
version = igbinary_unserialize32(igsd);
/* Support older version 1 and the current format 2 */
if (version == IGBINARY_FORMAT_VERSION || version == 0x00000001) {
return 0;
} else {
igbinary_unserialize_header_emit_warning(igsd, version);
return 1;
}
}
/* }}} */
/* {{{ igbinary_unserialize8 */
/** Unserialize 8bit value. */
inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd) {
return *(igsd->buffer_ptr++);
}
/* }}} */
/* {{{ igbinary_unserialize16 */
/** Unserialize 16bit value. */
inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd) {
uint16_t ret =
((uint16_t) (igsd->buffer_ptr[0]) << 8) |
((uint16_t) (igsd->buffer_ptr[1]));
igsd->buffer_ptr += 2;
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize32 */
/** Unserialize 32bit value. */
inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd) {
uint32_t ret =
((uint32_t) (igsd->buffer_ptr[0]) << 24) |
((uint32_t) (igsd->buffer_ptr[1]) << 16) |
((uint32_t) (igsd->buffer_ptr[2]) << 8) |
((uint32_t) (igsd->buffer_ptr[3]));
igsd->buffer_ptr += 4;
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize64 */
/** Unserialize 64bit value. */
inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd) {
uint64_t ret =
((uint64_t) ((igsd->buffer_ptr[0])) << 56) |
((uint64_t) ((igsd->buffer_ptr[1])) << 48) |
((uint64_t) ((igsd->buffer_ptr[2])) << 40) |
((uint64_t) ((igsd->buffer_ptr[3])) << 32) |
((uint64_t) ((igsd->buffer_ptr[4])) << 24) |
((uint64_t) ((igsd->buffer_ptr[5])) << 16) |
((uint64_t) ((igsd->buffer_ptr[6])) << 8) |
((uint64_t) ((igsd->buffer_ptr[7])) << 0);
igsd->buffer_ptr += 8;
return ret;
}
/* }}} */
/* {{{ igbinary_unserialize_long */
/** Unserializes zend_long */
inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zend_long *ret) {
uint32_t tmp32;
#if SIZEOF_ZEND_LONG == 8
uint64_t tmp64;
#endif
if (t == igbinary_type_long8p || t == igbinary_type_long8n) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
*ret = (zend_long) (t == igbinary_type_long8n ? -1 : 1) * igbinary_unserialize8(igsd);
} else if (t == igbinary_type_long16p || t == igbinary_type_long16n) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
*ret = (zend_long) (t == igbinary_type_long16n ? -1 : 1) * igbinary_unserialize16(igsd);
} else if (t == igbinary_type_long32p || t == igbinary_type_long32n) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
/* check for boundaries */
tmp32 = igbinary_unserialize32(igsd);
#if SIZEOF_ZEND_LONG == 4
if (tmp32 > 0x80000000 || (tmp32 == 0x80000000 && t == igbinary_type_long32p)) {
zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform?");
tmp32 = 0; /* t == igbinary_type_long32p ? LONG_MAX : LONG_MIN; */
}
#endif
*ret = (zend_long) (t == igbinary_type_long32n ? -1 : 1) * tmp32;
} else if (t == igbinary_type_long64p || t == igbinary_type_long64n) {
#if SIZEOF_ZEND_LONG == 8
if (IGB_NEEDS_MORE_DATA(igsd, 8)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
/* check for boundaries */
tmp64 = igbinary_unserialize64(igsd);
if (tmp64 > 0x8000000000000000 || (tmp64 == 0x8000000000000000 && t == igbinary_type_long64p)) {
zend_error(E_WARNING, "igbinary_unserialize_long: too big 64bit long.");
tmp64 = 0; /* t == igbinary_type_long64p ? LONG_MAX : LONG_MIN */;
}
*ret = (zend_long) (t == igbinary_type_long64n ? -1 : 1) * tmp64;
#elif SIZEOF_ZEND_LONG == 4
/* can't put 64bit long into 32bit one, placeholder zero */
*ret = 0;
igbinary_unserialize64(igsd);
zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform");
#else
#error "Strange sizeof(zend_long)."
#endif
} else {
*ret = 0;
zend_error(E_WARNING, "igbinary_unserialize_long: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_double */
/** Unserializes double. */
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret) {
union {
double d;
uint64_t u;
} u;
(void) t;
if (IGB_NEEDS_MORE_DATA(igsd, 8)) {
zend_error(E_WARNING, "igbinary_unserialize_double: end-of-data");
return 1;
}
u.u = igbinary_unserialize64(igsd);
*ret = u.d;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_string */
/** Unserializes string. Unserializes both actual string or by string id. Returns NULL on error. */
inline static zend_string* igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t) {
size_t i;
zend_string *zstr;
if (t == igbinary_type_string_id8 || t == igbinary_type_object_id8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
return NULL;
}
i = igbinary_unserialize8(igsd);
} else if (t == igbinary_type_string_id16 || t == igbinary_type_object_id16) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
return NULL;
}
i = igbinary_unserialize16(igsd);
} else if (t == igbinary_type_string_id32 || t == igbinary_type_object_id32) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
return NULL;
}
i = igbinary_unserialize32(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_string: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return NULL;
}
if (i >= igsd->strings_count) {
zend_error(E_WARNING, "igbinary_unserialize_string: string index is out-of-bounds");
return NULL;
}
zstr = igsd->strings[i];
// Add one more ref - Callers of this will decrease refs as needed
zend_string_addref(zstr);
return zstr;
}
/* }}} */
/* {{{ igbinary_unserialize_chararray */
/** Unserializes chararray of string. Returns NULL on error. */
inline static zend_string* igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t) {
size_t l;
zend_string *zstr;
if (t == igbinary_type_string8 || t == igbinary_type_object8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
l = igbinary_unserialize8(igsd);
if (IGB_NEEDS_MORE_DATA(igsd, l)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
/* Requires converting these into interned strings. Maybe add one-char in v3 of igbinary format?
if (l == 1) {
zstr = ZSTR_CHAR((zend_uchar)igsd->buffer[igsd->buffer_offset]);
igsd->strings[igsd->strings_count] = zstr;
igsd->strings_count += 1;
igsd->buffer_offset++;
return zstr;
}
*/
} else if (t == igbinary_type_string16 || t == igbinary_type_object16) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
l = igbinary_unserialize16(igsd);
if (IGB_NEEDS_MORE_DATA(igsd, l)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
} else if (t == igbinary_type_string32 || t == igbinary_type_object32) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
l = igbinary_unserialize32(igsd);
if (IGB_NEEDS_MORE_DATA(igsd, l)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
} else {
zend_error(E_WARNING, "igbinary_unserialize_chararray: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return NULL;
}
if (igsd->strings_count + 1 > igsd->strings_capacity) {
zend_string **new_strings;
igsd->strings_capacity *= 2;
new_strings = (zend_string **) erealloc(igsd->strings, sizeof(zend_string *) * igsd->strings_capacity);
if (new_strings == NULL) {
// The cleanup function will take care of destroying the allocated zend_strings.
return NULL;
}
igsd->strings = new_strings;
}
zstr = zend_string_init((const char*)(igsd->buffer + IGB_BUFFER_OFFSET(igsd)), l, 0);
igsd->buffer_ptr += l;
if (zstr == NULL) {
return NULL;
}
zend_string_addref(zstr);
igsd->strings[igsd->strings_count] = zstr;
igsd->strings_count += 1;
return zstr;
}
/* }}} */
/* {{{ igbinary_unserialize_array */
/** Unserializes array. */
inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags) {
/* WANT_REF means that z will be wrapped by an IS_REFERENCE */
size_t n;
size_t i;
zval v;
zval *vp;
zval *z_deref;
enum igbinary_type key_type;
HashTable *h;
if (t == igbinary_type_array8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd);
} else if (t == igbinary_type_array16) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd);
} else if (t == igbinary_type_array32) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_array: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
/* n cannot be larger than the number of minimum "objects" in the array */
if (IGB_NEEDS_MORE_DATA(igsd, n)) {
zend_error(E_WARNING, "igbinary_unserialize_array: data size %zu smaller that requested array length %zu.", IGB_REMAINING_BYTES(igsd), (unsigned int) n);
return 1;
}
z_deref = z;
if (flags & WANT_REF) {
if (!Z_ISREF_P(z)) {
ZVAL_NEW_REF(z, z);
z_deref = Z_REFVAL_P(z);
}
}
array_init_size(z_deref, n);
{
struct igbinary_value_ref ref;
if (flags & WANT_REF) {
// We converted to reference earlier.
ref.reference.reference = Z_REF_P(z);
ref.type = IG_REF_IS_REFERENCE;
} else {
ref.reference.array = Z_ARR_P(z_deref);
ref.type = IG_REF_IS_ARRAY;
}
/* add the new array to the list of unserialized references */
if (igsd_append_ref(igsd, ref) == SIZE_MAX) {
return 1;
}
}
/* empty array */
if (n == 0) {
return 0;
}
h = HASH_OF(z_deref);
for (i = 0; i < n; i++) {
zend_long key_index = 0;
zend_string *key_str = NULL; /* NULL means use key_index */
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
zval_dtor(z);
ZVAL_NULL(z);
return 1;
}
key_type = (enum igbinary_type) igbinary_unserialize8(igsd);
switch (key_type) {
case igbinary_type_long8p:
case igbinary_type_long8n:
case igbinary_type_long16p:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
if (igbinary_unserialize_long(igsd, key_type, &key_index)) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
break;
case igbinary_type_string_id8:
case igbinary_type_string_id16:
case igbinary_type_string_id32:
key_str = igbinary_unserialize_string(igsd, key_type);
if (key_str == NULL) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
key_str = igbinary_unserialize_chararray(igsd, key_type);
if (key_str == NULL) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
break;
case igbinary_type_string_empty:
key_str = ZSTR_EMPTY_ALLOC();
break;
case igbinary_type_null:
continue;
default:
zend_error(E_WARNING, "igbinary_unserialize_array: unknown key type '%02x', position %zu", key_type, IGB_BUFFER_OFFSET(igsd));
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
/* first add key into array so references can properly and not stack allocated zvals */
/* Use NULL because inserting UNDEF into array does not add a new element */
ZVAL_NULL(&v);
if (key_str != NULL) {
vp = zend_hash_update(h, key_str, &v);
zend_string_release(key_str);
} else {
vp = zend_hash_index_update(h, key_index, &v);
}
ZEND_ASSERT(vp != NULL);
if (Z_TYPE_P(vp) == IS_INDIRECT) {
vp = Z_INDIRECT_P(vp);
}
ZEND_ASSERT(vp != NULL);
if (igbinary_unserialize_zval(igsd, vp, WANT_CLEAR)) {
/* zval_ptr_dtor(z); */
/* zval_ptr_dtor(vp); */
return 1;
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object_properties */
/** Unserializes array of object properties. */
inline static int igbinary_unserialize_object_properties(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z) {
/* WANT_REF means that z will be wrapped by an IS_REFERENCE */
size_t n;
size_t i;
zval v;
zval *vp;
zval *z_deref;
enum igbinary_type key_type;
HashTable *h;
zend_bool did_extend;
if (t == igbinary_type_array8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd);
} else if (t == igbinary_type_array16) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd);
} else if (t == igbinary_type_array32) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_array: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
/* n cannot be larger than the number of minimum "objects" in the array */
if (IGB_NEEDS_MORE_DATA(igsd, n)) {
zend_error(E_WARNING, "%s: data size %zu smaller that requested array length %zu.", "igbinary_unserialize_array", IGB_REMAINING_BYTES(igsd), n);
return 1;
}
z_deref = z;
ZVAL_DEREF(z_deref);
/* empty array */
if (n == 0) {
return 0;
}
h = HASH_OF(z_deref);
did_extend = 0;
for (i = 0; i < n; i++) {
zend_string *key_str = NULL; /* NULL means use key_index */
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
zval_dtor(z);
ZVAL_NULL(z);
return 1;
}
key_type = (enum igbinary_type) igbinary_unserialize8(igsd);
switch (key_type) {
case igbinary_type_long8p:
case igbinary_type_long8n:
case igbinary_type_long16p:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
{
zend_long key_index = 0;
if (igbinary_unserialize_long(igsd, key_type, &key_index)) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
key_str = zend_long_to_str(key_index);
if (UNEXPECTED(key_str == NULL)) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
break;
}
case igbinary_type_string_id8:
case igbinary_type_string_id16:
case igbinary_type_string_id32:
key_str = igbinary_unserialize_string(igsd, key_type);
if (UNEXPECTED(key_str == NULL)) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
key_str = igbinary_unserialize_chararray(igsd, key_type);
if (UNEXPECTED(key_str == NULL)) {
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
break;
case igbinary_type_string_empty:
key_str = ZSTR_EMPTY_ALLOC();
break;
case igbinary_type_null:
continue; /* Skip unserializing this element, serialized with no value. In C, this applies to loop, not switch. */
default:
zend_error(E_WARNING, "igbinary_unserialize_array: unknown key type '%02x', position %zu", key_type, IGB_BUFFER_OFFSET(igsd));
zval_dtor(z);
ZVAL_UNDEF(z);
return 1;
}
/* first add key into array so references can properly and not stack allocated zvals */
/* Use NULL because inserting UNDEF into array does not add a new element */
ZVAL_NULL(&v);
zval *prototype_value = zend_hash_find(h, key_str);
if (prototype_value != NULL) {
if (Z_TYPE_P(prototype_value) == IS_INDIRECT) {
prototype_value = Z_INDIRECT_P(prototype_value);
}
convert_to_null(prototype_value);
vp = zend_hash_update_ind(h, key_str, &v);
} else {
if (!did_extend) {
zend_long remaining_elements = n - i;
/* Copied from var_unserializer.re. Need to ensure that IGB_REF_VAL doesn't point to invalid data. */
/* Worst case: All remaining_elements of the added properties are dynamic. */
zend_hash_extend(h, zend_hash_num_elements(h) + remaining_elements, (h->u.flags & HASH_FLAG_PACKED));
did_extend = 1;
}
vp = zend_hash_add_new(h, key_str, &v);
}
zend_string_release(key_str);
ZEND_ASSERT(vp != NULL);
if (Z_TYPE_P(vp) == IS_INDIRECT) {
vp = Z_INDIRECT_P(vp);
}
ZEND_ASSERT(vp != NULL);
if (igbinary_unserialize_zval(igsd, vp, WANT_CLEAR)) {
/* zval_ptr_dtor(z); */
/* zval_ptr_dtor(vp); */
return 1;
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object_ser */
/** Unserializes object's property array of objects implementing Serializable -interface. */
inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, zend_class_entry *ce) {
size_t n;
int ret;
php_unserialize_data_t var_hash;
if (ce->unserialize == NULL) {
zend_error(E_WARNING, "Class %s has no unserializer", ce->name);
return 1;
}
if (t == igbinary_type_object_ser8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd);
} else if (t == igbinary_type_object_ser16) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd);
} else if (t == igbinary_type_object_ser32) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
if (IGB_NEEDS_MORE_DATA(igsd, n)) {
zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
return 1;
}
PHP_VAR_UNSERIALIZE_INIT(var_hash);
ret = ce->unserialize(z, ce,
(const unsigned char*)igsd->buffer_ptr, n,
(zend_unserialize_data *)&var_hash);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
if (ret != SUCCESS || EG(exception)) {
return 1;
}
igsd->buffer_ptr += n;
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object */
/** Unserialize object.
* @see ext/standard/var_unserializer.c
*/
inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags) {
zend_class_entry *ce;
size_t ref_n;
zend_string *class_name;
int r;
bool incomplete_class = false;
bool is_from_serialized_data = false;
zval user_func;
zval retval;
zval args[1];
if (t == igbinary_type_object8 || t == igbinary_type_object16 || t == igbinary_type_object32) {
class_name = igbinary_unserialize_chararray(igsd, t);
} else if (t == igbinary_type_object_id8 || t == igbinary_type_object_id16 || t == igbinary_type_object_id32) {
class_name = igbinary_unserialize_string(igsd, t);
} else {
zend_error(E_WARNING, "igbinary_unserialize_object: unknown object type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
if (class_name == NULL) {
return 1;
}
do {
/* Try to find class directly */
if ((ce = zend_lookup_class(class_name)) != NULL) {
/* FIXME: lookup class may cause exception in load callback */
break;
}
/* Check for unserialize callback */
if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
incomplete_class = 1;
ce = PHP_IC_ENTRY;
break;
}
/* Call unserialize callback */
ZVAL_STRING(&user_func, PG(unserialize_callback_func));
/* FIXME: Do we need a str copy? */
/* FIXME: Release arg[0] */
/* FIXME: Release class_name */
ZVAL_STR_COPY(&args[0], class_name);
if (call_user_function_ex(CG(function_table), NULL, &user_func, &retval, 1, args, 0, NULL) != SUCCESS) {
php_error_docref(NULL, E_WARNING, "defined (%s) but not found", ZSTR_VAL(class_name));
incomplete_class = 1;
ce = PHP_IC_ENTRY;
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&user_func);
break;
}
/* FIXME: always safe? */
zval_ptr_dtor(&retval);
/* The callback function may have defined the class */
ce = zend_lookup_class(class_name);
if (!ce) {
php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", ZSTR_VAL(class_name));
incomplete_class = true;
ce = PHP_IC_ENTRY;
}
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&user_func);
} while (0);
/* previous user function call may have raised an exception */
if (EG(exception)) {
zend_string_release(class_name);
return 1;
}
/* add this to the list of unserialized references, get the index */
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_object: end-of-data");
zend_string_release(class_name);
return 1;
}
{
struct igbinary_value_ref ref;
ref_n = igsd_append_ref(igsd, ref);
if (ref_n == SIZE_MAX) {
zend_string_release(class_name);
return 1;
}
}
t = (enum igbinary_type) igbinary_unserialize8(igsd);
switch (t) {
case igbinary_type_array8:
case igbinary_type_array16:
case igbinary_type_array32:
{
if (object_init_ex(z, ce) != SUCCESS) {
php_error_docref(NULL, E_NOTICE, "igbinary unable to create object for class entry");
r = 1;
break;
}
if (incomplete_class) {
php_store_class_name(z, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
}
struct igbinary_value_ref *ref = &IGB_REF_VAL_2(igsd, ref_n);;
if ((flags & WANT_REF) != 0) {
ZVAL_MAKE_REF(z);
ref->reference.reference = Z_REF_P(z);
ref->type = IG_REF_IS_REFERENCE;
} else {
ref->reference.object = Z_OBJ_P(z);
ref->type = IG_REF_IS_OBJECT;
}
r = igbinary_unserialize_object_properties(igsd, t, z);
break;
}
case igbinary_type_object_ser8:
case igbinary_type_object_ser16:
case igbinary_type_object_ser32:
{
is_from_serialized_data = true;
// FIXME will this break if z isn't an object?
r = igbinary_unserialize_object_ser(igsd, t, z, ce);
if (r != 0) {
break;
}
if (incomplete_class) {
php_store_class_name(z, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
}
struct igbinary_value_ref *ref = &IGB_REF_VAL_2(igsd, ref_n);
if ((flags & WANT_REF) != 0) {
ZVAL_MAKE_REF(z);
ref->reference.reference = Z_REF_P(z);
ref->type = IG_REF_IS_REFERENCE;
} else {
ref->reference.object = Z_OBJ_P(z);
ref->type = IG_REF_IS_OBJECT;
}
break;
}
default:
zend_error(E_WARNING, "igbinary_unserialize_object: unknown object inner type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
r = 1;
}
zend_string_release(class_name);
class_name = NULL;
/* If unserialize was successful, call __wakeup if __wakeup exists for this object. */
/* (But don't call __wakeup() if Serializable::unserialize was called */
if (r == 0 && !is_from_serialized_data) {
struct igbinary_value_ref * const ref = &IGB_REF_VAL_2(igsd, ref_n);
zval ztemp;
zend_object *object;
if (ref->type == IG_REF_IS_OBJECT) {
object = ref->reference.object;
ZVAL_OBJ(&ztemp, object);
} else if (ref->type == IG_REF_IS_REFERENCE) {
ztemp = ref->reference.reference->val;
if (Z_TYPE(ztemp) != IS_OBJECT) {
zend_error(E_WARNING, "igbinary_unserialize_object preparing to __wakeup: got reference to non-object somehow", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
object = Z_OBJ(ztemp);
} else {
zend_error(E_WARNING, "igbinary_unserialize_object preparing to __wakeup: created non-object somehow", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
zend_class_entry *ztemp_ce;
/* May have created a reference while deserializing an object, if it was recursive. */
ztemp_ce = Z_OBJCE(ztemp);
if (ztemp_ce != PHP_IC_ENTRY &&
zend_hash_str_exists(&ztemp_ce->function_table, "__wakeup", sizeof("__wakeup") - 1)) {
if (igsd_defer_wakeup(igsd, object)) {
r = 1;
}
}
}
/* ZVAL_COPY_VALUE(z, IGB_REF_VAL(igsd, ref_n)); */
return r;
}
/* }}} */
/* {{{ igbinary_unserialize_ref */
/** Unserializes array or object by reference. */
inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags) {
size_t n;
if (t == igbinary_type_ref8 || t == igbinary_type_objref8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
return 1;
}
n = igbinary_unserialize8(igsd);
} else if (t == igbinary_type_ref16 || t == igbinary_type_objref16) {
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
return 1;
}
n = igbinary_unserialize16(igsd);
} else if (t == igbinary_type_ref32 || t == igbinary_type_objref32) {
if (IGB_NEEDS_MORE_DATA(igsd, 4)) {
zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_ref: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
if (n >= igsd->references_count) {
zend_error(E_WARNING, "igbinary_unserialize_ref: invalid reference %zu >= %zu", (int) n, (int)igsd->references_count);
return 1;
}
if (z != NULL) {
/* FIXME: check with is refcountable or some such */
zval_ptr_dtor(z);
ZVAL_UNDEF(z);
}
struct igbinary_value_ref* ref_ptr = &IGB_REF_VAL_2(igsd, n);
struct igbinary_value_ref ref = *ref_ptr;
/**
* Permanently convert the zval in IGB_REF_VAL() into a IS_REFERENCE if it wasn't already one.
* TODO: Can there properly be multiple reference groups to an object?
* Similar to https://github.com/php/php-src/blob/master/ext/standard/var_unserializer.re , for "R:"
* Using `flags` because igbinary_unserialize_ref might be used both for copy on writes ($a = $b = [2]) and by PHP references($a = &$b).
*/
if ((flags & WANT_REF) != 0) {
/* Want to create an IS_REFERENCE, not just to share the same value until modified. */
switch (ref.type) {
case IG_REF_IS_OBJECT:
ZVAL_OBJ(z, ref.reference.object);
Z_TRY_ADDREF_P(z);
ZVAL_MAKE_REF(z); /* Convert original zval data to a reference */
/* replace the entry in IGB_REF_VAL with a reference. */
ref_ptr->reference.reference = Z_REF_P(z);
ref_ptr->type = IG_REF_IS_REFERENCE;
break;
case IG_REF_IS_ARRAY:
ZVAL_ARR(z, ref.reference.array);
Z_TRY_ADDREF_P(z);
ZVAL_MAKE_REF(z); /* Convert original zval data to a reference */
/* replace the entry in IGB_REF_VAL with a reference. */
ref_ptr->reference.reference = Z_REF_P(z);
ref_ptr->type = IG_REF_IS_REFERENCE;
break;
case IG_REF_IS_REFERENCE:
// This is already a reference, convert into reference count.
ZVAL_REF(z, ref.reference.reference);
Z_ADDREF_P(z);
break;
}
} else {
switch (ref.type) {
case IG_REF_IS_OBJECT:
ZVAL_OBJ(z, ref.reference.object);
Z_TRY_ADDREF_P(z);
break;
case IG_REF_IS_ARRAY:
ZVAL_ARR(z, ref.reference.array);
Z_TRY_ADDREF_P(z);
break;
case IG_REF_IS_REFERENCE:
ZVAL_COPY(z, &(ref.reference.reference->val));
break;
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_zval */
/** Unserialize zval. */
static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval *const z, int flags) {
enum igbinary_type t;
zend_long tmp_long;
double tmp_double;
zend_string *tmp_str;
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_zval: end-of-data");
return 1;
}
t = (enum igbinary_type) igbinary_unserialize8(igsd);
switch (t) {
case igbinary_type_ref:
if (igbinary_unserialize_zval(igsd, z, WANT_REF)) {
return 1;
}
/* If it is already a ref, nothing to do */
if (Z_ISREF_P(z)) {
break;
}
const zend_uchar type = Z_TYPE_P(z);
/* Permanently convert the zval in IGB_REF_VAL() into a IS_REFERENCE if it wasn't already one. */
/* TODO: Support multiple reference groups to the same object */
/* Similar to https://github.com/php/php-src/blob/master/ext/standard/var_unserializer.re , for "R:" */
ZVAL_MAKE_REF(z);
switch (type) {
case IS_STRING:
case IS_LONG:
case IS_NULL:
case IS_DOUBLE:
case IS_FALSE:
case IS_TRUE:
{
struct igbinary_value_ref ref;
ref.reference.reference = Z_REF_P(z);
ref.type = IG_REF_IS_REFERENCE;
/* add the unserialized scalar to the list of unserialized references. Objects and arrays were already added in igbinary_unserialize_zval. */
if (igsd_append_ref(igsd, ref) == SIZE_MAX) {
return 1;
}
break;
}
default:
break;
}
break;
case igbinary_type_objref8:
case igbinary_type_objref16:
case igbinary_type_objref32:
case igbinary_type_ref8:
case igbinary_type_ref16:
case igbinary_type_ref32:
if (igbinary_unserialize_ref(igsd, t, z, flags)) {
return 1;
}
break;
case igbinary_type_object8:
case igbinary_type_object16:
case igbinary_type_object32:
case igbinary_type_object_id8:
case igbinary_type_object_id16:
case igbinary_type_object_id32:
if (igbinary_unserialize_object(igsd, t, z, flags)) {
return 1;
}
break;
case igbinary_type_array8:
case igbinary_type_array16:
case igbinary_type_array32:
if (igbinary_unserialize_array(igsd, t, z, flags)) {
return 1;
}
break;
case igbinary_type_string_empty:
ZVAL_EMPTY_STRING(z);
break;
case igbinary_type_string_id8:
case igbinary_type_string_id16:
case igbinary_type_string_id32:
tmp_str = igbinary_unserialize_string(igsd, t);
if (tmp_str == NULL) {
return 1;
}
ZVAL_STR(z, tmp_str);
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
tmp_str = igbinary_unserialize_chararray(igsd, t);
if (tmp_str == NULL) {
return 1;
}
ZVAL_STR(z, tmp_str);
break;
case igbinary_type_long8p:
case igbinary_type_long8n:
case igbinary_type_long16p:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
if (igbinary_unserialize_long(igsd, t, &tmp_long)) {
return 1;
}
ZVAL_LONG(z, tmp_long);
break;
case igbinary_type_null:
ZVAL_NULL(z);
break;
case igbinary_type_bool_false:
ZVAL_BOOL(z, 0);
break;
case igbinary_type_bool_true:
ZVAL_BOOL(z, 1);
break;
case igbinary_type_double:
if (igbinary_unserialize_double(igsd, t, &tmp_double)) {
return 1;
}
ZVAL_DOUBLE(z, tmp_double);
break;
default:
zend_error(E_WARNING, "igbinary_unserialize_zval: unknown type '%02x', position %zu", t, IGB_BUFFER_OFFSET(igsd));
return 1;
}
return 0;
}
/* }}} */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
igbinary-2.0.5/src/php7/igbinary.h 0000644 0001750 0001750 00000005111 13177372464 016072 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef IGBINARY_H
#define IGBINARY_H
#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
# include
#endif
/* Forward declarations. */
struct zval;
/* Constants and constant macros */
/** Binary protocol version of igbinary. */
#define IGBINARY_FORMAT_VERSION 0x00000002
#define PHP_IGBINARY_VERSION "2.0.5"
/* Macros */
#ifdef PHP_WIN32
# if defined(IGBINARY_EXPORTS) || (!defined(COMPILE_DL_IGBINARY))
# define IGBINARY_API __declspec(dllexport)
# elif defined(COMPILE_DL_IGBINARY)
# define IGBINARY_API __declspec(dllimport)
# else
# define IGBINARY_API /* nothing special */
# endif
#elif defined(__GNUC__) && __GNUC__ >= 4
# define IGBINARY_API __attribute__ ((visibility("default")))
#else
# define IGBINARY_API /* nothing special */
#endif
/** Struct that contains pointers to memory allocation and deallocation functions.
* @see igbinary_serialize_data
*/
struct igbinary_memory_manager {
void *(*alloc)(size_t size, void *context);
void *(*realloc)(void *ptr, size_t new_size, void *context);
void (*free)(void *ptr, void *context);
void *context;
};
/** Serialize zval.
* Return buffer is allocated by this function with emalloc.
* @param[out] ret Return buffer
* @param[out] ret_len Size of return buffer
* @param[in] z Variable to be serialized
* @return 0 on success, 1 elsewhere.
*/
IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z);
/** Serialize zval.
* Return buffer is allocated by this function with emalloc.
* @param[out] ret Return buffer
* @param[out] ret_len Size of return buffer
* @param[in] z Variable to be serialized
* @param[in] memory_manager Pointer to the structure that contains memory allocation functions.
* @return 0 on success, 1 elsewhere.
*/
IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager);
/** Unserialize to zval.
* @param[in] buf Buffer with serialized data.
* @param[in] buf_len Buffer length.
* @param[out] z Unserialized zval
* @return 0 on success, 1 elsewhere.
*/
IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval *z);
#endif /* IGBINARY_H */
igbinary-2.0.5/src/php7/php_igbinary.h 0000644 0001750 0001750 00000004552 13177372464 016751 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef PHP_IGBINARY_H
#define PHP_IGBINARY_H
#include "php.h"
/** Module entry of igbinary. */
extern zend_module_entry igbinary_module_entry;
#define phpext_igbinary_ptr &igbinary_module_entry
#ifdef PHP_WIN32
#define PHP_IGBINARY_API __declspec(dllexport)
#else
#define PHP_IGBINARY_API
#endif
ZEND_BEGIN_MODULE_GLOBALS(igbinary)
zend_bool compact_strings;
ZEND_END_MODULE_GLOBALS(igbinary)
#ifdef ZTS
#include "TSRM.h"
#endif
#include "ext/standard/php_smart_string.h"
/** Module init function. */
PHP_MINIT_FUNCTION(igbinary);
/** Module shutdown function. */
PHP_MSHUTDOWN_FUNCTION(igbinary);
/** Request init function. */
PHP_RINIT_FUNCTION(igbinary);
/** Request shutdown function. */
PHP_RSHUTDOWN_FUNCTION(igbinary);
/** Module info function for phpinfo(). */
PHP_MINFO_FUNCTION(igbinary);
/** string igbinary_serialize(mixed value).
* Returns the binary serialized value.
*/
PHP_FUNCTION(igbinary_serialize);
/** mixed igbinary_unserialize(string data).
* Unserializes the given inputstring (value).
*/
PHP_FUNCTION(igbinary_unserialize);
#ifdef ZTS
#define IGBINARY_G(v) TSRMG(igbinary_globals_id, zend_igbinary_globals *, v)
#else
#define IGBINARY_G(v) (igbinary_globals.v)
#endif
/** Backport macros from php 5.3 */
#ifndef Z_ISREF_P
#define Z_ISREF_P(pz) PZVAL_IS_REF(pz)
#endif
#ifndef Z_ISREF_PP
#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz))
#endif
#ifndef Z_SET_ISREF_TO_P
#define Z_SET_ISREF_TO_P(pz, isref) (Z_ISREF_P(pz) = (isref))
#endif
#ifndef Z_SET_ISREF_TO_PP
#define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref)
#endif
#ifndef Z_ADDREF_P
#define Z_ADDREF_P(pz) ZVAL_ADDREF(pz)
#endif
#ifndef Z_ADDREF_PP
#define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz))
#endif
#endif /* PHP_IGBINARY_H */
/*
* Local variables:
* tab-width: 2
* c-basic-offset: 0
* End:
* vim600: noet sw=2 ts=2 fdm=marker
* vim<600: noet sw=2 ts=2
*/
igbinary-2.0.5/src/php7/ig_win32.h 0000644 0001750 0001750 00000001056 13177372464 015713 0 ustar tyson tyson #ifndef _IG_WIN32_H
#define _IG_WIN32_H
#if PHP_WIN32
# include "win32/php_stdint.h"
# if defined(_MSC_VER) && _MSC_VER >= 1800
# include
# else
# ifndef inline
# define inline __inline
# endif
# ifndef __cplusplus
# if !0
typedef enum { false = 0, true = 1 } _Bool;
# define bool _Bool
# endif
# else
typedef bool _Bool;
# define bool _Bool
# endif
# define false 0
# define true 1
# define __bool_true_false_are_defined 1
# endif /* __MSC_VER */
#endif /* PHP_WIN32 */
#endif /* _IG_WIN32_H */
igbinary-2.0.5/igbinary.php 0000644 0001750 0001750 00000006411 13177372464 014771 0 ustar tyson tyson
* @version 1.0.0
* @package igbinary
*/
/** Generates a storable representation of a value.
* This is useful for storing or passing PHP values around without losing their type and structure.
* To make the serialized string into a PHP value again, use {@link igbinary_unserialize}.
*
* igbinary_serialize() handles all types, except the resource-type.
* You can even serialize() arrays that contain references to itself.
* Circular references inside the array/object you are serialize()ing will also be stored.
*
* If object implements {@link http://www.php.net/~helly/php/ext/spl/interfaceSerializable.html Serializable} -interface,
* PHP will call the member function serialize to get serialized representation of object.
*
* When serializing objects, PHP will attempt to call the member function __sleep prior to serialization.
* This is to allow the object to do any last minute clean-up, etc. prior to being serialized.
* Likewise, when the object is restored using unserialize() the __wakeup member function is called.
*
* @param mixed $value The value to be serialized.
* @return string Returns a string containing a byte-stream representation of value that can be stored anywhere.
* @link http://www.php.net/serialize PHP default serialize
*/
function igbinary_serialize($value);
/** Creates a PHP value from a stored representation.
* igbinary_unserialize() takes a single serialized variable and converts it back into a PHP value.
*
* If the variable being unserialized is an object, after successfully reconstructing the object
* PHP will automatically attempt to call the __wakeup() member function (if it exists).
* In case the passed string is not unserializeable, NULL is returned and E_WARNING is issued.
*
* @param string $str The serialized string.
* @return mixed The converted value is returned, and can be a boolean, integer, float, string, array or object.
* @link http://www.php.net/manual/en/function.unserialize.php PHP default unserialize
* @link http://www.php.net/~helly/php/ext/spl/interfaceSerializable.html Serializable
*/
function igbinary_unserialize($str);
?>
igbinary-2.0.5/igbinary.php.ini 0000644 0001750 0001750 00000000210 13177372464 015536 0 ustar tyson tyson [igbinary]
extension=igbinary.so
; Enable or disable compacting of duplicate strings
; The default is On.
;igbinary.compact_strings=On
igbinary-2.0.5/tags.sh 0000755 0001750 0001750 00000000323 13177372464 013745 0 ustar tyson tyson #!/bin/sh
#
# This generates the tags file for vim or emacs. (vim -t igbinary_serialize8)
#
# Try with "vim -t igbinary_serialize8"
#
find . -name "*.h" -o -name "*.c" | ctags-exuberant --language-force=c -L -
igbinary-2.0.5/igbinary.spec 0000644 0001750 0001750 00000003106 13177372464 015132 0 ustar tyson tyson # Define version and release number
%define version 1.0.2
%define release 1
Name: php-igbinary
Version: %{version}
Release: %{release}%{?dist}
Packager: Mikko Koppanen
Summary: PHP igbinary extension
License: PHP Style License (http://opensource.dynamoid.com/#license)
Group: Web/Applications
URL: http://opensource.dynamoid.com/
# pear package creates .tgz file and the original source was .tar.gz
Source: http://opensource.dynamoid.com/igbinary-%{version}.tgz
Prefix: %{_prefix}
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildRequires: php-devel, make, gcc, /usr/bin/phpize
%description
Igbinary is a drop in replacement for the standard PHP serializer.
Instead of time and space consuming textual representation,
igbinary stores PHP data structures in a compact binary form.
%prep
%setup -q -n igbinary-%{version}
%build
/usr/bin/phpize && %configure && %{__make} %{?_smp_mflags}
# Clean the buildroot so that it does not contain any stuff from previous builds
[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
# Install the extension
%{__make} install INSTALL_ROOT=%{buildroot}
# Create the ini location
%{__mkdir} -p %{buildroot}/etc/php.d
# Preliminary extension ini
echo "extension=igbinary.so" > %{buildroot}/%{_sysconfdir}/php.d/igbinary.ini
%clean
[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
%files
%{_libdir}/php/modules/igbinary.so
%{_sysconfdir}/php.d/igbinary.ini
%{_includedir}/php/ext/igbinary/igbinary.h
%changelog
* Fri Oct 02 2009 Mikko Koppanen
- Initial spec file
igbinary-2.0.5/COPYING 0000644 0001750 0001750 00000003017 13177372464 013506 0 ustar tyson tyson Copyright (c) 2008 Sulake Dynamoid Oy, 2008-2014 Oleg Grenrus, Teddy Grenman,
igbinary contributors
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 the 'igbinary' nor the names of its 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.
igbinary-2.0.5/CREDITS 0000644 0001750 0001750 00000001032 13177372464 013466 0 ustar tyson tyson igbinary is written for IRC-Galleria by Sulake Dynamoid Oy and its employees.
Author
* Oleg Grenrus
Contributors
* Teddy Grenman (fixes, tests, docs)
* Kari Lavikka (docs)
* Pierre Joye (Windows support)
* Mikko Koppanen (PECL and RPM spec files)
* Tyson Andre (PHP7 compatibility fixes)
Other
* Original hash functions - Bob Jenkins
---
http://irc-galleria.net/ - a finnish social networking site
igbinary-2.0.5/README.md 0000644 0001750 0001750 00000012047 13177372464 013735 0 ustar tyson tyson igbinary
========
[](https://travis-ci.org/igbinary/igbinary)
[](https://ci.appveyor.com/project/TysonAndre/igbinary-bemsx)
Igbinary is a drop in replacement for the standard php serializer. Instead of
time and space consuming textual representation, igbinary stores php data
structures in compact binary form. Savings are significant when using
memcached or similar memory based storages for serialized data. About 50%
reduction in storage requirement can be expected. Specific number depends on
your data.
Unserialization performance is at least on par with the standard PHP serializer.
Serialization performance depends on the "compact_strings" option which enables
duplicate string tracking. String are inserted to a hash table which adds some
overhead. In usual scenarios this does not have much significance since usage
pattern is "serialize rarely, unserialize often". With "compact_strings"
option igbinary is usually a bit slower than the standard serializer. Without
it, a bit faster.
Features
--------
- Supports same data types as the standard PHP serializer: null, bool, int,
float, string, array and objects.
- `__autoload` & `unserialize_callback_func`
- `__sleep` & `__wakeup`
- Serializable -interface
- Data portability between platforms (32/64bit, endianess)
- Tested on Linux amd64, Linux ARM, Mac OSX x86, HP-UX PA-RISC and NetBSD sparc64
- Hooks up to APC opcode cache as a serialization handler (APC 3.1.7+)
(Hooks up to the substitute APCu for recent php releases)
- Compatible with PHP 5.2 – 5.6, 7.0 – 7.2
Implementation details
----------------------
Storing complex PHP data structures like arrays of associative arrays
with the standard PHP serializer is not very space efficient. The main
reasons in order of significance are (at least in our applications):
1. Array keys are repeated redundantly.
2. Numerical values are plain text.
3. Human readability adds some overhead.
Igbinary uses two specific strategies to minimize the size of the serialized
output.
1. Repetitive strings are stored only once. Collections of objects benefit
significantly from this. See "compact_strings" option.
2. Numerical values are stored in the smallest primitive data type
available:
*123* = `int8_t`,
*1234* = `int16_t`,
*123456* = `int32_t`
... and so on.
3. ( Well, it is not human readable ;)
How to use
----------
Add the following lines to your php.ini:
; Load igbinary extension
extension=igbinary.so
; Use igbinary as session serializer
session.serialize_handler=igbinary
; Enable or disable compacting of duplicate strings
; The default is On.
igbinary.compact_strings=On
; Use igbinary as serializer in APC cache (3.1.7 or later)
;apc.serializer=igbinary
.. and in your php code replace serialize and unserialize function calls
with `igbinary_serialize` and `igbinary_unserialize`.
Installing
----------
Note:
Sometimes phpize must be substituted with phpize5. In such cases the following
option must be given to configure script: "--with-php-config=.../php-config5"
1. `phpize`
2. `./configure:
- With GCC: `./configure CFLAGS="-O2 -g" --enable-igbinary`
- With ICC (Intel C Compiler) `./configure CFLAGS=" -no-prec-div -O3 -xO -unroll2 -g" CC=icc --enable-igbinary`
- With clang: `./configure CC=clang CFLAGS="-O0 -g" --enable-igbinary`
3. `make`
4. `make test`
5. `make install`
6. igbinary.so is installed to the default extension directory
### To run APCu test
```
# go to modules directory
cd modules
# ... and create symlink to apcu extension
# it will be loaded during test suite
/opt/lib/php/extensions/no-debug-non-zts-20121212/apcu.so
```
Similar approach should work for APC.
### Installing on Windows
If you are a contributor to/packager of igbinary, see [WINDOWS.md](./WINDOWS.md)
Bugs & Contributions
--------------------
Mailing list for bug reports and other development discussion can be found
at http://groups.google.com/group/igbinary
Fill bug reports at
https://github.com/igbinary/igbinary/issues
The preferred ways for contributions are pull requests and email patches
(in git format). Feel free to fork at http://github.com/igbinary/igbinary
Utilizing in other extensions
-----------------------------
Igbinary can be called from other extensions fairly easily. Igbinary installs
its header file to _ext/igbinary/igbinary.h_. There are just two straighforward
functions: `igbinary_serialize` and `igbinary_unserialize`. Look at _igbinary.h_ for
prototypes and usage.
Add `PHP_ADD_EXTENSION_DEP(yourextension, igbinary)` to your _config.m4_ in case
someone wants to compile both of them statically into php.
Trivia
------
Where does the name "igbinary" come from? There was once a similar project
called fbinary but it has disappeared from the Internet a long time ago. Its
architecture wasn't particularly clean either. IG is an abbreviation for a
finnish social networking site IRC-Galleria (http://irc-galleria.net/)
igbinary-2.0.5/NEWS 0000644 0001750 0001750 00000005623 13177372464 013157 0 ustar tyson tyson 2.0.5 2017-11-04
========
* Same as 2.0.5RC1 (no bugs were reported in that release candidate)
2.0.5RC1 2017-10-15
========
* Improve performance when unserializing objects/arrays and serializing objects/arrays/strings in php 5/7.
* Update unserialization of integer object keys for php 7.2: Make those keys accessible when unserializing.
* Properly pick up presence of gcc for default compiler flags (`cc --version` doesn't contain gcc).
Add -O2 to default gcc compiler flags.
* Use empty string for serializing empty $_SESSION array, similar to "session.serialize_handler=php".
Older igbinary releases already unserialize the empty string to the empty array.
2.0.4 2017-04-14
========
* Fixes bug #129: Should not call __wakeup() on data which was created by Serializable::unserialize()
2.0.3 2017-03-31
========
* Fixes bug #126: Fatal error: "igbinary_serialize_zval: zval has unknown type 0" (IS_UNDEF)
Make this a warning instead of a fatal error (and serialize as null instead), since IS_UNDEF is a known type.
Later releases will fix the root cause of the warning, and consistently omit array/object/other entries for IS_UNDEF.
2.0.2 2017-02-27
========
* Compatible with PHP 5.2 - 7.1
* Fixes crash in Memcached->setMulti (in php 7.0+) when the first level of array elements have references as values.
Other extensions using igbinary shouldn't be affected.
2.0.1 2016-11-19
========
* Compatible with PHP 5.2 - 7.0
* Fixes bug in session decoder not calling __wakeup() in php 7.0+
* (Enhancement) Reuses identical strings when unserializing objects and arrays in php 7.0+
2.0.0 2016-10-30
========
* Compatible with PHP 5.2 - 7.0 (Adds PHP 7 support)
* Serialization format is unchanged
* Performance improvements for serialization and unserialization in PHP 5.2 - 7.0
* (PHP 7) Don't call __destruct if __wakeup threw an exception (or __wakeup wasn't called yet)
* Ports integration with other extensions to PHP 7.0 (session serialization, Memcached, Redis, APCu, etc.)
* Fixes Windows PECL builds for PHP 5.6+
* Reword warnings for invalid header bytes of serialized data (in igbinary_unserialize).
1.2.1 2014-08-29
========
* Compatible with PHP 5.2 - 5.6
1.2.0 2014-08-28
========
* PECL bug #22614, igbinary_unserialize(FALSE) must return FALSE
* PHP bug #54662, unserializing nested objects cause crash
* Other fixes
1.1.1 2011-01-17
========
* Critical crash fix. Thanks to Ilia Alshanetsky for spotting and fixing.
1.1.0 2011-01-17
========
* New ini setting to disable duplicate string compacting
* APC serializer registration (APC 3.1.7 beta)
* Windows support (PHP 5.3)
* Updated serialized binary format (1.1 reads 1.0.x format)
* Minor performance improvements
* Bug fixes
* New source repository at https://github.com/igbinary/igbinary
1.0.2
========
* Bug fix release
1.0.1 2008-07-05
========
* unserialize_callback_func support
* slight speedup when serializing scalars
1.0.0 2008-06-25
========
* Public version