package.xml 0000664 0001750 0001750 00000135164 14532662345 012333 0 ustar tyson tyson
igbinary
pecl.php.net
igbinary extension
Igbinary is a drop in replacement for the standard php serializer. Instead of
the time and space consuming textual representation used by PHP's serialize(), 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
tandre@php.net
yes
2023-12-02
3.2.15
1.4.0
stable
stable
BSD-3-Clause
* Fix crash in igbinary_unserialize_object_enum_case with opcache protected memory and non-constant value.
7.0.0
1.4.0b1
igbinary
2023-02-26
3.2.14
1.4.0
stable
stable
BSD-3-Clause
* Fix build error in PHP 8.3-dev
* Fix test expectation errors in php 8.3-dev due to change to php's TypeErrors.
2023-02-02
3.2.13
1.4.0
stable
stable
BSD-3-Clause
* Speed up unserialization of typed properties by reducing hash table collisions when looking up property reference info.
2022-11-07
3.2.12
1.4.0
stable
stable
BSD-3-Clause
* Fix symbol error seen in php 8.2.0 loading zend_class_unserialize_deny, due to failing to load a header defining a macro.
2022-11-06
3.2.11
1.4.0
stable
stable
BSD-3-Clause
* Fix a bug that could prevent objects/arrays with reference cycles from being properly garbage collected.
* Fix bugs in unserializing PHP references to values found in php 7.4 typed properties (#363)
2022-11-06
3.2.10
1.4.0
stable
stable
BSD-3-Clause
* Add a macro that callers can use to check if igbinary will accept the header for data being unserialized.
* Fix bug preventing the unserialization of data containing representations of strings larger than 4GB.
2022-10-17
3.2.9
1.3.1
stable
stable
BSD-3-Clause
* Fix invalid release artifact name in job to build dlls for https://github.com/igbinary/igbinary
2022-10-16
3.2.8
1.3.1
stable
stable
BSD-3-Clause
* Reduce excessive inlining to reduce shared library size.
* Miscellaneous optimizations.
* Update test expectations to handle changes to var_export output (fully qualified class names) in PHP 8.2.
* Throw an Error when igbinary_unserialize would add dynamic properties to class definitions that forbid them in PHP 8.0+
(especially PHP 8.2 `readonly` classes)
* Emit a deprecation notice when igbinary_unserialize() adds dynamic properties to a class without `#[AllowDynamicProperties]` in PHP 8.2.
Doing that would become an Error in PHP 9.0.
* Set up CI job to build dlls on https://github.com/igbinary/igbinary - at the moment, the infrastructure used by the Windows for php team has been broken for months.
2021-08-11
3.2.7
1.3.1
stable
stable
BSD-3-Clause
* Update test expectations for php 8.2.0-dev. Add `#[AllowDynamicProperties]` Attribute to some tests to avoid notices.
* In php 8.1+, make igbinary_unserialize check to see if an equivalent interned string already exists when unserializing object property names, array keys, and class names
and use that instead of creating a brand new string.
(This deliberately doesn't create a new interned string if one doesn't already exist.)
(Before this change, igbinary would deduplicate strings when serializing, but would not check if strings were interned by PHP itself when unserializing)
* Avoid debug build assertion failure for `HT_ASSERT_RC1` the same way as PHP's unserialize - this is a case where ostensibly there are no other references to the array being unserialized.
2021-08-11
3.2.6
1.3.1
stable
stable
BSD-3-Clause
* Fix igbinary extension version found in reflection.
2021-08-07
3.2.5
1.3.1
stable
stable
BSD-3-Clause
* Fix change in behavior introduced in 3.2.2RC1 when unserializing arrays - the internal array pointer (for `next()`, `key()`, etc) pointed past the end of the array in php 7.0-7.2.
2021-07-24
3.2.4
1.3.1
stable
stable
BSD-3-Clause
* Forbid serializing classes that deny serialization/unserialization (anonymous classes, CURLFile, etc.) even when subclasses implement '__serialize' and '__unserialize'
2021-06-09
3.2.3
1.3.1
stable
stable
BSD-3-Clause
* Fix build for php 8.1 after changes to enum internals.
* Update tests to suppress deprecations in php 8.1 and support run-tests.php changes in php 8.1
* Don't emit a notice when unserialize_callback_func causes igbinary_unserialize to throw https://bugs.php.net/bug.php?id=81118
2021-04-18
3.2.2
1.3.0
stable
stable
BSD-3-Clause
* Eliminate impossible/redundant checks.
* Add a new type code for serialization and unserialization of PHP strings that are larger than 4GB.
* Add additional checks for overflow when serializing extremely large data structures.
(e.g. serializing more than 2**32 strings or 2**32 objects/references/arrays)
* Support serializing and unserializing php 8.1 enums (can only be unserialized in php 8.1+)
2021-01-11
3.2.2RC1
1.2.5
beta
stable
BSD-3-Clause
* Update php version check to allow igbinary to be statically built in PHP 8.0+
* Fix bug in out of memory error handling in __sleep, slightly speed up serializing with __sleep.
* Continue serializing remaining properties if a missing property name is returned from __sleep.
* Speed up serializing by optimizing for the case where there is no memory manager override.
When there is a memory manager override, only use that for allocating the string to return.
(benchmarks/serialize-scalar-int.b.php showed a speedup from 0.22 to 0.18 seconds for repeated serialization of a single scalar,
and from 0.186 to 0.180 seconds for benchmarks/serialize-stringarray.b.php for an array of strings)
* Speed up unserializing arrays in php 7.2-8.0 by adding optimized code for finding the hash bucket of
a string/integer key of an array, or creating a placeholder if it does not already exist.
2020-12-27
3.2.1
1.2.5
stable
stable
BSD-3-Clause
* Fix crash when unserializing if __serialize was defined but __unserialize was undefined in php 8.0+ (due to typo).
2020-12-26
3.2.0
1.2.5
stable
stable
BSD-3-Clause
* Use PHP's shared empty array instance when unserializing empty arrays in php 7.3+.
(helps slightly with memory usage when repeatedly unserializing,
when removing elements from arrays before unserializing them,
or when serializing values including an empty array that was unserialized)
* Emit a deprecation notice when serializing resources.
PHP itself is converting many resources to objects that throw an Error on serialization attempts.
Continue to represent resources as null in the serialized data.
* Fix memory management bug when unserializing invalid data (duplicate properties in objects (e.g. from `__sleep`) or duplicate fields in arrays (impossible for valid data)).
* Speed up calls to `__serialize`/`__unserialize` in php 8.0+.
* Fix error messages for unserialize_callback_func: make messages properly refer to the autoload function.
* Optimize unserializing alternative names for private/protected properties that were previously public.
2020-10-08
3.1.6
1.2.4
stable
stable
BSD-3-Clause
* Fix build failure with older C standard (e.g. building on CentOS 6).
* Otherwise, identical to 3.1.6RC1.
2020-10-07
3.1.6RC1
1.2.4
beta
stable
BSD-3-Clause
* Fix igbinary_serialize incorrectly deduplicating arrays/objects/references when they were garbage collected/freed during serialization.
2020-09-02
3.1.5
1.2.3
stable
stable
BSD-3-Clause
* Update unit test expectation to match behavior in php 8 due to changes in php's handling of cyclic references in arrays.
* Support API changes in php 8.0.0beta3.
2020-08-05
3.1.4
1.2.3
stable
stable
BSD-3-Clause
* Fix unserialization of PHP references to internal/user-defined classes using PHP 7.4's `__unserialize` (e.g. `ArrayObject`)
2020-08-04
3.1.3
1.2.3
stable
stable
BSD-3-Clause
* Properly serialize reference groups of size 1 (these can be created by array_walk_recursive and other functions).
Note that this does not fix the general case where values not being serialized are in the same reference group as a value being serialized.
* PHP 8.0 compatibility fixes.
2020-01-21
3.1.2
1.2.3
stable
stable
BSD-3-Clause
* Speed up object, array, reference, and string serialization.
* Speed up unserializing integers between 0 and 65535 (as values and array keys).
* Speed up unserializing objects with declared properties.
2020-01-16
3.1.1
1.2.3
stable
stable
BSD-3-Clause
* Fix bug causing incorrect serialization for 1 in 2**32 strings on 64-bit php installations when string hashes collide.
(https://github.com/igbinary/igbinary/issues/260)
2021-01-11
3.1.1a1
1.2.2
beta
beta
BSD-3-Clause
* Throw when an uninitialized php 7.4 typed property is included in the result of __sleep(),
instead of emitting a notice and attempting to represent the unset/uninitialized value as null (#258).
See https://bugs.php.net/bug.php?id=79002
Uninitialized properties without types (from __sleep) continue to cause igbinary to emit notices and are represented as null.
2019-12-27
3.1.0
1.2.2
beta
beta
BSD-3-Clause
* Same as 3.1.0b4.
2019-12-20
3.1.0b4
1.2.2
beta
beta
BSD-3-Clause
* Don't call __destruct for objects where deferred __unserialize calls were not started (e.g. due to Serializable::unserialize throwing).
2019-12-10
3.1.0b3
1.2.2
beta
beta
BSD-3-Clause
* Skip over object properties that are uninitialized or unset when serializing, instead of serializing them as null.
This is done to avoid Errors when unserializing their values for php 7.4 typed properties.
2019-12-09
3.1.0b2
1.2.1
beta
beta
BSD-3-Clause
* Fix crashes related to unserializing instances of classes with php 7.4 typed properties.
2019-12-08
3.1.0b1
1.2.1
beta
beta
BSD-3-Clause
* Support php 7.4's __serialize/__unserialize the same way serialize()/unserialize() does.
This deliberately only supports __serialize/__unserialize in php 7.4, to making switching to/from serialize()/unserialize() as straightforward as possible.
2019-03-20
3.0.1
1.2.0
stable
stable
BSD-3-Clause
* Fix version check when statically building igbinary inside of the php-src folder.
2019-02-17
3.0.0
1.2.0
stable
stable
BSD-3-Clause
* Identical to 3.0.0a2
2019-02-13
3.0.0a2
1.2.0
alpha
stable
BSD-3-Clause
* Don't use empty string for serializing empty $_SESSION array, it breaks some save handlers. (Issue #231)
Continue treating the empty string as the empty $_SESSION array when unserializing.
2019-02-09
3.0.0a1
1.2.0
alpha
stable
BSD-3-Clause
* Drop support for PHP 5.
* Drop support for APC (APC was only available for PHP5 - It is the predecessor of APCu)
* Emit a warning and return null if igbinary_unserialize() is passed more data to unserialize than expected.
* Fix compilation against PHP 7.4-dev. Igbinary does NOT yet properly serialize/unserialize all classes with PHP 7.4-dev's typed properties.
* The serialization format is exactly the same as igbinary 2.x
2018-10-20
2.0.8
1.1.2
stable
stable
BSD-3-Clause
* Be more aggressive about deduplication when generating serialization of arrays in php 7.0+.
* Define HAVE_IGBINARY on Unix/Linux. (previously defined only on Windows)
* Update formatting/wording of documentation.
2018-06-27
2.0.7
1.1.1
stable
stable
BSD-3-Clause
* Fix compiler warnings about format strings, for errors that should not occur during normal igbinary usage.
2018-05-12
2.0.6
1.1.1
beta
stable
BSD-3-Clause
* Same as 2.0.6RC1
2018-04-01
2.0.6RC1
1.1.1
stable
stable
BSD-3-Clause
* Same as 2.0.6RC1
* Fix a bug in Windows debug builds.
* Emit more specific warnings when __sleep() returns a declared property that was unset.
* Fix harmless compiler warnings during builds.
* Fix a build error on PHP7.3-dev.
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-3.2.15/tests/__serialize_001.phpt 0000664 0001750 0001750 00000001520 14532662345 017436 0 ustar tyson tyson --TEST--
__serialize() mechanism (001): Basics
--SKIPIF--
--FILE--
$this->prop, 42 => $this->prop2];
}
public function __unserialize(array $data) {
$this->prop = $data["value"];
$this->prop2 = $data[42];
}
}
$test = new Test;
$test->prop = "foobar";
$test->prop2 = "barfoo";
var_dump(bin2hex($s = igbinary_serialize($test)));
var_dump(igbinary_unserialize($s));
?>
--EXPECT--
string(74) "000000021704546573741402110576616c75651106666f6f626172062a1106626172666f6f"
object(Test)#2 (2) {
["prop"]=>
string(6) "foobar"
["prop2"]=>
string(6) "barfoo"
}
igbinary-3.2.15/tests/__serialize_002.phpt 0000664 0001750 0001750 00000000736 14532662345 017447 0 ustar tyson tyson --TEST--
__serialize() mechanism (002): TypeError on invalid return type
--SKIPIF--
--FILE--
getMessage(), "\n";
}
?>
--EXPECT--
Test::__serialize() must return an array
igbinary-3.2.15/tests/__serialize_003.phpt 0000664 0001750 0001750 00000003320 14532662345 017440 0 ustar tyson tyson --TEST--
__serialize() mechanism (003): Interoperability of different serialization mechanisms
--SKIPIF--
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
"value"];
}
public function __unserialize(array $data) {
echo "__unserialize() called\n";
var_dump($data);
}
public function serialize() {
echo "serialize() called\n";
return "payload";
}
public function unserialize($payload) {
echo "unserialize() called\n";
var_dump($payload);
}
}
$test = new Test;
var_dump(bin2hex($s = igbinary_serialize($test)));
var_dump(igbinary_unserialize($s));
var_dump(igbinary_unserialize(hex2bin('000000021704546573741d077061796c6f6164')));
?>
--EXPECT--
__serialize() called
string(48) "00000002170454657374140111036b6579110576616c7565"
__unserialize() called
array(1) {
["key"]=>
string(5) "value"
}
object(Test)#2 (0) {
}
unserialize() called
string(7) "payload"
object(Test)#2 (0) {
}
igbinary-3.2.15/tests/__serialize_004.phpt 0000664 0001750 0001750 00000005267 14532662345 017455 0 ustar tyson tyson --TEST--
__serialize() mechanism (004): Delayed __unserialize() calls
--SKIPIF--
--FILE--
data = $data;
}
public function __wakeup() {
echo "__wakeup() called\n";
var_dump($this->data);
$this->woken_up = true;
}
}
#[AllowDynamicProperties]
class Unserialize {
public $data;
public function __construct(array $data) {
$this->data = $data;
}
public function __serialize() {
return $this->data;
}
public function __unserialize(array $data) {
$this->data = $data;
echo "__unserialize() called\n";
var_dump($this->data);
$this->unserialized = true;
}
}
$obj = new Wakeup([new Unserialize([new Wakeup([new Unserialize([])])])]);
var_dump(bin2hex($s = igbinary_serialize($obj)));
var_dump(igbinary_unserialize($s));
?>
--EXPECT--
string(110) "00000002170657616b657570140111046461746114010600170b556e73657269616c697a65140106001a0014010e01140106001a021400"
__unserialize() called
array(0) {
}
__wakeup() called
array(1) {
[0]=>
object(Unserialize)#8 (2) {
["data"]=>
array(0) {
}
["unserialized"]=>
bool(true)
}
}
__unserialize() called
array(1) {
[0]=>
object(Wakeup)#7 (2) {
["data"]=>
array(1) {
[0]=>
object(Unserialize)#8 (2) {
["data"]=>
array(0) {
}
["unserialized"]=>
bool(true)
}
}
["woken_up"]=>
bool(true)
}
}
__wakeup() called
array(1) {
[0]=>
object(Unserialize)#6 (2) {
["data"]=>
array(1) {
[0]=>
object(Wakeup)#7 (2) {
["data"]=>
array(1) {
[0]=>
object(Unserialize)#8 (2) {
["data"]=>
array(0) {
}
["unserialized"]=>
bool(true)
}
}
["woken_up"]=>
bool(true)
}
}
["unserialized"]=>
bool(true)
}
}
object(Wakeup)#5 (2) {
["data"]=>
array(1) {
[0]=>
object(Unserialize)#6 (2) {
["data"]=>
array(1) {
[0]=>
object(Wakeup)#7 (2) {
["data"]=>
array(1) {
[0]=>
object(Unserialize)#8 (2) {
["data"]=>
array(0) {
}
["unserialized"]=>
bool(true)
}
}
["woken_up"]=>
bool(true)
}
}
["unserialized"]=>
bool(true)
}
}
["woken_up"]=>
bool(true)
}
igbinary-3.2.15/tests/__serialize_005.phpt 0000664 0001750 0001750 00000003106 14532662345 017444 0 ustar tyson tyson --TEST--
__serialize() mechanism (005): parent::__unserialize() is safe
--SKIPIF--
--FILE--
data = $data;
}
public function __serialize() {
return $this->data;
}
public function __unserialize(array $data) {
$this->data = $data;
}
}
class B extends A {
public function __construct(array $data, array $data2) {
parent::__construct($data);
$this->data2 = $data2;
}
public function __serialize() {
return [$this->data2, parent::__serialize()];
}
public function __unserialize(array $payload) {
[$data2, $data] = $payload;
parent::__unserialize($data);
$this->data2 = $data2;
}
}
$common = new stdClass;
$obj = new B([$common], [$common]);
var_dump(bin2hex($s = igbinary_serialize($obj)));
var_dump(igbinary_unserialize($s));
?>
--EXPECT--
string(70) "0000000217014214020600140106001708737464436c61737314000601140106002202"
object(B)#3 (2) {
["data":"A":private]=>
array(1) {
[0]=>
object(stdClass)#4 (0) {
}
}
["data2":protected]=>
array(1) {
[0]=>
object(stdClass)#4 (0) {
}
}
}
igbinary-3.2.15/tests/__serialize_006.phpt 0000664 0001750 0001750 00000002314 14532662345 017445 0 ustar tyson tyson --TEST--
__serialize() mechanism (006): DateTime
--SKIPIF--
--FILE--
--EXPECT--
string(164) "0000000217084461746554696d651403110464617465111a323031392d31322d30382031323a33343a30302e303030303030110d74696d657a6f6e655f747970650603110874696d657a6f6e651103555443"
object(DateTime)#2 (3) {
["date"]=>
string(26) "2019-12-08 12:34:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
string(184) "0000000217084461746554696d651403110464617465111a323031392d31322d30382031323a33343a30302e303030303030110d74696d657a6f6e655f747970650603110874696d657a6f6e65110d506163696669632f4e61757275"
object(DateTime)#1 (3) {
["date"]=>
string(26) "2019-12-08 12:34:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Pacific/Nauru"
}
igbinary-3.2.15/tests/__serialize_007.phpt 0000664 0001750 0001750 00000002754 14532662345 017456 0 ustar tyson tyson --TEST--
__serialize() mechanism (007): handle __unserialize throwing
--SKIPIF--
--FILE--
prop, $this->prop2];
}
public function __unserialize(array $data) {
$this->prop = $data[0];
$this->prop2 = $data[1];
throw new RuntimeException($this->prop);
}
public function __destruct() {
// should not be called
echo "Called destruct prop=$this->prop\n";
}
}
$test = new Test;
$test->prop = 'XX';
$test->prop2 = [$test];
// 00000002 - igbinary header
// 17 04 54657374 - object of class with name "Test"
// 14 02 - 2 properties
// 06 00 - uint8(0) =>
// 11 02 5858 - 'XX'
// 06 01 - uint8(1) =>
// 14 01 - array(size=2)
// 06 00 - uint8(0) =>
// 22 00 - igbinary_type_objref8 (pointer to the first referenceable item, i.e. the instance of "Test"
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
var_dump(igbinary_unserialize($s));
} catch (RuntimeException $e) {
echo "Caught: {$e->getMessage()}\n";
}
$test->prop = 'not from igbinary_unserialize';
?>
--EXPECT--
string(52) "0000000217045465737414020600110258580601140106002200"
Caught: XX
Called destruct prop=not from igbinary_unserialize
igbinary-3.2.15/tests/__serialize_008.phpt 0000664 0001750 0001750 00000003071 14532662345 017450 0 ustar tyson tyson --TEST--
__serialize() mechanism (007): handle __destruct of returned data
--SKIPIF--
= 90000) { echo "skip requires php < 9.0 when testing that the deprecation has no impact on igbinary functionality\n"; } ?>
--FILE--
= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }
class DestructorThrows {
public function __construct(string $val) {
$this->val = $val;
}
public function __destruct() {
echo "DestructorThrows called val=$this->val\n";
throw new RuntimeException($this->val);
}
}
class Xyz {
public $Xyz;
public function __serialize() {
return [new DestructorThrows($this->Xyz)];
}
public function __unserialize(array $data) {
$this->Xyz = $data[0];
}
public function __destruct() {
// should not be called
echo "Called destruct prop=$this->Xyz\n";
}
}
$test = new Xyz;
$test->Xyz = 'Xyz';
try {
var_dump(bin2hex($s = igbinary_serialize($test)));
} catch (RuntimeException $e) {
echo "message={$e->getMessage()}\n";
}
unset($test);
$test = new Xyz;
$test->Xyz = '';
try {
var_dump(bin2hex($s = igbinary_serialize($test)));
} catch (RuntimeException $e) {
echo "message={$e->getMessage()}\n";
}
?>
--EXPECT--
DestructorThrows called val=Xyz
message=Xyz
DestructorThrows called val=
Called destruct prop=Xyz
message=
Called destruct prop=
igbinary-3.2.15/tests/__serialize_009.phpt 0000664 0001750 0001750 00000004315 14532662345 017453 0 ustar tyson tyson --TEST--
__serialize() mechanism (009): Object/reference ids should be the same whether or not __serialize is used.
--SKIPIF--
--FILE--
value = $value;
}
}
class Test {
public $prop;
public function __construct($value) {
$this->prop = $value;
}
public function __serialize() {
return ["value" => $this->prop];
}
public function __unserialize(array $data) {
$this->prop = $data["value"];
}
}
$vest = new Vest('first');
$vest2 = new Vest(null);
$vest3 = new Vest($vest2);
$sv = igbinary_serialize([$vest, $vest2, $vest3, $vest, $vest2]);
$test = new Test('first');
$test2 = new Test(null);
$test3 = new Test($test2);
$s = igbinary_serialize([$test, $test2, $test3, $test, $test2]);
// The only difference in the serialization should be the first byte of the only occurrence of the class name.
var_dump(bin2hex($sv));
var_dump(bin2hex($s));
var_dump(igbinary_unserialize($s));
var_dump(igbinary_unserialize($sv));
?>
--EXPECT--
string(114) "00000002140506001704566573741401110576616c75651105666972737406011a0014010e010006021a0014010e0122020603220106042202"
string(114) "00000002140506001704546573741401110576616c75651105666972737406011a0014010e010006021a0014010e0122020603220106042202"
array(5) {
[0]=>
object(Test)#7 (1) {
["prop"]=>
string(5) "first"
}
[1]=>
object(Test)#8 (1) {
["prop"]=>
NULL
}
[2]=>
object(Test)#9 (1) {
["prop"]=>
object(Test)#8 (1) {
["prop"]=>
NULL
}
}
[3]=>
object(Test)#7 (1) {
["prop"]=>
string(5) "first"
}
[4]=>
object(Test)#8 (1) {
["prop"]=>
NULL
}
}
array(5) {
[0]=>
object(Vest)#8 (1) {
["value"]=>
string(5) "first"
}
[1]=>
object(Vest)#7 (1) {
["value"]=>
NULL
}
[2]=>
object(Vest)#9 (1) {
["value"]=>
object(Vest)#7 (1) {
["value"]=>
NULL
}
}
[3]=>
object(Vest)#8 (1) {
["value"]=>
string(5) "first"
}
[4]=>
object(Vest)#7 (1) {
["value"]=>
NULL
}
}
igbinary-3.2.15/tests/__serialize_010.phpt 0000664 0001750 0001750 00000003026 14532662345 017441 0 ustar tyson tyson --TEST--
__serialize() mechanism (010): handle references in array returned by __serialize
--SKIPIF--
--FILE--
prop, $this->prop2];
}
public function __unserialize(array $data) {
$this->prop = $data[0];
$this->prop2 = $data[1];
if (!$this->prop) {
throw new RuntimeException("Threw from __unserialize");
}
}
public function __destruct() {
// should not be called
echo "Called destruct\n";
}
}
$test = new Test;
$test->prop = &$test;
$test->prop2 = [&$test];
var_dump(bin2hex($s = igbinary_serialize($test)));
var_dump(igbinary_unserialize($s));
unset($test->prop);
$test->prop = false;
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
igbinary_unserialize($s);
} catch (RuntimeException $e) {
echo "message={$e->getMessage()}\n";
}
echo "Calling gc_collect_cycles\n";
gc_collect_cycles();
echo "After call to gc_collect_cycles\n";
?>
--EXPECT--
string(50) "00000002170454657374140206002200060114010600252200"
object(Test)#2 (2) {
["prop"]=>
*RECURSION*
["prop2"]=>
array(1) {
[0]=>
*RECURSION*
}
}
string(48) "000000021704546573741402060004060114010600252200"
message=Threw from __unserialize
Calling gc_collect_cycles
Called destruct
After call to gc_collect_cycles
Called destruct igbinary-3.2.15/tests/__serialize_011.phpt 0000664 0001750 0001750 00000005340 14532662345 017443 0 ustar tyson tyson --TEST--
__unserializing deeply nested structures
--SKIPIF--
--FILE--
childs];
}
public function __unserialize(array $data)
{
list($this->childs) = $data;
}
}
function createTree ($width, $depth) {
$root = new Node();
$nextLevel = [$root];
for ($level=1; $level<$depth; $level++) {
$levelRoots = $nextLevel;
$nextLevel = [];
while (count($levelRoots) > 0) {
$levelRoot = array_shift($levelRoots);
for ($w = 0; $w < $width; $w++) {
$tester = new Node();
$levelRoot->childs[] = $tester;
$nextLevel[] = $tester;
}
}
}
return $root;
}
$width = 3;
ob_implicit_flush();
foreach (range(1, 8) as $depth) {
$tree = createTree($width, $depth);
echo "Testcase tree $width x $depth".PHP_EOL;
echo "> Serializing now".PHP_EOL;
$serialized = igbinary_serialize($tree);
echo "> Unserializing now".PHP_EOL;
$tree = igbinary_unserialize($serialized);
// Lets test whether all is ok!
$expectedSize = ($width**$depth - 1)/($width-1);
$nodes = [$tree];
$count = 0;
while (count($nodes) > 0) {
$count++;
$node = array_shift($nodes);
foreach ($node->childs as $node) {
$nodes[] = $node;
}
}
echo "> Unserialized total node count was $count, expected $expectedSize: ".($expectedSize === $count ? 'CORRECT!' : 'INCORRECT');
echo PHP_EOL;
echo PHP_EOL;
}
?>
--EXPECT--
Testcase tree 3 x 1
> Serializing now
> Unserializing now
> Unserialized total node count was 1, expected 1: CORRECT!
Testcase tree 3 x 2
> Serializing now
> Unserializing now
> Unserialized total node count was 4, expected 4: CORRECT!
Testcase tree 3 x 3
> Serializing now
> Unserializing now
> Unserialized total node count was 13, expected 13: CORRECT!
Testcase tree 3 x 4
> Serializing now
> Unserializing now
> Unserialized total node count was 40, expected 40: CORRECT!
Testcase tree 3 x 5
> Serializing now
> Unserializing now
> Unserialized total node count was 121, expected 121: CORRECT!
Testcase tree 3 x 6
> Serializing now
> Unserializing now
> Unserialized total node count was 364, expected 364: CORRECT!
Testcase tree 3 x 7
> Serializing now
> Unserializing now
> Unserialized total node count was 1093, expected 1093: CORRECT!
Testcase tree 3 x 8
> Serializing now
> Unserializing now
> Unserialized total node count was 3280, expected 3280: CORRECT!
igbinary-3.2.15/tests/__serialize_012.phpt 0000664 0001750 0001750 00000002121 14532662345 017436 0 ustar tyson tyson --TEST--
Test unserialization of classes derived from ArrayIterator
--SKIPIF--
--FILE--
object(Foo1)#3 (1) {
["storage":"ArrayIterator":private]=>
array(0) {
}
}
[1]=>
object(Foo2)#4 (0) {
}
}
array(2) {
[0]=>
object(__PHP_Incomplete_Class)#4 (5) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Bar1"
["0"]=>
int(0)
["1"]=>
array(0) {
}
["2"]=>
array(0) {
}
["3"]=>
NULL
}
[1]=>
object(__PHP_Incomplete_Class)#3 (1) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Bar2"
}
}
igbinary-3.2.15/tests/__serialize_013.phpt 0000664 0001750 0001750 00000005431 14532662345 017446 0 ustar tyson tyson --TEST--
__serialize() mechanism (013): Properties are still typed after unserialization
--SKIPIF--
= 80000) { echo "skip different error message format"; }
?>
--FILE--
i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [$t->std];
var_dump($t);
var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
$t2->i = 'x';
} catch (Error $e) {
echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
$t2->s = false;
} catch (Error $e) {
echo "s: " . $e->getMessage() . "\n";
}
$t2->s = 'other';
try {
$t2->o = null;
} catch (Error $e) {
echo "o: " . $e->getMessage() . "\n";
}
try {
$t2->a = null;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
try {
$t2->stdClass = $t;
} catch (Error $e) {
echo "stdClass: " . $e->getMessage() . "\n";
}
try {
$t2->a = $t2;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
--EXPECT--
object(Test)#1 (5) {
["i"]=>
int(1)
["s"]=>
string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
array(1) {
[0]=>
object(stdClass)#2 (1) {
["key"]=>
string(5) "value"
}
}
["std"]=>
object(stdClass)#2 (1) {
["key"]=>
string(5) "value"
}
}
string(142) "000000021704546573741406110169060111017311056f7468657211016f220000110161140106001708737464436c617373140111036b6579110576616c756511037374642202"
object(Test)#3 (5) {
["i"]=>
int(1)
["s"]=>
string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
array(1) {
[0]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
["std"]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
i: Typed property Test::$i must be int, string used
s: Typed property Test::$s must be string or null, bool used
o: Typed property Test::$o must be object, null used
a: Typed property Test::$a must be array, null used
stdClass: Typed property Test::$stdClass must be an instance of stdClass, Test used
a: Typed property Test::$a must be array, Test used
object(Test)#3 (5) {
["i"]=>
int(1)
["s"]=>
string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
array(1) {
[0]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
["std"]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
igbinary-3.2.15/tests/__serialize_013_php8.phpt 0000664 0001750 0001750 00000005427 14532662345 020412 0 ustar tyson tyson --TEST--
__serialize() mechanism (013): Properties are still typed after unserialization (php8)
--SKIPIF--
--FILE--
i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [$t->std];
var_dump($t);
var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
$t2->i = 'x';
} catch (Error $e) {
echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
$t2->s = false;
} catch (Error $e) {
echo "s: " . str_replace('false', 'bool', $e->getMessage()) . "\n";
}
$t2->s = 'other';
try {
$t2->o = null;
} catch (Error $e) {
echo "o: " . $e->getMessage() . "\n";
}
try {
$t2->a = null;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
try {
$t2->stdClass = $t;
} catch (Error $e) {
echo "stdClass: " . $e->getMessage() . "\n";
}
try {
$t2->a = $t2;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
?>
--EXPECT--
object(Test)#1 (5) {
["i"]=>
int(1)
["s"]=>
string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
array(1) {
[0]=>
object(stdClass)#2 (1) {
["key"]=>
string(5) "value"
}
}
["std"]=>
object(stdClass)#2 (1) {
["key"]=>
string(5) "value"
}
}
string(142) "000000021704546573741406110169060111017311056f7468657211016f220000110161140106001708737464436c617373140111036b6579110576616c756511037374642202"
object(Test)#3 (5) {
["i"]=>
int(1)
["s"]=>
string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
array(1) {
[0]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
["std"]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
i: Cannot assign string to property Test::$i of type int
s: Cannot assign bool to property Test::$s of type ?string
o: Cannot assign null to property Test::$o of type object
a: Cannot assign null to property Test::$a of type array
stdClass: Cannot assign Test to property Test::$stdClass of type stdClass
a: Cannot assign Test to property Test::$a of type array
object(Test)#3 (5) {
["i"]=>
int(1)
["s"]=>
string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
array(1) {
[0]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
["std"]=>
object(stdClass)#4 (1) {
["key"]=>
string(5) "value"
}
}
igbinary-3.2.15/tests/__serialize_014.phpt 0000664 0001750 0001750 00000003037 14532662345 017447 0 ustar tyson tyson --TEST--
__serialize() mechanism (014): Uninitialized properties can be serialized and unserialized
--SKIPIF--
= 80000) { echo "skip different error message format"; }
?>
--FILE--
o = new stdClass();
unset($m->o);
$m->s = 'other';
unset($m->s);
$m->i = 42;
unset($m->i);
// Should have the same serialized representation.
var_dump($m);
var_dump(bin2hex($s = igbinary_serialize($m)));
try {
$m->i = 'i';
} catch (TypeError $e) {
echo $e->getMessage() . "\n";
}
--EXPECT--
object(MyClass)#1 (0) {
["o"]=>
uninitialized(stdClass)
["s"]=>
uninitialized(string)
["i"]=>
uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
object(MyClass)#2 (0) {
["o"]=>
uninitialized(stdClass)
["s"]=>
uninitialized(string)
["i"]=>
uninitialized(?int)
}
object(MyClass)#2 (0) {
["o"]=>
uninitialized(stdClass)
["s"]=>
uninitialized(string)
["i"]=>
uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
Typed property MyClass::$i must be int or null, string used
igbinary-3.2.15/tests/__serialize_014_php8.phpt 0000664 0001750 0001750 00000002664 14532662345 020413 0 ustar tyson tyson --TEST--
__serialize() mechanism (014): Uninitialized properties can be serialized and unserialized
--SKIPIF--
--FILE--
o = new stdClass();
unset($m->o);
$m->s = 'other';
unset($m->s);
$m->i = 42;
unset($m->i);
// Should have the same serialized representation.
var_dump($m);
var_dump(bin2hex($s = igbinary_serialize($m)));
try {
$m->i = 'i';
} catch (TypeError $e) {
echo $e->getMessage() . "\n";
}
--EXPECT--
object(MyClass)#1 (0) {
["o"]=>
uninitialized(stdClass)
["s"]=>
uninitialized(string)
["i"]=>
uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
object(MyClass)#2 (0) {
["o"]=>
uninitialized(stdClass)
["s"]=>
uninitialized(string)
["i"]=>
uninitialized(?int)
}
object(MyClass)#2 (0) {
["o"]=>
uninitialized(stdClass)
["s"]=>
uninitialized(string)
["i"]=>
uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
Cannot assign string to property MyClass::$i of type ?int igbinary-3.2.15/tests/__serialize_015.phpt 0000664 0001750 0001750 00000004702 14532662345 017450 0 ustar tyson tyson --TEST--
__serialize() mechanism (015): Uninitialized properties from __sleep should throw when serializing
--SKIPIF--
--FILE--
$name = $value;
}
}
class SimplePrivate {
private ?int $i;
public function __sleep() {
return ['i'];
}
public function __set($name, $value) {
$this->$name = $value;
}
}
// 00000002 -- header
// 17 03 4d79436c617373 -- object of type "MyClass"
// 14 03 000000 -- with 3 uninitialized properties
$m = new OSI();
function try_serialize_invalid($o) {
try {
var_dump(bin2hex($s = igbinary_serialize($o)));
} catch (Error $e) {
printf("Caught %s: %s\n", get_class($e), $e->getMessage());
}
}
// These should throw whether or not the uninitialized property is nullable.
try_serialize_invalid(new OSI());
try_serialize_invalid(new SimplePublic());
try_serialize_invalid(new SimpleProtected());
try_serialize_invalid(new SimplePrivate());
$s = new SimplePublic();
$s->i = null;
try_serialize_invalid($s);
$s = new SimpleProtected();
$s->i = 0;
try_serialize_invalid($s);
$s = new SimplePrivate();
$s->i = null;
try_serialize_invalid($s);
--EXPECT--
Caught Error: Typed property OSI::$o must not be accessed before initialization (in __sleep)
Caught Error: Typed property SimplePublic::$i must not be accessed before initialization (in __sleep)
Caught Error: Typed property SimpleProtected::$i must not be accessed before initialization (in __sleep)
Caught Error: Typed property SimplePrivate::$i must not be accessed before initialization (in __sleep)
string(48) "00000002170c53696d706c655075626c6963140111016900"
string(62) "00000002170f53696d706c6550726f74656374656414011104002a00690600"
string(80) "00000002170d53696d706c6550726976617465140111100053696d706c6550726976617465006900"
igbinary-3.2.15/tests/__serialize_016.phpt 0000664 0001750 0001750 00000006730 14532662345 017454 0 ustar tyson tyson --TEST--
__serialize() mechanism (016): Properties are still typed after unserialization (references)
--SKIPIF--
= 80000) { echo "skip different error message format"; }
?>
--FILE--
i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [&$t->std, &$t->i, &$t->s, &$t->o];
$t->std->key = &$t->a;
var_dump($t);
var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
$t2->i = 'x';
} catch (Error $e) {
echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
$t2->s = false;
} catch (Error $e) {
echo "s: " . $e->getMessage() . "\n";
}
$t2->s = 'other';
try {
$t2->o = null;
} catch (Error $e) {
echo "o: " . $e->getMessage() . "\n";
}
try {
$t2->a = null;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
try {
$t2->stdClass = $t;
} catch (Error $e) {
echo "stdClass: " . $e->getMessage() . "\n";
}
try {
$t2->a = $t2;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
--EXPECT--
object(Test)#1 (5) {
["i"]=>
&int(1)
["s"]=>
&string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
&array(4) {
[0]=>
&object(stdClass)#2 (1) {
["key"]=>
*RECURSION*
}
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
["std"]=>
&object(stdClass)#2 (1) {
["key"]=>
&array(4) {
[0]=>
*RECURSION*
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
}
}
string(176) "0000000217045465737414061101692506011101732511056f7468657211016f252200001101612514040600251708737464436c617373140111036b65792501030601250101060225010206032522001103737464252204"
object(Test)#3 (5) {
["i"]=>
&int(1)
["s"]=>
&string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
&array(4) {
[0]=>
&object(stdClass)#4 (1) {
["key"]=>
*RECURSION*
}
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
["std"]=>
&object(stdClass)#4 (1) {
["key"]=>
&array(4) {
[0]=>
*RECURSION*
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
}
}
i: Typed property Test::$i must be int, string used
s: Typed property Test::$s must be string or null, bool used
o: Typed property Test::$o must be object, null used
a: Typed property Test::$a must be array, null used
stdClass: Typed property Test::$stdClass must be an instance of stdClass, Test used
a: Typed property Test::$a must be array, Test used
object(Test)#3 (5) {
["i"]=>
&int(1)
["s"]=>
&string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
&array(4) {
[0]=>
&object(stdClass)#4 (1) {
["key"]=>
*RECURSION*
}
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
["std"]=>
&object(stdClass)#4 (1) {
["key"]=>
&array(4) {
[0]=>
*RECURSION*
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
}
} igbinary-3.2.15/tests/__serialize_016_php8.phpt 0000664 0001750 0001750 00000007637 14532662345 020422 0 ustar tyson tyson --TEST--
__serialize() mechanism (016): Properties are still typed after unserialization (references)
--SKIPIF--
= 90000) { echo "skip requires php < 9.0 when testing that the deprecation has no impact on igbinary functionality\n"; }
?>
--FILE--
= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }
/** @property mixed $std undeclared dynamic property */
class Test {
public int $i = 0;
public ?string $s = 's';
public object $o;
public stdClass $stdClass;
public array $a = [];
}
$t = new Test();
$t->i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [&$t->std, &$t->i, &$t->s, &$t->o];
$t->std->key = &$t->a;
var_dump($t);
var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
$t2->i = 'x';
} catch (Error $e) {
echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
$t2->s = false;
} catch (Error $e) {
// The error message is "Cannot assign false" in php 8.3+
echo "s: " . str_replace('false', 'bool', $e->getMessage()) . "\n";
}
$t2->s = 'other';
try {
$t2->o = null;
} catch (Error $e) {
echo "o: " . $e->getMessage() . "\n";
}
try {
$t2->a = null;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
try {
$t2->stdClass = $t;
} catch (Error $e) {
echo "stdClass: " . $e->getMessage() . "\n";
}
try {
$t2->a = $t2;
} catch (Error $e) {
echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
?>
--EXPECT--
object(Test)#1 (5) {
["i"]=>
&int(1)
["s"]=>
&string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
&array(4) {
[0]=>
&object(stdClass)#2 (1) {
["key"]=>
*RECURSION*
}
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
["std"]=>
&object(stdClass)#2 (1) {
["key"]=>
&array(4) {
[0]=>
*RECURSION*
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
}
}
string(176) "0000000217045465737414061101692506011101732511056f7468657211016f252200001101612514040600251708737464436c617373140111036b65792501030601250101060225010206032522001103737464252204"
object(Test)#3 (5) {
["i"]=>
&int(1)
["s"]=>
&string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
&array(4) {
[0]=>
&object(stdClass)#4 (1) {
["key"]=>
*RECURSION*
}
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
["std"]=>
&object(stdClass)#4 (1) {
["key"]=>
&array(4) {
[0]=>
*RECURSION*
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
}
}
i: Cannot assign string to property Test::$i of type int
s: Cannot assign bool to property Test::$s of type ?string
o: Cannot assign null to property Test::$o of type object
a: Cannot assign null to property Test::$a of type array
stdClass: Cannot assign Test to property Test::$stdClass of type stdClass
a: Cannot assign Test to property Test::$a of type array
object(Test)#3 (5) {
["i"]=>
&int(1)
["s"]=>
&string(5) "other"
["o"]=>
*RECURSION*
["stdClass"]=>
uninitialized(stdClass)
["a"]=>
&array(4) {
[0]=>
&object(stdClass)#4 (1) {
["key"]=>
*RECURSION*
}
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
["std"]=>
&object(stdClass)#4 (1) {
["key"]=>
&array(4) {
[0]=>
*RECURSION*
[1]=>
&int(1)
[2]=>
&string(5) "other"
[3]=>
*RECURSION*
}
}
}
igbinary-3.2.15/tests/__serialize_017.phpt 0000664 0001750 0001750 00000001643 14532662345 017453 0 ustar tyson tyson --TEST--
__serialize() mechanism (001): Basics
--SKIPIF--
--FILE--
$this->prop];
}
public function __unserialize(array $data) {
echo "In __unserialize\n";
if (!$data['prop']) {
throw new RuntimeException("bad prop");
}
}
public function __destruct() {
echo "In __destruct\n";
}
}
$test = new Test;
$test->prop = new Test();
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
igbinary_unserialize($s);
} catch (RuntimeException $e) {
echo "Caught {$e->getMessage()}\n";
}
?>
--EXPECT--
string(50) "000000021704546573741401110470726f701a0014010e0100"
In __unserialize
Caught bad prop
In __destruct
In __destruct igbinary-3.2.15/tests/__serialize_018.phpt 0000664 0001750 0001750 00000004464 14532662345 017460 0 ustar tyson tyson --TEST--
__serialize() freed on unserialize exception without calling destructor.
--SKIPIF--
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
$this->prop, "value" => $this->prop2];
}
public function __unserialize(array $data) {
echo "In __unserialize Test\n";
}
public function __destruct() {
echo "In __destruct Test\n";
}
}
$test = new Test;
$test->prop = new ThrowsInUnserialize();
$test->prop2 = "barfoo";
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
var_dump(igbinary_unserialize($s));
} catch (Error $e) {
echo "Caught: {$e->getMessage()}\n";
}
gc_collect_cycles();
echo "After gc_collect_cycles\n";
unset($test);
gc_collect_cycles();
echo "And for serialize/unserialize\n";
$test = new Test;
$test->prop = new ThrowsInUnserialize();
$test->prop2 = "barfoo";
var_dump(bin2hex($s = serialize($test)));
try {
var_dump(unserialize($s));
} catch (Error $e) {
echo "Caught: {$e->getMessage()}\n";
}
?>
--EXPECT--
string(122) "000000021704546573741402060017135468726f7773496e556e73657269616c697a651d09746573742064617461110576616c75651106626172666f6f"
Unserializing test data
In __destruct ThrowsInUnserialize
Caught: test data
After gc_collect_cycles
In __destruct Test
In __destruct ThrowsInUnserialize
And for serialize/unserialize
string(168) "4f3a343a2254657374223a323a7b693a303b433a31393a225468726f7773496e556e73657269616c697a65223a393a7b7465737420646174617d733a353a2276616c7565223b733a363a22626172666f6f223b7d"
Unserializing test data
In __destruct ThrowsInUnserialize
Caught: test data
In __destruct Test
In __destruct ThrowsInUnserialize igbinary-3.2.15/tests/__serialize_019.phpt 0000664 0001750 0001750 00000002515 14532662345 017454 0 ustar tyson tyson --TEST--
__serialize() freed on unserialize exception without calling destructor.
--SKIPIF--
--FILE--
$this->prop, "value" => $this->prop2];
}
public function __unserialize(array $data) {
echo "In __unserialize Test\n";
$this->prop = $data[0];
$this->prop2 = $data['value'];
unset($data[0]);
unset($data['value']);
}
public function __destruct() {
echo "In __destruct Test\n";
}
}
$obj = new stdClass();
$testObj = new Test();
$testObj->prop = 123;
$testObj->prop2 = ['xyz'];
$obj->test = 'bar';
$obj->value = &$testObj;
var_dump(bin2hex($s = igbinary_serialize($obj)));
var_dump(igbinary_unserialize($s));
echo "Done\n";
?>
--EXPECT--
string(116) "000000021708737464436c61737314021104746573741103626172110576616c75652517045465737414020600067b0e0314010600110378797a"
In __unserialize Test
object(stdClass)#3 (2) {
["test"]=>
string(3) "bar"
["value"]=>
object(Test)#4 (2) {
["prop"]=>
int(123)
["prop2"]=>
array(1) {
[0]=>
string(3) "xyz"
}
}
}
In __destruct Test
Done
In __destruct Test
igbinary-3.2.15/tests/__serialize_020.phpt 0000664 0001750 0001750 00000040665 14532662345 017454 0 ustar tyson tyson --TEST--
issue when serializing/deserializing nested objects with __serialize
--SKIPIF--
--FILE--
events[] = $event;
$this->transports[$event->getTransport()] = true;
}
public function getEvents(string $name = null): array
{
return $this->events;
}
}
final class MessageEvent extends Event
{
private $propagationStopped = false;
private $message;
private $envelope;
private $transport;
private $queued;
public function __construct(RawMessage $message, Envelope $envelope, string $transport, bool $queued = false)
{
$this->message = $message;
$this->envelope = $envelope;
$this->transport = $transport;
$this->queued = $queued;
}
public function getTransport(): string
{
return $this->transport;
}
public function getMessage(): RawMessage
{
return $this->message;
}
}
class Envelope
{
protected $sender;
protected $recipients = [];
protected $senderSet = false;
protected $recipientsSet = false;
protected $message;
public function __construct(Address $sender, array $recipients)
{
$this->setSender($sender);
$this->setRecipients($recipients);
}
public static function create(RawMessage $message): self
{
return new DelayedEnvelope($message);
}
public function setSender(Address $sender): void
{
$this->sender = $sender;
}
public function setRecipients(array $recipients): void
{
$this->recipients = [];
foreach ($recipients as $recipient) {
$this->recipients[] = new Address($recipient->getAddress());
}
}
public function getRecipients(): array
{
return $this->recipients;
}
}
final class DelayedEnvelope extends Envelope
{
public function __construct(Message $message)
{
$this->message = $message;
}
public function setSender(Address $sender): void
{
parent::setSender($sender);
$this->senderSet = true;
}
public function setRecipients(array $recipients): void
{
parent::setRecipients($recipients);
$this->recipientsSet = parent::getRecipients();
}
}
final class Address
{
private $address;
private $name;
public function __construct(string $address, string $name = '')
{
$this->address = trim($address);
$this->name = trim(str_replace(["\n", "\r"], '', $name));
}
/**
* @param Address|string $address
*/
public static function create($address): self
{
if ($address instanceof self) {
return $address;
}
if (\is_string($address)) {
if (false === strpos($address, '<')) {
return new self($address);
}
return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"'));
}
throw new InvalidArgumentException(sprintf('An address can be an instance of Address or a string ("%s" given).', get_debug_type($address)));
}
public static function createArray(array $addresses): array
{
$addrs = [];
foreach ($addresses as $address) {
$addrs[] = self::create($address);
}
return $addrs;
}
}
abstract class AbstractHeader
{
private static $encoder;
private $name;
private $lineLength = 76;
private $lang;
private $charset = 'utf-8';
protected $addresses = [];
public function __construct(string $name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
final class Headers
{
private $headers = [];
private $lineLength = 76;
public function __construct(...$headers)
{
foreach ($headers as $header) {
$this->add($header);
}
}
public function __clone()
{
foreach ($this->headers as $name => $collection) {
foreach ($collection as $i => $header) {
$this->headers[$name][$i] = clone $header;
}
}
}
public function addMailboxListHeader(string $name, array $addresses): self
{
return $this->add(new MailboxListHeader($name, Address::createArray($addresses)));
}
public function add($header): self
{
self::checkHeaderClass($header);
$name = strtolower($header->getName());
$this->headers[$name][] = $header;
return $this;
}
public function get(string $name)
{
$name = strtolower($name);
if (!isset($this->headers[$name])) {
return null;
}
$values = array_values($this->headers[$name]);
return array_shift($values);
}
public function all(string $name = null): iterable
{
if (null === $name) {
foreach ($this->headers as $name => $collection) {
foreach ($collection as $header) {
yield $name => $header;
}
}
} elseif (isset($this->headers[strtolower($name)])) {
foreach ($this->headers[strtolower($name)] as $header) {
yield $header;
}
}
}
public static function checkHeaderClass($header): void
{
$name = strtolower($header->getName());
}
}
final class MailboxListHeader extends AbstractHeader
{
public function __construct(string $name, array $addresses)
{
parent::__construct($name);
$this->addAddresses($addresses);
}
public function addAddresses(array $addresses)
{
foreach ($addresses as $address) {
$this->addAddress($address);
}
}
/**
* @throws RfcComplianceException
*/
public function addAddress(Address $address)
{
$this->addresses[] = $address;
}
}
class RawMessage
{
protected $message;
protected $headers;
protected $body;
protected $text;
protected $textCharset;
protected $html;
protected $htmlCharset;
protected $attachments = [];
public function __construct($message)
{
$this->message = $message;
}
public function __serialize(): array
{
return [$this->message];
}
public function __unserialize(array $data): void
{
[$this->message] = $data;
}
}
class Message extends RawMessage
{
public function __construct(Headers $headers = null, AbstractPart $body = null)
{
$this->headers = $headers ? clone $headers : new Headers();
$this->body = $body;
}
public function __clone()
{
$this->headers = clone $this->headers;
if (null !== $this->body) {
$this->body = clone $this->body;
}
}
public function getHeaders(): Headers { return $this->headers; }
public function __serialize(): array
{
return [$this->headers];
}
public function __unserialize(array $data): void
{
[$this->headers] = $data;
}
}
class Email extends Message
{
public function to(...$addresses)
{
return $this->setListAddressHeaderBody('To', $addresses);
}
private function setListAddressHeaderBody(string $name, array $addresses)
{
$addresses = Address::createArray($addresses);
$headers = $this->getHeaders();
$headers->addMailboxListHeader($name, $addresses);
return $this;
}
/**
* @internal
*/
public function __serialize(): array
{
return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()];
}
/**
* @internal
*/
public function __unserialize(array $data): void
{
[$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data;
parent::__unserialize($parentData);
}
}
$messageEvents = new MessageEvents();
$messageEvents->add(new MessageEvent($message1 = (new Email())->to('alice@example.com'), Envelope::create($message1), 'null://null'));
$messageEvents->add(new MessageEvent($message2 = (new Email())->to('bob@example.com'), Envelope::create($message2), 'null://null'));
var_dump($messageEvents); // Comment/uncomment to trigger the bug
var_dump('headers_before', $messageEvents->getEvents()[0]->getMessage()->getHeaders() === $messageEvents->getEvents()[1]->getMessage()->getHeaders());
$ser = igbinary_serialize($messageEvents);
$messageEvents = igbinary_unserialize($ser);
// should dump "false", but dumps "true" the "var_dump($messageEvents)" is not commented
var_dump('headers_after', $messageEvents->getEvents()[0]->getMessage()->getHeaders() === $messageEvents->getEvents()[1]->getMessage()->getHeaders());
?>
--EXPECT--
object(MessageEvents)#1 (2) {
["events":"MessageEvents":private]=>
array(2) {
[0]=>
object(MessageEvent)#2 (5) {
["propagationStopped":"MessageEvent":private]=>
bool(false)
["message":"MessageEvent":private]=>
object(Email)#3 (8) {
["message":protected]=>
NULL
["headers":protected]=>
object(Headers)#4 (2) {
["headers":"Headers":private]=>
array(1) {
["to"]=>
array(1) {
[0]=>
object(MailboxListHeader)#6 (5) {
["name":"AbstractHeader":private]=>
string(2) "To"
["lineLength":"AbstractHeader":private]=>
int(76)
["lang":"AbstractHeader":private]=>
NULL
["charset":"AbstractHeader":private]=>
string(5) "utf-8"
["addresses":protected]=>
array(1) {
[0]=>
object(Address)#5 (2) {
["address":"Address":private]=>
string(17) "alice@example.com"
["name":"Address":private]=>
string(0) ""
}
}
}
}
}
["lineLength":"Headers":private]=>
int(76)
}
["body":protected]=>
NULL
["text":protected]=>
NULL
["textCharset":protected]=>
NULL
["html":protected]=>
NULL
["htmlCharset":protected]=>
NULL
["attachments":protected]=>
array(0) {
}
}
["envelope":"MessageEvent":private]=>
object(DelayedEnvelope)#7 (5) {
["sender":protected]=>
NULL
["recipients":protected]=>
array(0) {
}
["senderSet":protected]=>
bool(false)
["recipientsSet":protected]=>
bool(false)
["message":protected]=>
object(Email)#3 (8) {
["message":protected]=>
NULL
["headers":protected]=>
object(Headers)#4 (2) {
["headers":"Headers":private]=>
array(1) {
["to"]=>
array(1) {
[0]=>
object(MailboxListHeader)#6 (5) {
["name":"AbstractHeader":private]=>
string(2) "To"
["lineLength":"AbstractHeader":private]=>
int(76)
["lang":"AbstractHeader":private]=>
NULL
["charset":"AbstractHeader":private]=>
string(5) "utf-8"
["addresses":protected]=>
array(1) {
[0]=>
object(Address)#5 (2) {
["address":"Address":private]=>
string(17) "alice@example.com"
["name":"Address":private]=>
string(0) ""
}
}
}
}
}
["lineLength":"Headers":private]=>
int(76)
}
["body":protected]=>
NULL
["text":protected]=>
NULL
["textCharset":protected]=>
NULL
["html":protected]=>
NULL
["htmlCharset":protected]=>
NULL
["attachments":protected]=>
array(0) {
}
}
}
["transport":"MessageEvent":private]=>
string(11) "null://null"
["queued":"MessageEvent":private]=>
bool(false)
}
[1]=>
object(MessageEvent)#8 (5) {
["propagationStopped":"MessageEvent":private]=>
bool(false)
["message":"MessageEvent":private]=>
object(Email)#9 (8) {
["message":protected]=>
NULL
["headers":protected]=>
object(Headers)#10 (2) {
["headers":"Headers":private]=>
array(1) {
["to"]=>
array(1) {
[0]=>
object(MailboxListHeader)#12 (5) {
["name":"AbstractHeader":private]=>
string(2) "To"
["lineLength":"AbstractHeader":private]=>
int(76)
["lang":"AbstractHeader":private]=>
NULL
["charset":"AbstractHeader":private]=>
string(5) "utf-8"
["addresses":protected]=>
array(1) {
[0]=>
object(Address)#11 (2) {
["address":"Address":private]=>
string(15) "bob@example.com"
["name":"Address":private]=>
string(0) ""
}
}
}
}
}
["lineLength":"Headers":private]=>
int(76)
}
["body":protected]=>
NULL
["text":protected]=>
NULL
["textCharset":protected]=>
NULL
["html":protected]=>
NULL
["htmlCharset":protected]=>
NULL
["attachments":protected]=>
array(0) {
}
}
["envelope":"MessageEvent":private]=>
object(DelayedEnvelope)#13 (5) {
["sender":protected]=>
NULL
["recipients":protected]=>
array(0) {
}
["senderSet":protected]=>
bool(false)
["recipientsSet":protected]=>
bool(false)
["message":protected]=>
object(Email)#9 (8) {
["message":protected]=>
NULL
["headers":protected]=>
object(Headers)#10 (2) {
["headers":"Headers":private]=>
array(1) {
["to"]=>
array(1) {
[0]=>
object(MailboxListHeader)#12 (5) {
["name":"AbstractHeader":private]=>
string(2) "To"
["lineLength":"AbstractHeader":private]=>
int(76)
["lang":"AbstractHeader":private]=>
NULL
["charset":"AbstractHeader":private]=>
string(5) "utf-8"
["addresses":protected]=>
array(1) {
[0]=>
object(Address)#11 (2) {
["address":"Address":private]=>
string(15) "bob@example.com"
["name":"Address":private]=>
string(0) ""
}
}
}
}
}
["lineLength":"Headers":private]=>
int(76)
}
["body":protected]=>
NULL
["text":protected]=>
NULL
["textCharset":protected]=>
NULL
["html":protected]=>
NULL
["htmlCharset":protected]=>
NULL
["attachments":protected]=>
array(0) {
}
}
}
["transport":"MessageEvent":private]=>
string(11) "null://null"
["queued":"MessageEvent":private]=>
bool(false)
}
}
["transports":"MessageEvents":private]=>
array(1) {
["null://null"]=>
bool(true)
}
}
string(14) "headers_before"
bool(false)
string(13) "headers_after"
bool(false) igbinary-3.2.15/tests/__serialize_021.phpt 0000664 0001750 0001750 00000002030 14532662345 017435 0 ustar tyson tyson --TEST--
__serialize() mechanism (021): Temporary references in serialized arrays should be properly deduplicated
--FILE--
i = $i;
}
public function __serialize() {
$j = $this->i + 0x7700;
return [&$j, &$j];
}
public function __unserialize(array $data) {
list($this->i) = $data;
}
}
$values = [];
for ($i = 0; $i < 256; $i++) {
$values[] = new Test($i);
}
$ser = igbinary_serialize($values);
$result = igbinary_unserialize($ser);
printf("Count=%d\n", count($values));
$j = 0;
foreach ($values as $i => $v) {
if ($i !== $j) {
echo "Unexpected key $i, expected $j\n";
}
if ($v->i !== $j) {
echo "Unexpected value {$v->i}, expected $j\n";
}
$j++;
}
echo "Done\n";
?>
--EXPECT--
Count=256
Done
igbinary-3.2.15/tests/__serialize_022.phpt 0000664 0001750 0001750 00000001777 14532662345 017457 0 ustar tyson tyson --TEST--
__serialize() mechanism (021): Test __serialize without __unserialize
--SKIPIF--
--FILE--
'value'];
public function __serialize() {
return self::SOME_CONST;
}
public static function test_serialize() {
$x = igbinary_serialize([self::SOME_CONST, new self(), new self()]);
// aggressively reuses arrays
echo urlencode($x), "\n";
var_dump(igbinary_unserialize($x));
}
}
Test::test_serialize();
?>
--EXPECT--
%00%00%00%02%14%03%06%00%14%01%11%03key%11%05value%06%01%17%04Test%14%01%0E%00%0E%01%06%02%1A%02%14%01%0E%00%0E%01
array(3) {
[0]=>
array(1) {
["key"]=>
string(5) "value"
}
[1]=>
object(Test)#2 (1) {
["key"]=>
string(5) "value"
}
[2]=>
object(Test)#1 (1) {
["key"]=>
string(5) "value"
}
}
igbinary-3.2.15/tests/igbinary_001.phpt 0000664 0001750 0001750 00000001053 14532662345 016756 0 ustar tyson tyson --TEST--
Check for igbinary presence
--SKIPIF--
--FILE--
--EXPECT--
igbinary extension is available
igbinary-3.2.15/tests/igbinary_002.phpt 0000664 0001750 0001750 00000001320 14532662345 016754 0 ustar tyson tyson --TEST--
Check for null serialisation
--SKIPIF--
--FILE--
--EXPECT--
null
00
OK
igbinary-3.2.15/tests/igbinary_003.phpt 0000664 0001750 0001750 00000002014 14532662345 016756 0 ustar tyson tyson --TEST--
Check for bool serialisation
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
--EXPECT--
bool true
05
OK
bool false
04
OK
igbinary-3.2.15/tests/igbinary_004.phpt 0000664 0001750 0001750 00000002127 14532662345 016764 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-3.2.15/tests/igbinary_005.phpt 0000664 0001750 0001750 00000001507 14532662345 016766 0 ustar tyson tyson --TEST--
Check for double serialisation
--SKIPIF--
--FILE--
--EXPECT--
double: 123.456
0c405edd2f1a9fbe77
OK
igbinary-3.2.15/tests/igbinary_006.phpt 0000664 0001750 0001750 00000001566 14532662345 016774 0 ustar tyson tyson --TEST--
Check for simple string serialization
--SKIPIF--
--FILE--
--EXPECT--
empty: ""
0d
OK
string: "foobar"
1106666f6f626172
OK
igbinary-3.2.15/tests/igbinary_007.phpt 0000664 0001750 0001750 00000002161 14532662345 016765 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-3.2.15/tests/igbinary_008.phpt 0000664 0001750 0001750 00000002036 14532662345 016767 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-3.2.15/tests/igbinary_009.phpt 0000664 0001750 0001750 00000002705 14532662345 016773 0 ustar tyson tyson --TEST--
Check for reference serialisation
--SKIPIF--
7) {
echo "skip requires php 7.x\n";
}
--INI--
pcre.jit=0
--FILE--
&array(1) {
[0]=>
array(1) {
[0]=>
*RECURSION*
}
}
}
Expected
array(1) {
[0]=>
&array(1) {
[0]=>
*RECURSION*
}
}
(Was normalized)
cyclic $a = array(array(&$a)); $a[0] - testing functionality
14010600251401060014010600250101
OK
But var dump differs:
Actual:
array(1) {
[0]=>
&array(1) {
[0]=>
array(1) {
[0]=>
*RECURSION*
}
}
}
Expected
array(1) {
[0]=>
&array(1) {
[0]=>
*RECURSION*
}
}
(Was normalized) igbinary-3.2.15/tests/igbinary_010.phpt 0000664 0001750 0001750 00000001667 14532662345 016771 0 ustar tyson tyson --TEST--
Array test
--SKIPIF--
--FILE--
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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
array
140211016114021101621101631101641101651101661401110167110168
OK
igbinary-3.2.15/tests/igbinary_012.phpt 0000664 0001750 0001750 00000002431 14532662345 016761 0 ustar tyson tyson --TEST--
Object test
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a140311016106011104002a006206021106004f626a00630603
OK
igbinary-3.2.15/tests/igbinary_013.phpt 0000664 0001750 0001750 00000002000 14532662345 016752 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
object
1402060017034f626a14021101610601110162060206011a0014020e0106030e020604
OK
igbinary-3.2.15/tests/igbinary_014.phpt 0000664 0001750 0001750 00000001226 14532662345 016764 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-3.2.15/tests/igbinary_015.phpt 0000664 0001750 0001750 00000002515 14532662345 016767 0 ustar tyson tyson --TEST--
Check for serialization handler
--SKIPIF--
--EXPECT--
2
14011103666f6f0602
igbinary-3.2.15/tests/igbinary_015b.phpt 0000664 0001750 0001750 00000002543 14532662345 017132 0 ustar tyson tyson --TEST--
Check for serialization handler, ini-directive
--SKIPIF--
--EXPECT--
2
14011103666f6f0602
igbinary-3.2.15/tests/igbinary_015c.phpt 0000664 0001750 0001750 00000002544 14532662345 017134 0 ustar tyson tyson --TEST--
Check for serialization handler
--SKIPIF--
--FILE--
--EXPECT--
read(abcdef10231512dfaz_12311)
write(abcdef10231512dfaz_12311): data:(000000021400)
igbinary-3.2.15/tests/igbinary_016.phpt 0000664 0001750 0001750 00000002265 14532662345 016772 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a140311016106011104002a006206021106004f626a00630603
OK
igbinary-3.2.15/tests/igbinary_017.phpt 0000664 0001750 0001750 00000001773 14532662345 016776 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a140211016106011101620602
OK
igbinary-3.2.15/tests/igbinary_018.phpt 0000664 0001750 0001750 00000002510 14532662345 016765 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
nonexisting
17034f626a140111016300
OK
wrong
17034f706a140100
OK
igbinary-3.2.15/tests/igbinary_019.phpt 0000664 0001750 0001750 00000002056 14532662345 016773 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
autoload
17034f626a140211016106011101620602
OK
igbinary-3.2.15/tests/igbinary_020.phpt 0000664 0001750 0001750 00000002205 14532662345 016757 0 ustar tyson tyson --TEST--
Object test, incomplete class
--SKIPIF--
--FILE--
= 80200) {
// TODO undo workaround when #[AllowDynamicProperties] is added to __PHP_Incomplete_Class
error_reporting(E_ALL & ~E_DEPRECATED);
}
function test($type, $variable, $test) {
$serialized = pack('H*', $variable);
$unserialized = igbinary_unserialize($serialized);
echo $type, "\n";
echo substr(bin2hex($serialized), 8), "\n";
var_dump($unserialized);
// echo "\n";
}
test('incom', '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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECTF--
incom
17034f626a140211016106011101620602
object(__PHP_Incomplete_Class)#%d (3) {
["__PHP_Incomplete_Class_Name"]=>
string(3) "Obj"
["a"]=>
int(1)
["b"]=>
int(2)
}
igbinary-3.2.15/tests/igbinary_021.phpt 0000664 0001750 0001750 00000002546 14532662345 016770 0 ustar tyson tyson --TEST--
Object Serializable interface
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
object
17034f626a1d080000000100000002
OK
igbinary-3.2.15/tests/igbinary_022.phpt 0000664 0001750 0001750 00000003737 14532662345 016774 0 ustar tyson tyson --TEST--
Object test, unserialize_callback_func (PHP < 8.2)
--SKIPIF--
= 80200) echo "skip requires php < 8.2\n"; ?>
--INI--
error_reporting=E_ALL
unserialize_callback_func=autoload
--FILE--
b == 2 ? 'OK' : 'ERROR';
echo "\n";
}
function autoload($classname) {
echo "Autoloading $classname\n";
if (!class_exists(Obj::class)) {
class Obj {
var $a;
var $b;
function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
}
}
}
test('autoload', '0000000217034f626a140211016106011101620602', false);
test('autoload', '0000000217034f626b140211016106011101620602', false);
ini_set('unserialize_callback_func', strtolower('Missing_autoload'));
test('missing_autoload', '0000000217034f626c140211016106011101620602', 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECTF--
Autoloading Obj
autoload
17034f626a140211016106011101620602
OK
Autoloading Obk
%s: igbinary_unserialize(): Function autoload() hasn't defined the class it was called for in %sigbinary_022.php on line 8
autoload
17034f626b140211016106011101620602
%s: test(): %s to load the class definition %Sin %sigbinary_022.php on line 12
ERROR
%s: igbinary_unserialize(): defined (missing_autoload) but not found in %sigbinary_022.php on line 8
missing_autoload
17034f626c140211016106011101620602
%s: test(): %s to load the class definition %Sin %sigbinary_022.php on line 12
ERROR
igbinary-3.2.15/tests/igbinary_022_php82.phpt 0000664 0001750 0001750 00000005665 14532662345 020017 0 ustar tyson tyson --TEST--
Object test, unserialize_callback_func (PHP >= 8.2)
--SKIPIF--
--INI--
error_reporting=E_ALL
unserialize_callback_func=autoload
--FILE--
getMessage()}\n";
return;
}
echo $type, "\n";
echo substr(bin2hex($serialized), 8), "\n";
var_dump($unserialized);
// The read_property handler is set to incomplete_class_get_property,
// making this always return null for __PHP_Incomplete_Class
var_dump($unserialized->b);
echo $unserialized->b == 2 ? 'OK' : 'ERROR';
echo "\n";
}
function autoload($classname) {
echo "Autoloading $classname\n";
if (!class_exists(Obj::class)) {
class Obj {
var $a;
var $b;
function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
}
}
}
test('autoload', '0000000217034f626a140211016106011101620602'); // "Obj"
test('autoload', '0000000217034f626b140211016106011101620602'); // "Obk" failing to autoload
ini_set('unserialize_callback_func', strtolower('Missing_autoload'));
test('missing_autoload', '0000000217034f626c140211016106011101620602'); // Obk" with missing autoload function
/*
* 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECTF--
Autoloading Obj
autoload
17034f626a140211016106011101620602
object(Obj)#1 (2) {
["a"]=>
int(1)
["b"]=>
int(2)
}
int(2)
OK
Autoloading Obk
Warning: igbinary_unserialize(): Function autoload() hasn't defined the class it was called for in %sigbinary_022_php82.php on line 9
autoload
17034f626b140211016106011101620602
object(__PHP_Incomplete_Class)#1 (3) {
["__PHP_Incomplete_Class_Name"]=>
string(3) "Obk"
["a"]=>
int(1)
["b"]=>
int(2)
}
Warning: test(): The script tried to access a property on an incomplete object. Please ensure that the class definition "Obk" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %sigbinary_022_php82.php on line 21
NULL
Warning: test(): The script tried to access a property on an incomplete object. Please ensure that the class definition "Obk" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %sigbinary_022_php82.php on line 22
ERROR
missing_autoload
Caught Invalid callback missing_autoload, function "missing_autoload" not found or invalid function name
igbinary-3.2.15/tests/igbinary_023.phpt 0000664 0001750 0001750 00000001747 14532662345 016774 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
objectrec
17044f626a32140711026161001105002a006262001108004f626a32006363001109004f626a32006f626a17034f626a140311016106011104002a006206021106004f626a006306030e06060111016206021101630603
OK
objectrecarr
17044f626a331401110a004f626a33006f626a731404060017034f626a140311016106001104002a006206001106004f626a0063060406011a0214030e0306000e0406010e05060406021a0214030e0306000e0406020e05060406031a0214030e0306000e0406030e050604
OK
objectselfrec
17044f626a3414021107004f626a34006106641109004f626a34006f626a2200
OK
igbinary-3.2.15/tests/igbinary_025.phpt 0000664 0001750 0001750 00000004005 14532662345 016764 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-3.2.15/tests/igbinary_025b.phpt 0000664 0001750 0001750 00000001207 14532662345 017127 0 ustar tyson tyson --TEST--
Object test, array of small objects with __sleep
--SKIPIF--
--FILE--
c = $c;
}
function __sleep() {
return array('c');
}
}
$obj = new Obj(4);
test('array', $obj, true);
?>
--EXPECT--
object(Obj)#1 (1) {
["c":"Obj":private]=>
int(4)
}
object(Obj)#2 (1) {
["c":"Obj":private]=>
int(4)
}
igbinary-3.2.15/tests/igbinary_026.phpt 0000664 0001750 0001750 00000002412 14532662345 016765 0 ustar tyson tyson --TEST--
Cyclic array test
--INI--
report_memleaks=0
--SKIPIF--
7) {
echo "skip requires php 7.x\n";
}
--FILE--
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-3.2.15/tests/igbinary_026_php8.phpt 0000664 0001750 0001750 00000003145 14532662345 017730 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:\nActual:\n", $dump_act, "\nExpected:\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";
echo "Actual\n";
var_dump($act);
var_dump($act['foo']);
echo "Expected\n";
var_dump($exp);
var_dump($exp['foo']);
}
?>
--EXPECT--
array
140211016114021101621101631101641101651101662514020e0001010e05250102
OK
Var dump differs:
Actual:
array(1) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
array(1) {
["foo"]=>
*RECURSION*
}
}
}
Expected:
array(1) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
*RECURSION*
}
}
igbinary-3.2.15/tests/igbinary_026b.phpt 0000664 0001750 0001750 00000001672 14532662345 017136 0 ustar tyson tyson --TEST--
Cyclic array test 2
--INI--
report_memleaks=0
--SKIPIF--
7) {
echo "skip requires php 7.x\n";
}
--FILE--
&$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-3.2.15/tests/igbinary_026b_php8.phpt 0000664 0001750 0001750 00000002524 14532662345 020072 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
*/
/* NOTE: This is different in php 8 because igbinary_unserialize() is declared to return a reference, not a value */
//$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--
Output differs
Expected:
array(1) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
*RECURSION*
}
}
Actual:
array(1) {
["foo"]=>
&array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
array(1) {
["foo"]=>
*RECURSION*
}
}
}
OK igbinary-3.2.15/tests/igbinary_027.phpt 0000664 0001750 0001750 00000003022 14532662345 016764 0 ustar tyson tyson --TEST--
Check for serialization handler
--SKIPIF--
--EXPECT--
bool(true)
read
wrote: 14021103666f6f06011104746573741106666f6f626172
igbinary-3.2.15/tests/igbinary_028.phpt 0000664 0001750 0001750 00000004533 14532662345 016775 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
read
write: 140311036f6c641703466f6f1403110700466f6f0064311703426172140311026431220111070042617200643222011105002a00643322011105002a00643222021102643322021104746573741106666f6f62617211036e65771a0314030e041a0114030e0222030e0722030e0822030e0522040e062204
igbinary-3.2.15/tests/igbinary_029.phpt 0000664 0001750 0001750 00000000704 14532662345 016772 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-3.2.15/tests/igbinary_030_php7.phpt 0000664 0001750 0001750 00000002257 14532662345 017725 0 ustar tyson tyson --TEST--
Unserialize invalid data
--SKIPIF--
= 70200) {
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
$str2 = $str . "98398afa\000y21_ ";
$v = igbinary_unserialize($str2);
if ($v !== NULL) {
echo "Should return null with padding\n";
var_dump($v);
}
$str3 = $str . "\x00";
$v = igbinary_unserialize($str3);
if ($v !== NULL) {
echo "Should return null with single byte of padding\n";
var_dump($v);
}
}
echo "Success!\n";
?>
--EXPECT--
Success!
igbinary-3.2.15/tests/igbinary_030_php72.phpt 0000664 0001750 0001750 00000002263 14532662345 020004 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
$str2 = $str . "98398afa\000y21_ ";
$v = igbinary_unserialize($str2);
if ($v !== NULL) {
echo "Should return null with padding\n";
var_dump($v);
}
$str3 = $str . "\x00";
$v = igbinary_unserialize($str3);
if ($v !== NULL) {
echo "Should return null with single byte of padding\n";
var_dump($v);
}
}
echo "Success!\n";
?>
--EXPECT--
Success!
igbinary-3.2.15/tests/igbinary_031.phpt 0000664 0001750 0001750 00000003433 14532662345 016765 0 ustar tyson tyson --TEST--
Object Serializable interface throws exceptions
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--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 ($e->getPrevious()) {
$e = $e->getPrevious();
}
echo $e->getMessage(), "\n";
}
echo "b, b, d\n";
try {
test(array($b, $b, $d));
} catch (Exception $e) {
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-3.2.15/tests/igbinary_032.phpt 0000664 0001750 0001750 00000002573 14532662345 016772 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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
exception in __sleep 0
exception in __wakeup 2
igbinary-3.2.15/tests/igbinary_033.phpt 0000664 0001750 0001750 00000001604 14532662345 016765 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;
}
}
error_reporting(E_ALL);
$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-3.2.15/tests/igbinary_034.phpt 0000664 0001750 0001750 00000001163 14532662345 016766 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-3.2.15/tests/igbinary_040.phpt 0000664 0001750 0001750 00000003157 14532662345 016770 0 ustar tyson tyson --TEST--
b0rked random data test
--SKIPIF--
--FILE--
--EXPECTF--
After testing 100 random values
Warning: igbinary_unserialize: received more data to unserialize than expected in %s on line 48
NULL
igbinary-3.2.15/tests/igbinary_041.phpt 0000664 0001750 0001750 00000004063 14532662345 016766 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-3.2.15/tests/igbinary_044.phpt 0000664 0001750 0001750 00000011220 14532662345 016762 0 ustar tyson tyson --TEST--
Check for double extremes
--FILE--
getVersion(), '4.0.2', '<')) {
echo "skip require APCu version 4.0.2 or above";
}
--INI--
apc.enable_cli=1
apc.serializer=igbinary
--FILE--
int(10)
}
igbinary-3.2.15/tests/igbinary_045c.phpt 0000664 0001750 0001750 00000003232 14532662345 017132 0 ustar tyson tyson --TEST--
APCu serializer registration - more data types
--INI--
apc.enable_cli=1
apc.serializer=igbinary
--SKIPIF--
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-3.2.15/tests/igbinary_046.phpt 0000664 0001750 0001750 00000000742 14532662345 016773 0 ustar tyson tyson --TEST--
Correctly unserialize scalar refs.
--INI--
igbinary.compact_strings = On
--FILE--
&string(1) "V"
[1]=>
&string(1) "V"
[2]=>
&string(1) "V"
[3]=>
&string(1) "V"
}
igbinary-3.2.15/tests/igbinary_046b.phpt 0000664 0001750 0001750 00000001301 14532662345 017125 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-3.2.15/tests/igbinary_046c.phpt 0000664 0001750 0001750 00000001213 14532662345 017130 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-3.2.15/tests/igbinary_046d.phpt 0000664 0001750 0001750 00000002346 14532662345 017141 0 ustar tyson tyson --TEST--
Correctly unserialize multiple object refs and non-refs.
--INI--
igbinary.compact_strings = On
--FILE--
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-3.2.15/tests/igbinary_047.phpt 0000664 0001750 0001750 00000004045 14532662345 016774 0 ustar tyson tyson --TEST--
Check for serialization handler, SessionHandlerInterface
--SKIPIF--
--FILE--
Returns the number of deleted sessions on success, or false on failure.
// > Note this value is returned internally to PHP for processing.
public function gc($time): int {
return 0;
}
}
class Foo {
}
class Bar {
}
ini_set('session.serialize_handler', 'igbinary');
$handler = new S();
session_set_save_handler($handler, true);
$db_object = new Foo();
$session_object = new Bar();
$v = session_start();
var_dump($v);
$_SESSION['test'] = "foobar";
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 TESTING.md for further information on
* writing regression tests
*/
?>
--EXPECT--
bool(true)
read
wrote: 14021103666f6f06011104746573741106666f6f626172
igbinary-3.2.15/tests/igbinary_048.phpt 0000664 0001750 0001750 00000001050 14532662345 016766 0 ustar tyson tyson --TEST--
Object test, __set not called for private attr in extended class
--FILE--
a = [1, 2, 3];
$x->nonexistent = 'aaa';
igbinary_unserialize(igbinary_serialize($x));
--EXPECT--
magic function called for nonexistent with 'aaa'
igbinary-3.2.15/tests/igbinary_048b.phpt 0000664 0001750 0001750 00000001026 14532662345 017133 0 ustar tyson tyson --TEST--
Object test, __set not called for private attr in extended class
--FILE--
a = [1, 2, 3];
$x->nonexistent = 'aaa';
unserialize(serialize($x));
--EXPECT--
magic function called for nonexistent with 'aaa'
igbinary-3.2.15/tests/igbinary_049.phpt 0000664 0001750 0001750 00000003466 14532662345 017004 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-3.2.15/tests/igbinary_049b.phpt 0000664 0001750 0001750 00000002647 14532662345 017146 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-3.2.15/tests/igbinary_050.phpt 0000664 0001750 0001750 00000002021 14532662345 016756 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.
--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-3.2.15/tests/igbinary_051.phpt 0000664 0001750 0001750 00000001457 14532662345 016773 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-3.2.15/tests/igbinary_052.phpt 0000664 0001750 0001750 00000003256 14532662345 016773 0 ustar tyson tyson --TEST--
Object Serializable interface can be serialized in references
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--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-3.2.15/tests/igbinary_053.phpt 0000664 0001750 0001750 00000001764 14532662345 016776 0 ustar tyson tyson --TEST--
__wakeup can modify properties without affecting other objects
--FILE--
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-3.2.15/tests/igbinary_054.phpt 0000664 0001750 0001750 00000002627 14532662345 016776 0 ustar tyson tyson --TEST--
__wakeup can add dynamic properties without affecting other objects
--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-3.2.15/tests/igbinary_055.phpt 0000664 0001750 0001750 00000001235 14532662345 016771 0 ustar tyson tyson --TEST--
__wakeup can replace a copy of the object referring to the root node.
--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-3.2.15/tests/igbinary_057.phpt 0000664 0001750 0001750 00000001747 14532662345 017003 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-3.2.15/tests/igbinary_058.phpt 0000664 0001750 0001750 00000002555 14532662345 017002 0 ustar tyson tyson --TEST--
Should not call __destruct if __wakeup throws an exception
--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-3.2.15/tests/igbinary_058b.phpt 0000664 0001750 0001750 00000002575 14532662345 017146 0 ustar tyson tyson --TEST--
Should not call __destruct if __wakeup throws an exception (in arrays)
--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-3.2.15/tests/igbinary_059.phpt 0000664 0001750 0001750 00000002365 14532662345 017002 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-3.2.15/tests/igbinary_060.phpt 0000664 0001750 0001750 00000002517 14532662345 016771 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-3.2.15/tests/igbinary_062.phpt 0000664 0001750 0001750 00000002337 14532662345 016773 0 ustar tyson tyson --TEST--
igbinary should not call __wakeup() if Serializable::unserialize was used to unserialize the object data (like `unserialize`)
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--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-3.2.15/tests/igbinary_063_php7.phpt 0000664 0001750 0001750 00000002312 14532662345 017723 0 ustar tyson tyson --TEST--
Accessing unserialized numbers.
--SKIPIF--
= 70200) {
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-3.2.15/tests/igbinary_063_php72.phpt 0000664 0001750 0001750 00000002276 14532662345 020016 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-3.2.15/tests/igbinary_064.phpt 0000664 0001750 0001750 00000004275 14532662345 017000 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-3.2.15/tests/igbinary_065.phpt 0000664 0001750 0001750 00000003034 14532662345 016771 0 ustar tyson tyson --TEST--
Don't emit zval has unknown type 0 (IS_UNDEF)
--FILE--
x);
unset($this->y);
unset($this->z);
$this->set = 'setVal';
$this->priv = null;
$this->omitted = 'otherVal';
return ['kept', 'x', 'y', 'z', 'set', 'priv'];
}
}
error_reporting(E_ALL);
// TODO: emit 'Notice: igbinary_serialize(): "x" returned as member variable from __sleep() but does not exist' instead.
$serialized = igbinary_serialize(new MyClass());
echo bin2hex($serialized) . "\n";
var_export_normalized(igbinary_unserialize($serialized));
echo "\n";
?>
--EXPECTF--
Notice: igbinary_serialize(): "x" returned as member variable from __sleep() but does not exist in %s on line 25
Notice: igbinary_serialize(): "y" returned as member variable from __sleep() but does not exist in %s on line 25
Notice: igbinary_serialize(): "z" returned as member variable from __sleep() but does not exist in %s on line 25
0000000217074d79436c617373140611046b6570740602110178001104002a007900110a004d79436c617373007a001106002a00736574110673657456616c110d004d79436c617373007072697600
MyClass::__set_state(array(
'kept' => 2,
'x' => NULL,
'y' => NULL,
'z' => NULL,
'set' => 'setVal',
'priv' => NULL,
'omitted' => 'myVal',
))
igbinary-3.2.15/tests/igbinary_066.phpt 0000664 0001750 0001750 00000002171 14532662345 016773 0 ustar tyson tyson --TEST--
Test serializing different empty arrays
--FILE--
array(), '2nd' => array(), '3rd' => array()))));
echo "\n";
var_dump(igbinary_unserialize(igbinary_serialize(array('1st' => $a, '2nd' => $a, '3rd' => $a))));
echo "\n";
$result = igbinary_unserialize(igbinary_serialize(array('1st' => $a, '2nd' => &$a, '3rd' => &$a, '4th' => array())));
var_dump($result);
$result['2nd'][] = 2;
var_dump($result);
echo "\n";
?>
--EXPECT--
array(3) {
["1st"]=>
array(0) {
}
["2nd"]=>
array(0) {
}
["3rd"]=>
array(0) {
}
}
array(3) {
["1st"]=>
array(0) {
}
["2nd"]=>
array(0) {
}
["3rd"]=>
array(0) {
}
}
array(4) {
["1st"]=>
array(0) {
}
["2nd"]=>
&array(0) {
}
["3rd"]=>
&array(0) {
}
["4th"]=>
array(0) {
}
}
array(4) {
["1st"]=>
array(0) {
}
["2nd"]=>
&array(1) {
[0]=>
int(2)
}
["3rd"]=>
&array(1) {
[0]=>
int(2)
}
["4th"]=>
array(0) {
}
}
igbinary-3.2.15/tests/igbinary_067.phpt 0000664 0001750 0001750 00000001466 14532662345 017002 0 ustar tyson tyson --TEST--
Test serializing multiple reference groups to the same empty array
--SKIPIF--
--FILE--
$value) {
echo "$k: " . json_encode($value) . "\n";
}
}
function main() {
$a = array();
$b = $a;
$c = $a;
$value = array(&$b, $a, &$b, &$c, &$c);
$ser = igbinary_serialize($value);
echo bin2hex($ser) . "\n";
$v = igbinary_unserialize($ser);
dump($v);
$v[0][] = 2;
dump($v);
$v[3][] = 3;
dump($v);
var_export($a);
}
main();
?>
--EXPECT--
000000021405060025140006011400060225010106032514000604250103
5 values
0: []
1: []
2: []
3: []
4: []
5 values
0: [2]
1: []
2: [2]
3: []
4: []
5 values
0: [2]
1: []
2: [2]
3: [3]
4: [3]
array (
)
igbinary-3.2.15/tests/igbinary_068.phpt 0000664 0001750 0001750 00000000715 14532662345 016777 0 ustar tyson tyson --TEST--
Test serializing and unserializing PHP_INT_MIN
--FILE--
--EXPECT--
true
true
true
igbinary-3.2.15/tests/igbinary_069.phpt 0000664 0001750 0001750 00000000547 14532662345 017003 0 ustar tyson tyson --TEST--
Test serializing and unserializing many duplicate strings
--FILE--
--FILE--
$this->prop, 42 => $this->prop2];
}
public function __unserialize(array $data) {
$this->prop = 'unser' . $data["value"];
$this->prop2 = 'unser' . $data[42];
}
}
$test = new Test;
$test->prop = "foobar";
$test->prop2 = "barfoo";
$s = igbinary_serialize($test);
echo bin2hex($s) . "\n";
var_dump(igbinary_unserialize($s));
?>
--EXPECT--
000000021704546573741402110576616c75651106666f6f626172062a1106626172666f6f
object(Test)#2 (2) {
["prop"]=>
string(11) "unserfoobar"
["prop2"]=>
string(11) "unserbarfoo"
}
igbinary-3.2.15/tests/igbinary_071.phpt 0000664 0001750 0001750 00000004663 14532662345 016777 0 ustar tyson tyson --TEST--
igbinary_unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
= 80000) { echo "skip different error message format"; }
?>
--FILE--
a = 1234;
$a->b = &$a->a;
var_dump(bin2hex($s = igbinary_serialize($a)));
var_dump(igbinary_unserialize($s));
echo "Test B\n";
$b = new B();
$b->a = -1234;
$b->b = &$b->a;
var_dump(bin2hex($s = igbinary_serialize($b)));
var_dump(igbinary_unserialize($s));
$z = new Z();
$z->a = null;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'A', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('Z', 'B', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 'x';
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'D', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
/*
try {
var_dump(unserialize('O:1:"D":2:{s:1:"a";i:1;s:1:"b";R:2;}'));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
*/
?>
--EXPECT--
string(44) "000000021701411402110161250804d2110162250101"
object(A)#2 (2) {
["a"]=>
&int(1234)
["b"]=>
&int(1234)
}
Test B
string(44) "000000021701421402110161250904d2110162250101"
object(B)#3 (2) {
["a"]=>
&int(-1234)
["b"]=>
&int(-1234)
}
Typed property A::$a must be int, null used
Typed property B::$b must be int, null used
Typed property C::$b must be string, int used
Typed property C::$a must be int, string used
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float
igbinary-3.2.15/tests/igbinary_071_php8.phpt 0000664 0001750 0001750 00000004536 14532662345 017735 0 ustar tyson tyson --TEST--
igbinary_unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
--FILE--
a = 1234;
$a->b = &$a->a;
var_dump(bin2hex($s = igbinary_serialize($a)));
var_dump(igbinary_unserialize($s));
echo "Test B\n";
$b = new B();
$b->a = -1234;
$b->b = &$b->a;
var_dump(bin2hex($s = igbinary_serialize($b)));
var_dump(igbinary_unserialize($s));
$z = new Z();
$z->a = null;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'A', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('Z', 'B', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 'x';
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
var_dump(igbinary_unserialize(str_replace('Z', 'D', $s)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
/*
try {
var_dump(unserialize('O:1:"D":2:{s:1:"a";i:1;s:1:"b";R:2;}'));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
*/
?>
--EXPECT--
string(44) "000000021701411402110161250804d2110162250101"
object(A)#2 (2) {
["a"]=>
&int(1234)
["b"]=>
&int(1234)
}
Test B
string(44) "000000021701421402110161250904d2110162250101"
object(B)#3 (2) {
["a"]=>
&int(-1234)
["b"]=>
&int(-1234)
}
Cannot assign null to property A::$a of type int
Cannot assign null to property B::$b of type int
Cannot assign int to property C::$b of type string
Cannot assign string to property C::$a of type int
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float igbinary-3.2.15/tests/igbinary_072.phpt 0000664 0001750 0001750 00000003006 14532662345 016766 0 ustar tyson tyson --TEST--
igbinary and __PHP_INCOMPLETE_CLASS
--FILE--
= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }
class Test {}
function test_ser_unser($obj) {
var_dump(bin2hex($s = igbinary_serialize($obj)));
$s = str_replace('Test', 'Best', $s);
$obj2 = igbinary_unserialize($s);
var_dump($obj2);
var_dump(bin2hex($s = igbinary_serialize($obj2)));
var_dump(igbinary_unserialize($s));
}
test_ser_unser(new Test());
echo "Testing with properties\n";
$obj = new Test();
$obj->dynamicProp = 'value';
$obj->nullProp = null;
test_ser_unser($obj);
?>
--EXPECT--
string(24) "000000021704546573741400"
object(__PHP_Incomplete_Class)#2 (1) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Best"
}
string(24) "000000021704426573741400"
object(__PHP_Incomplete_Class)#3 (1) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Best"
}
Testing with properties
string(86) "000000021704546573741402110b64796e616d696350726f70110576616c756511086e756c6c50726f7000"
object(__PHP_Incomplete_Class)#1 (3) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Best"
["dynamicProp"]=>
string(5) "value"
["nullProp"]=>
NULL
}
string(86) "000000021704426573741402110b64796e616d696350726f70110576616c756511086e756c6c50726f7000"
object(__PHP_Incomplete_Class)#3 (3) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Best"
["dynamicProp"]=>
string(5) "value"
["nullProp"]=>
NULL
} igbinary-3.2.15/tests/igbinary_073.phpt 0000664 0001750 0001750 00000003256 14532662345 016776 0 ustar tyson tyson --TEST--
igbinary and large Serializable
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
prop;
}
public function unserialize($s) {
$this->prop = $s;
}
}
function var_export_normalized($value) {
echo ltrim(var_export($value, true), "\\");
}
$t = new Test();
$t->prop = str_repeat('0', 256);
var_export_normalized(bin2hex($s = igbinary_serialize($t)));
echo "\n";
var_export_normalized(igbinary_unserialize($s));
echo "\n";
$t->prop = str_repeat('0', 1 << 16);
$t2 = igbinary_unserialize(igbinary_serialize($t));
var_dump($t2->prop === $t->prop);
?>
--EXPECT--
'000000021704546573741e010030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030'
Test::__set_state(array(
'prop' => '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
))
bool(true)
igbinary-3.2.15/tests/igbinary_074.phpt 0000664 0001750 0001750 00000002060 14532662345 016767 0 ustar tyson tyson --TEST--
igbinary and not enough data for array
--FILE--
--EXPECTF--
One byte
Warning: igbinary_unserialize_array: end-of-data in %s on line 3
Two byte
Warning: igbinary_unserialize_array: end-of-data in %s on line 5
Warning: igbinary_unserialize_array: end-of-data in %s on line 6
Warning: igbinary_unserialize_array: data size 0 smaller that requested array length 1. in %s on line 7
Four byte
Warning: igbinary_unserialize_array: end-of-data in %s on line 9
Warning: igbinary_unserialize_array: end-of-data in %s on line 10
Warning: igbinary_unserialize_array: data size 0 smaller that requested array length 1. in %s on line 11
igbinary-3.2.15/tests/igbinary_075.phpt 0000664 0001750 0001750 00000001657 14532662345 017003 0 ustar tyson tyson --TEST--
igbinary and not enough data for array
--FILE--
--EXPECTF--
string(18) "000000021701581400"
One byte
igbinary_unserialize_object_properties: end-of-data
NULL
Two byte
igbinary_unserialize_object_properties: end-of-data
NULL
igbinary_unserialize_object_properties: end-of-data
Four byte
igbinary_unserialize_object_properties: end-of-data
NULL
igbinary_unserialize_object_properties: end-of-data igbinary-3.2.15/tests/igbinary_076.phpt 0000664 0001750 0001750 00000001072 14532662345 016773 0 ustar tyson tyson --TEST--
igbinary and edge cases unserializing array keys
--FILE--
true])));
// 3-byte string truncated in the middle of the array key
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x14\x01\x11\x03\x6b\x65"));
// null instead of a string - skip over the entry
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x14\x01\x00"));
?>
--EXPECTF--
string(24) "00000002140111036b657905"
igbinary_unserialize_chararray: end-of-data
NULL
array(0) {
}
igbinary-3.2.15/tests/igbinary_077.phpt 0000664 0001750 0001750 00000004525 14532662345 017002 0 ustar tyson tyson --TEST--
igbinary and large arrays
--FILE--
--EXPECTF--
string(2062) "0000000215010006000600060106010602060206030603060406040605060506060606060706070608060806090609060a060a060b060b060c060c060d060d060e060e060f060f06100610061106110612061206130613061406140615061506160616061706170618061806190619061a061a061b061b061c061c061d061d061e061e061f061f06200620062106210622062206230623062406240625062506260626062706270628062806290629062a062a062b062b062c062c062d062d062e062e062f062f06300630063106310632063206330633063406340635063506360636063706370638063806390639063a063a063b063b063c063c063d063d063e063e063f063f06400640064106410642064206430643064406440645064506460646064706470648064806490649064a064a064b064b064c064c064d064d064e064e064f064f06500650065106510652065206530653065406540655065506560656065706570658065806590659065a065a065b065b065c065c065d065d065e065e065f065f06600660066106610662066206630663066406640665066506660666066706670668066806690669066a066a066b066b066c066c066d066d066e066e066f066f06700670067106710672067206730673067406740675067506760676067706770678067806790679067a067a067b067b067c067c067d067d067e067e067f067f06800680068106810682068206830683068406840685068506860686068706870688068806890689068a068a068b068b068c068c068d068d068e068e068f068f06900690069106910692069206930693069406940695069506960696069706970698069806990699069a069a069b069b069c069c069d069d069e069e069f069f06a006a006a106a106a206a206a306a306a406a406a506a506a606a606a706a706a806a806a906a906aa06aa06ab06ab06ac06ac06ad06ad06ae06ae06af06af06b006b006b106b106b206b206b306b306b406b406b506b506b606b606b706b706b806b806b906b906ba06ba06bb06bb06bc06bc06bd06bd06be06be06bf06bf06c006c006c106c106c206c206c306c306c406c406c506c506c606c606c706c706c806c806c906c906ca06ca06cb06cb06cc06cc06cd06cd06ce06ce06cf06cf06d006d006d106d106d206d206d306d306d406d406d506d506d606d606d706d706d806d806d906d906da06da06db06db06dc06dc06dd06dd06de06de06df06df06e006e006e106e106e206e206e306e306e406e406e506e506e606e606e706e706e806e806e906e906ea06ea06eb06eb06ec06ec06ed06ed06ee06ee06ef06ef06f006f006f106f106f206f206f306f306f406f406f506f506f606f606f706f706f806f806f906f906fa06fa06fb06fb06fc06fc06fd06fd06fe06fe06ff06ff"
bool(true)
bool(true)
igbinary-3.2.15/tests/igbinary_078.phpt 0000664 0001750 0001750 00000001117 14532662345 016775 0 ustar tyson tyson --TEST--
igbinary and large arrays
--FILE--
prop = $value;
}
public function __sleep() {
return null;
}
}
var_dump(bin2hex($s = igbinary_serialize(new BadSleep('override'))));
var_dump(igbinary_unserialize($s));
?>
--EXPECTF--
Notice: igbinary_serialize(): __sleep should return an array only containing the names of instance-variables to serialize in %s on line %d
string(32) "000000021708426164536c6565701400"
object(BadSleep)#1 (1) {
["prop"]=>
string(1) "x"
} igbinary-3.2.15/tests/igbinary_079.phpt 0000664 0001750 0001750 00000002012 14532662345 016771 0 ustar tyson tyson --TEST--
igbinary and many arrays
--FILE--
--EXPECTF--
string(60) "000000021404060014010600060006011401060006010602010106030102"
array(4) {
[0]=>
array(1) {
[0]=>
int(0)
}
[1]=>
array(1) {
[0]=>
int(1)
}
[2]=>
array(1) {
[0]=>
int(0)
}
[3]=>
array(1) {
[0]=>
int(1)
}
}
bool(true)
bool(true)
igbinary-3.2.15/tests/igbinary_080.phpt 0000664 0001750 0001750 00000001113 14532662345 016762 0 ustar tyson tyson --TEST--
igbinary with hash collision serializing strings
--FILE--
"3010480803", 'user_id'=>12346];
$serialized = igbinary_serialize($var);
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
$var=['id'=>"3010480803", 'user_id'=>"3010480804"];
$serialized = igbinary_serialize($var);
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
?>
--EXPECT--
array(2) {
["id"]=>
string(10) "3010480803"
["user_id"]=>
int(12346)
}
array(2) {
["id"]=>
string(10) "3010480803"
["user_id"]=>
string(10) "3010480804"
}
igbinary-3.2.15/tests/igbinary_081.phpt 0000664 0001750 0001750 00000002070 14532662345 016766 0 ustar tyson tyson --TEST--
igbinary with reference group of size 1 created by array_walk_recursive
--FILE--
env = &$e;
}
}
$arrayObject = new ArrayObject();
$testClass = new TestClass();
$testClass->setEnv($arrayObject);
var_dump(igbinary_unserialize(igbinary_serialize($testClass)));
?>
--EXPECTF--
object(TestClass)#%d (1) {
["env":"TestClass":private]=>
object(ArrayObject)#%d (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
}
igbinary-3.2.15/tests/igbinary_082_php74.phpt 0000664 0001750 0001750 00000001503 14532662345 020011 0 ustar tyson tyson --TEST--
igbinary object with typed properties with reference to ArrayObject
--SKIPIF--
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
env = &$e;
}
}
$arrayObject = new ArrayObject();
$testClass = new TestClass();
$testClass->setEnv($arrayObject);
var_dump(igbinary_unserialize(igbinary_serialize($testClass)));
?>
--EXPECTF--
object(TestClass)#%d (1) {
["env":"TestClass":private]=>
object(ArrayObject)#%d (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
}
igbinary-3.2.15/tests/igbinary_083.phpt 0000664 0001750 0001750 00000001653 14532662345 016776 0 ustar tyson tyson --TEST--
igbinary object with reference to ArrayObject
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
--EXPECT--
Called serialize
%00%00%00%02%14%04%06%00%25%00%06%01%25%22%01%06%02%25%11%06endcap%06%03%25%01%02
array(4) {
[0]=>
&NULL
[1]=>
&NULL
[2]=>
&string(6) "endcap"
[3]=>
&string(6) "endcap"
} igbinary-3.2.15/tests/igbinary_084.phpt 0000664 0001750 0001750 00000001126 14532662345 016772 0 ustar tyson tyson --TEST--
Properly free duplicate properties when unserializing invalid data
--FILE--
pub = new Test();
$s = igbinary_serialize($t);
echo urlencode($s), "\n";
$unser = igbinary_unserialize($s);
var_dump($unser);
?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%03pub%1A%00%14%02%0E%01%00%0E%01%00%0E%01%22%01
object(Test)#3 (1) {
["pub"]=>
object(Test)#4 (1) {
["pub"]=>
NULL
}
}
igbinary-3.2.15/tests/igbinary_084b.phpt 0000664 0001750 0001750 00000001642 14532662345 017137 0 ustar tyson tyson --TEST--
Properly free duplicate undeclared properties when unserializing invalid data
--SKIPIF--
= 90000) { echo "skip requires php < 9.0 when testing that the deprecation has no impact on igbinary functionality\n"; }
?>
--FILE--
= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }
class Test {
public function __construct( ) {
$this->pub = null;
}
public function __sleep() {
// TODO: Could start detecting duplicates and emitting a notice as well
return ["pub", "pub"];
}
}
$t = new Test();
$t->pub = new Test();
$s = igbinary_serialize($t);
echo urlencode($s), "\n";
$unser = igbinary_unserialize($s);
var_dump($unser);
?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%03pub%1A%00%14%02%0E%01%00%0E%01%00%0E%01%22%01
object(Test)#3 (1) {
["pub"]=>
object(Test)#4 (1) {
["pub"]=>
NULL
}
}
igbinary-3.2.15/tests/igbinary_085.phpt 0000664 0001750 0001750 00000001462 14532662345 016776 0 ustar tyson tyson --TEST--
Properly free unexpected duplicate fields when unserializing arrays
--FILE--
$s, 'yy' => $s]);
echo urlencode($ser), "\n";
$result = igbinary_unserialize(str_replace('xx', 'yy', $ser));
var_dump($result);
$ser = igbinary_serialize([0x66 => $s, 0x77 => $s]);
echo urlencode($ser), "\n";
$result2 = igbinary_unserialize(str_replace("\x66", "\x77", $ser));
var_dump($result2);
?>
--EXPECT--
%00%00%00%02%14%02%11%02xx%17%08stdClass%14%00%11%02yy%22%01
array(1) {
["yy"]=>
object(stdClass)#2 (0) {
}
}
%00%00%00%02%14%02%06f%17%08stdClass%14%00%06w%22%01
array(1) {
[119]=>
object(stdClass)#3 (0) {
}
} igbinary-3.2.15/tests/igbinary_086.phpt 0000664 0001750 0001750 00000001377 14532662345 017004 0 ustar tyson tyson --TEST--
Test serializing many different classes
--SKIPIF--
--FILE--
--EXPECT--
bool(true)
object(C0)#1 (0) {
}
object(C67800)#679 (0) {
}
igbinary-3.2.15/tests/igbinary_087.phpt 0000664 0001750 0001750 00000014171 14532662345 017001 0 ustar tyson tyson --TEST--
Test serializing many values in __sleep
--SKIPIF--
--FILE--
{"p$i"} = "$i";
}
$ser = igbinary_serialize($x);
$unser = igbinary_unserialize($ser);
echo urlencode($ser), "\n";
var_dump($unser == $x);
unset($unser);
for ($i = 0; $i < 70000; $i++) {
$x->{"p$i"} = "other$i";
}
var_dump(igbinary_unserialize(igbinary_serialize($x)) == $x);
?>
--EXPECT--
Called __sleep props=300
%00%00%00%02%17%01X%15%01%2C%11%02p0%11%010%11%02p1%11%011%11%02p2%11%012%11%02p3%11%013%11%02p4%11%014%11%02p5%11%015%11%02p6%11%016%11%02p7%11%017%11%02p8%11%018%11%02p9%11%019%11%03p10%11%0210%11%03p11%11%0211%11%03p12%11%0212%11%03p13%11%0213%11%03p14%11%0214%11%03p15%11%0215%11%03p16%11%0216%11%03p17%11%0217%11%03p18%11%0218%11%03p19%11%0219%11%03p20%11%0220%11%03p21%11%0221%11%03p22%11%0222%11%03p23%11%0223%11%03p24%11%0224%11%03p25%11%0225%11%03p26%11%0226%11%03p27%11%0227%11%03p28%11%0228%11%03p29%11%0229%11%03p30%11%0230%11%03p31%11%0231%11%03p32%11%0232%11%03p33%11%0233%11%03p34%11%0234%11%03p35%11%0235%11%03p36%11%0236%11%03p37%11%0237%11%03p38%11%0238%11%03p39%11%0239%11%03p40%11%0240%11%03p41%11%0241%11%03p42%11%0242%11%03p43%11%0243%11%03p44%11%0244%11%03p45%11%0245%11%03p46%11%0246%11%03p47%11%0247%11%03p48%11%0248%11%03p49%11%0249%11%03p50%11%0250%11%03p51%11%0251%11%03p52%11%0252%11%03p53%11%0253%11%03p54%11%0254%11%03p55%11%0255%11%03p56%11%0256%11%03p57%11%0257%11%03p58%11%0258%11%03p59%11%0259%11%03p60%11%0260%11%03p61%11%0261%11%03p62%11%0262%11%03p63%11%0263%11%03p64%11%0264%11%03p65%11%0265%11%03p66%11%0266%11%03p67%11%0267%11%03p68%11%0268%11%03p69%11%0269%11%03p70%11%0270%11%03p71%11%0271%11%03p72%11%0272%11%03p73%11%0273%11%03p74%11%0274%11%03p75%11%0275%11%03p76%11%0276%11%03p77%11%0277%11%03p78%11%0278%11%03p79%11%0279%11%03p80%11%0280%11%03p81%11%0281%11%03p82%11%0282%11%03p83%11%0283%11%03p84%11%0284%11%03p85%11%0285%11%03p86%11%0286%11%03p87%11%0287%11%03p88%11%0288%11%03p89%11%0289%11%03p90%11%0290%11%03p91%11%0291%11%03p92%11%0292%11%03p93%11%0293%11%03p94%11%0294%11%03p95%11%0295%11%03p96%11%0296%11%03p97%11%0297%11%03p98%11%0298%11%03p99%11%0299%11%04p100%11%03100%11%04p101%11%03101%11%04p102%11%03102%11%04p103%11%03103%11%04p104%11%03104%11%04p105%11%03105%11%04p106%11%03106%11%04p107%11%03107%11%04p108%11%03108%11%04p109%11%03109%11%04p110%11%03110%11%04p111%11%03111%11%04p112%11%03112%11%04p113%11%03113%11%04p114%11%03114%11%04p115%11%03115%11%04p116%11%03116%11%04p117%11%03117%11%04p118%11%03118%11%04p119%11%03119%11%04p120%11%03120%11%04p121%11%03121%11%04p122%11%03122%11%04p123%11%03123%11%04p124%11%03124%11%04p125%11%03125%11%04p126%11%03126%11%04p127%11%03127%11%04p128%11%03128%11%04p129%11%03129%11%04p130%11%03130%11%04p131%11%03131%11%04p132%11%03132%11%04p133%11%03133%11%04p134%11%03134%11%04p135%11%03135%11%04p136%11%03136%11%04p137%11%03137%11%04p138%11%03138%11%04p139%11%03139%11%04p140%11%03140%11%04p141%11%03141%11%04p142%11%03142%11%04p143%11%03143%11%04p144%11%03144%11%04p145%11%03145%11%04p146%11%03146%11%04p147%11%03147%11%04p148%11%03148%11%04p149%11%03149%11%04p150%11%03150%11%04p151%11%03151%11%04p152%11%03152%11%04p153%11%03153%11%04p154%11%03154%11%04p155%11%03155%11%04p156%11%03156%11%04p157%11%03157%11%04p158%11%03158%11%04p159%11%03159%11%04p160%11%03160%11%04p161%11%03161%11%04p162%11%03162%11%04p163%11%03163%11%04p164%11%03164%11%04p165%11%03165%11%04p166%11%03166%11%04p167%11%03167%11%04p168%11%03168%11%04p169%11%03169%11%04p170%11%03170%11%04p171%11%03171%11%04p172%11%03172%11%04p173%11%03173%11%04p174%11%03174%11%04p175%11%03175%11%04p176%11%03176%11%04p177%11%03177%11%04p178%11%03178%11%04p179%11%03179%11%04p180%11%03180%11%04p181%11%03181%11%04p182%11%03182%11%04p183%11%03183%11%04p184%11%03184%11%04p185%11%03185%11%04p186%11%03186%11%04p187%11%03187%11%04p188%11%03188%11%04p189%11%03189%11%04p190%11%03190%11%04p191%11%03191%11%04p192%11%03192%11%04p193%11%03193%11%04p194%11%03194%11%04p195%11%03195%11%04p196%11%03196%11%04p197%11%03197%11%04p198%11%03198%11%04p199%11%03199%11%04p200%11%03200%11%04p201%11%03201%11%04p202%11%03202%11%04p203%11%03203%11%04p204%11%03204%11%04p205%11%03205%11%04p206%11%03206%11%04p207%11%03207%11%04p208%11%03208%11%04p209%11%03209%11%04p210%11%03210%11%04p211%11%03211%11%04p212%11%03212%11%04p213%11%03213%11%04p214%11%03214%11%04p215%11%03215%11%04p216%11%03216%11%04p217%11%03217%11%04p218%11%03218%11%04p219%11%03219%11%04p220%11%03220%11%04p221%11%03221%11%04p222%11%03222%11%04p223%11%03223%11%04p224%11%03224%11%04p225%11%03225%11%04p226%11%03226%11%04p227%11%03227%11%04p228%11%03228%11%04p229%11%03229%11%04p230%11%03230%11%04p231%11%03231%11%04p232%11%03232%11%04p233%11%03233%11%04p234%11%03234%11%04p235%11%03235%11%04p236%11%03236%11%04p237%11%03237%11%04p238%11%03238%11%04p239%11%03239%11%04p240%11%03240%11%04p241%11%03241%11%04p242%11%03242%11%04p243%11%03243%11%04p244%11%03244%11%04p245%11%03245%11%04p246%11%03246%11%04p247%11%03247%11%04p248%11%03248%11%04p249%11%03249%11%04p250%11%03250%11%04p251%11%03251%11%04p252%11%03252%11%04p253%11%03253%11%04p254%11%03254%11%04p255%11%03255%11%04p256%11%03256%11%04p257%11%03257%11%04p258%11%03258%11%04p259%11%03259%11%04p260%11%03260%11%04p261%11%03261%11%04p262%11%03262%11%04p263%11%03263%11%04p264%11%03264%11%04p265%11%03265%11%04p266%11%03266%11%04p267%11%03267%11%04p268%11%03268%11%04p269%11%03269%11%04p270%11%03270%11%04p271%11%03271%11%04p272%11%03272%11%04p273%11%03273%11%04p274%11%03274%11%04p275%11%03275%11%04p276%11%03276%11%04p277%11%03277%11%04p278%11%03278%11%04p279%11%03279%11%04p280%11%03280%11%04p281%11%03281%11%04p282%11%03282%11%04p283%11%03283%11%04p284%11%03284%11%04p285%11%03285%11%04p286%11%03286%11%04p287%11%03287%11%04p288%11%03288%11%04p289%11%03289%11%04p290%11%03290%11%04p291%11%03291%11%04p292%11%03292%11%04p293%11%03293%11%04p294%11%03294%11%04p295%11%03295%11%04p296%11%03296%11%04p297%11%03297%11%04p298%11%03298%11%04p299%11%03299
bool(true)
Called __sleep props=70000
bool(true) igbinary-3.2.15/tests/igbinary_088.phpt 0000664 0001750 0001750 00000001745 14532662345 017005 0 ustar tyson tyson --TEST--
Test serializing wrong values in __sleep
--SKIPIF--
--FILE--
{"p$i"} = "name$i";
}
$ser = igbinary_serialize($x);
$unser = igbinary_unserialize($ser);
echo str_replace(['\\', '%'], ['\\\\', '\x'], urlencode($ser)), "\n";
var_dump($unser);
?>
--EXPECTF--
Notice: igbinary_serialize(): "name0" returned as member variable from __sleep() but does not exist in %s on line 12
Notice: igbinary_serialize(): "name1" returned as member variable from __sleep() but does not exist in %s on line 12
Notice: igbinary_serialize(): "name2" returned as member variable from __sleep() but does not exist in %s on line 12
\x00\x00\x00\x02\x17\x01X\x14\x03\x11\x05name0\x00\x11\x05name1\x00\x11\x05name2\x00
object(X)#2 (3) {
["name0"]=>
NULL
["name1"]=>
NULL
["name2"]=>
NULL
} igbinary-3.2.15/tests/igbinary_089.phpt 0000664 0001750 0001750 00000001617 14532662345 017004 0 ustar tyson tyson --TEST--
Test serializing string > 4G
--INI--
memory_limit=15G
display_errors=stderr
error_reporting=E_ALL
--CONFLICTS--
high_memory
--SKIPIF--
--FILE--
--EXPECTF--
len=4200000009
0000000213fa56ea002a2a2a2a2a2a2a2a2a2a2a
bool(true)
Warning: igbinary_unserialize_chararray: end-of-data in %sigbinary_089.php on line 10
NULL igbinary-3.2.15/tests/igbinary_089_32bit.phpt 0000664 0001750 0001750 00000000756 14532662345 020012 0 ustar tyson tyson --TEST--
Test unserializing invalid 64-bit string header on 32-bit platform
--INI--
display_errors=stderr
error_reporting=E_ALL
--CONFLICTS--
high_memory
--SKIPIF--
4) { print "skip requires 32-bit\n"; }
?>
--FILE--
--EXPECTF--
Warning: igbinary_unserialize_chararray: %s in %sigbinary_089_32bit.php on line 3
NULL igbinary-3.2.15/tests/igbinary_090.phpt 0000664 0001750 0001750 00000001254 14532662345 016771 0 ustar tyson tyson --TEST--
Check for handling of IS_INDIRECT in arrays
--FILE--
$value) {
if (!in_array($key, ['globalVar', 'otherGlobalVar'])) {
unset($x[$key]);
}
}
var_dump($x);
$ser = igbinary_serialize($x);
echo urlencode($ser) . "\n";
var_dump(igbinary_unserialize($ser));
});
--EXPECT--
array(2) {
["globalVar"]=>
&int(123)
["otherGlobalVar"]=>
&int(123)
}
%00%00%00%02%14%02%11%09globalVar%25%06%7B%11%0EotherGlobalVar%25%01%01
array(2) {
["globalVar"]=>
&int(123)
["otherGlobalVar"]=>
&int(123)
}
igbinary-3.2.15/tests/igbinary_091.phpt 0000664 0001750 0001750 00000001513 14532662345 016770 0 ustar tyson tyson --TEST--
Check for handling of anonymous classes
--INI--
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
getMessage() . "\n";
}
}
check_serialize_throws(new class () {});
// TODO: Update behavior based on https://bugs.php.net/bug.php?id=81111
/**
check_serialize_throws(new class () {
public function __serialize() { return []; }
public function __unserialize($value) { }
});
*/
check_serialize_throws(new class () implements Serializable {
public function serialize() { return ''; }
public function unserialize($ser) { return new self(); }
});
?>
--EXPECTF--
Caught: Serialization of 'class@anonymous' is not allowed
Caught: Serialization of '%s@anonymous' is not allowed
igbinary-3.2.15/tests/igbinary_092.phpt 0000664 0001750 0001750 00000001770 14532662345 016776 0 ustar tyson tyson --TEST--
Object test, unserialize_callback_func
--INI--
error_reporting=E_ALL
--FILE--
b == 2 ? 'OK' : 'ERROR';
echo "\n";
} catch (Throwable $e) {
printf("Caught %s: %s\n", get_class($e), $e->getMessage());
}
}
class MyUnserializer {
public static function handleUnserialize(string $class) {
throw new RuntimeException('handleUnserialize: Class not found: ' . $class);
}
}
ini_set('unserialize_callback_func', strtoupper('MyUnserializer::handleUnserialize'));
test('throwing_autoload', '0000000217034f626a140211016106011101620602', false);
?>
--EXPECTF--
Caught RuntimeException: handleUnserialize: Class not found: Obj
igbinary-3.2.15/tests/igbinary_093.phpt 0000664 0001750 0001750 00000001230 14532662345 016766 0 ustar tyson tyson --TEST--
Test refusing to serialize/unserialize unserializable anonymous classes
--INI--
error_reporting=E_ALL
--FILE--
getMessage() . "\n";
}
}
check_serialize_throws(new class () {
public function __serialize() { return []; }
public function __unserialize($value) { }
});
check_serialize_throws(function () { });
?>
--EXPECTF--
Caught: Serialization of 'class@anonymous' is not allowed
Caught: Serialization of 'Closure' is not allowed
igbinary-3.2.15/tests/igbinary_094.phpt 0000664 0001750 0001750 00000001634 14532662345 016777 0 ustar tyson tyson --TEST--
Test refusing to serialize/unserialize unserializable internal classes
--INI--
error_reporting=E_ALL
--SKIPIF--
--FILE--
getMessage() . "\n";
}
}
class Something extends CURLFile {
public function __serialize() { return []; }
public function __unserialize($value) { return new self('file'); }
}
check_serialize_throws(new CURLFile('file'));
check_serialize_throws(new Something('file'));
?>
--EXPECTF--
Caught: Serialization of 'CURLFile' is not allowed
Caught: Serialization of 'Something' is not allowed
igbinary-3.2.15/tests/igbinary_095.phpt 0000664 0001750 0001750 00000004526 14532662345 017003 0 ustar tyson tyson --TEST--
Test handling php 8.1 readonly properties
--SKIPIF--
--FILE--
var = $intersection;
}
}
class Y {
public readonly mixed $var;
public function __construct(
public readonly int $a,
private readonly ArrayAccess&Countable $intersection,
protected readonly ?string $default = null,
) {
$this->var = $intersection;
}
public function __serialize(): array {
return [
'a' => $this->a,
'intersection' => $this->intersection,
'default' => $this->default,
'var' => $this->var,
];
}
public function __unserialize(array $data) {
[
'a' => $this->a,
'intersection' => $this->intersection,
'default' => $this->default,
'var' => $this->var,
] = $data;
}
}
$ser = igbinary_serialize(new X(1, new ArrayObject()));
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
$ser = igbinary_serialize(new Y(1, new ArrayObject()));
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
?>
--EXPECT--
%00%00%00%02%17%01X%14%04%11%03var%17%0BArrayObject%14%04%06%00%06%00%06%01%14%00%06%02%14%00%06%03%00%11%01a%06%01%11%0F%00X%00intersection%22%01%11%0A%00%2A%00default%00
object(X)#1 (4) {
["var"]=>
object(ArrayObject)#2 (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
["a"]=>
int(1)
["intersection":"X":private]=>
object(ArrayObject)#2 (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
["default":protected]=>
NULL
}
%00%00%00%02%17%01Y%14%04%11%01a%06%01%11%0Cintersection%17%0BArrayObject%14%04%06%00%06%00%06%01%14%00%06%02%14%00%06%03%00%11%07default%00%11%03var%22%01
object(Y)#1 (4) {
["var"]=>
object(ArrayObject)#2 (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
["a"]=>
int(1)
["intersection":"Y":private]=>
object(ArrayObject)#2 (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
["default":protected]=>
NULL
}
igbinary-3.2.15/tests/igbinary_096.phpt 0000664 0001750 0001750 00000001001 14532662345 016765 0 ustar tyson tyson --TEST--
Test unserialization creates valid current()
--INI--
display_errors=stderr
error_reporting=E_ALL
--FILE--
[
'two' => [
'three' => [
'four'
],
],
],
];
$test = current(current(current(current($arr))));
var_dump($test);
// Note: after unserialization the current is the last array element.
$arr2 = igbinary_unserialize(igbinary_serialize($arr));
$test2 = current(current(current(current($arr2))));
var_dump($test2);
?>
--EXPECT--
string(4) "four"
string(4) "four" igbinary-3.2.15/tests/igbinary_097.phpt 0000664 0001750 0001750 00000002071 14532662345 016776 0 ustar tyson tyson --TEST--
Test serialize globals
--SKIPIF--
= 80100) print "skip php >= 8.1\n"; // https://wiki.php.net/rfc/restrict_globals_usage
?>
--FILE--
$_) {
if ($key !== 'GLOBALS') {
unset($GLOBALS[$key]);
}
}
$ser = igbinary_serialize($GLOBALS);
echo urlencode($ser) . "\n";
var_dump(igbinary_unserialize($ser));
$GLOBALS['globalVar'] = new stdClass();
$ser = igbinary_serialize($GLOBALS);
echo urlencode($ser) . "\n";
var_dump(igbinary_unserialize($ser));
});
--EXPECTF--
%00%00%00%02%14%01%11%07GLOBALS%14%01%0E%00%01%01
array(1) {
["GLOBALS"]=>
array(1) {
["GLOBALS"]=>
*RECURSION*
}
}
%00%00%00%02%14%02%11%07GLOBALS%14%02%0E%00%01%01%11%09globalVar%17%08stdClass%14%00%0E%01%22%02
array(2) {
["GLOBALS"]=>
array(2) {
["GLOBALS"]=>
*RECURSION*
["globalVar"]=>
object(stdClass)#3 (0) {
}
}
["globalVar"]=>
object(stdClass)#3 (0) {
}
}
igbinary-3.2.15/tests/igbinary_098.phpt 0000664 0001750 0001750 00000001674 14532662345 017007 0 ustar tyson tyson --TEST--
Test PHP 8.2 readonly classes
--SKIPIF--
--FILE--
a = 8;
return $c;
}
}
$c = new C();
$ser = igbinary_serialize($c);
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
$c = C::create();
$ser = igbinary_serialize($c);
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
$invalid1 = str_replace('a', 'b', $ser);
try {
var_dump(igbinary_unserialize($invalid1));
} catch (Error $e) {
printf("%s: %s\n", $e::class, $e->getMessage());
}
--EXPECT--
%00%00%00%02%17%01C%14%01%00
object(C)#2 (0) {
["a"]=>
uninitialized(int)
}
%00%00%00%02%17%01C%14%01%11%01a%06%08
object(C)#1 (1) {
["a"]=>
int(8)
}
Error: Cannot create dynamic property C::$b in igbinary_unserialize
igbinary-3.2.15/tests/igbinary_099.phpt 0000664 0001750 0001750 00000001614 14532662345 017002 0 ustar tyson tyson --TEST--
Test PHP 8.2 deprecation of creation of dynamic properties
--SKIPIF--
--FILE--
getMessage());
}
}
--EXPECTF--
Deprecated: igbinary_unserialize(): Creation of dynamic property C::$a is deprecated in %sigbinary_099.php on line 12
object(C)#2 (1) {
["a"]=>
int(8)
}
Deprecated: igbinary_unserialize(): Creation of dynamic property C::$a is deprecated in %sigbinary_099.php on line 12
object(C)#2 (1) {
["a":protected]=>
int(8)
}
igbinary-3.2.15/tests/igbinary_bug54662.phpt 0000664 0001750 0001750 00000001045 14532662345 017643 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-3.2.15/tests/igbinary_bug72134.phpt 0000664 0001750 0001750 00000001045 14532662345 017635 0 ustar tyson tyson --TEST--
igbinary_unserialize regression test for 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-3.2.15/tests/igbinary_enums_1.phpt 0000664 0001750 0001750 00000001777 14532662345 020042 0 ustar tyson tyson --TEST--
Test unserializing valid enums
--SKIPIF--
--FILE--
'Diamonds']);
echo urlencode($serArray), "\n";
var_dump(igbinary_unserialize($serArray));
?>
--EXPECT--
%00%00%00%02%17%04Suit%27%11%06Hearts
enum(Suit::Hearts)
enum(Suit::Hearts)
%00%00%00%02%14%06%06%00%17%04Suit%27%11%06Hearts%06%01%1A%00%27%11%08Diamonds%06%02%1A%00%27%11%06Spades%06%03%1A%00%27%11%05Clubs%06%04%22%04%0E%02%0E%02
array(6) {
[0]=>
enum(Suit::Hearts)
[1]=>
enum(Suit::Diamonds)
[2]=>
enum(Suit::Spades)
[3]=>
enum(Suit::Clubs)
[4]=>
enum(Suit::Clubs)
["Diamonds"]=>
string(8) "Diamonds"
}
igbinary-3.2.15/tests/igbinary_enums_2.phpt 0000664 0001750 0001750 00000003467 14532662345 020041 0 ustar tyson tyson --TEST--
Test unserializing valid and invalid enums
--SKIPIF--
--FILE--
Suit::Hearts];
$arr[1] = &$arr['Hearts'];
$serArray = igbinary_serialize($arr);
// PHP 8.1 added support for %0 as a null byte in EXPECTF in https://github.com/php/php-src/pull/7069
// Igbinary's use case of urlencode on binary data is rare.
// So replace % with \x
echo str_replace(['\\', '%'], ['\\\\', '\x'], urlencode($serArray)), "\n";
$result = igbinary_unserialize($serArray);
var_dump($result);
$result[1] = 'new';
var_dump($result);
$serInvalid = str_replace('Hearts', 'HEARTS', $serArray);
var_dump(igbinary_unserialize($serInvalid));
$serInvalidConst = str_replace('Hearts', 'vvvvvv', $serArray);
var_dump(igbinary_unserialize($serInvalidConst));
$serMissingClass = str_replace('Suit', 'Club', $serArray);
var_dump(igbinary_unserialize($serMissingClass));
$serInvalidClass = str_replace('Suit', 'ABCD', $serArray);
var_dump(igbinary_unserialize($serInvalidClass));
?>
--EXPECTF--
\x00\x00\x00\x02\x14\x02\x11\x06Hearts\x25\x17\x04Suit\x27\x0E\x00\x06\x01\x25\x22\x01
array(2) {
["Hearts"]=>
&enum(Suit::Hearts)
[1]=>
&enum(Suit::Hearts)
}
array(2) {
["Hearts"]=>
&string(3) "new"
[1]=>
&string(3) "new"
}
Warning: igbinary_unserialize_object_enum_case: Suit::HEARTS is not an enum case in %s on line 25
NULL
Warning: igbinary_unserialize_object_enum_case: Undefined constant Suit::vvvvvv in %s on line 28
NULL
Warning: igbinary_unserialize_object_enum_case: Class 'Club' does not exist in %s on line 31
NULL
Warning: igbinary_unserialize_object_enum_case: Class 'ABCD' is not an enum in %s on line 34
NULL igbinary-3.2.15/tests/igbinary_enums_3.phpt 0000664 0001750 0001750 00000000726 14532662345 020035 0 ustar tyson tyson --TEST--
Test unserializing valid enums inferring value
--SKIPIF--
--FILE--
value);
?>
--EXPECT--
enum(X::X)
%00%00%00%02%17%01X%27%0E%00
string(2) "ab"
igbinary-3.2.15/tests/igbinary_enums_3_php83.phpt 0000664 0001750 0001750 00000000777 14532662345 021065 0 ustar tyson tyson --TEST--
Test unserializing valid enums inferring value
--SKIPIF--
--FILE--
value);
?>
--EXPECT--
enum(X::X)
%00%00%00%02%17%01X%27%0E%00
string(8) "dynamicX"
igbinary-3.2.15/tests/igbinary_unserialize_v1_compatible.phpt 0000664 0001750 0001750 00000005276 14532662345 023630 0 ustar tyson tyson --TEST--
Unserialize backwards compatible with v1.
--INI--
pcre.jit=0
--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-3.2.15/tests/php82_suppress_dynamic_properties_warning.inc 0000664 0001750 0001750 00000001245 14532662345 025005 0 ustar tyson tyson
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%0A%00Test%00priv%00%0E%01%00
object(Test)#1 (1) {
["priv":"Test":private]=>
NULL
}
igbinary-3.2.15/tests/typed_property_ref_assignment_failure.phpt 0000664 0001750 0001750 00000001335 14532662345 024461 0 ustar tyson tyson --TEST--
Failure to assign ref to typed property
--SKIPIF--
--FILE--
prop = new stdClass();
$b->prop->y = &$b->prop;
$ser = igbinary_serialize($b);
echo str_replace('%', '\\x', urlencode($ser)), "\n";
// Should reject stdClass reference
$ser2 = str_replace('Best', 'Test', $ser);
try {
var_dump(igbinary_unserialize($ser2));
} catch (Error $e) {
printf("Caught %s: %s\n", get_class($e), $e->getMessage());
}
?>
--EXPECTF--
\x00\x00\x00\x02\x17\x04Best\x14\x01\x11\x04prop\x25\x17\x08stdClass\x14\x01\x11\x01y\x25\x22\x01
Caught TypeError: %s property Test::$prop %s
igbinary-3.2.15/tests/typed_property_ref_overwrite.phpt 0000664 0001750 0001750 00000001410 14532662345 022622 0 ustar tyson tyson --TEST--
Overwriting a typed property reference
--SKIPIF--
--FILE--
prop = $orig;
$orig->drop = null;
$ser = igbinary_serialize($orig);
unset($orig);
gc_collect_cycles(); // also tests that igbinary properly marks unserialized data as a possible gc cycle root.
var_dump(igbinary_unserialize($ser));
gc_collect_cycles();
echo "Test overwrite reference group\n";
$ser2 = str_replace('drop', 'prop', $ser);
var_dump(igbinary_unserialize($ser2));
?>
--EXPECT--
object(Test)#1 (2) {
["prop"]=>
*RECURSION*
["drop"]=>
NULL
}
Test overwrite reference group
object(Test)#1 (2) {
["prop"]=>
NULL
["drop"]=>
NULL
}
igbinary-3.2.15/tests/typed_property_ref_overwrite2.phpt 0000664 0001750 0001750 00000001501 14532662345 022705 0 ustar tyson tyson --TEST--
Overwriting a typed property that is not yet a reference
--SKIPIF--
--FILE--
drop = null;
$orig->prop = new Test();
$orig->prop->prop = &$orig->prop;
$ser = igbinary_serialize($orig);
echo urlencode($ser), "\n";
$ser2 = str_replace('drop', 'prop', $ser);
$result = igbinary_unserialize($ser2);
var_dump($result);
try {
$result->prop = 1;
} catch (TypeError $e) {
printf("Caught %s\n", get_class($e));
}
?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%04drop%00%11%04prop%25%1A%00%14%02%0E%01%00%0E%02%25%22%01
object(Test)#3 (2) {
["drop"]=>
NULL
["prop"]=>
&object(Test)#4 (2) {
["drop"]=>
NULL
["prop"]=>
*RECURSION*
}
}
Caught TypeError
igbinary-3.2.15/tests/typed_property_refs.phpt 0000664 0001750 0001750 00000004464 14532662345 020713 0 ustar tyson tyson --TEST--
unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
--FILE--
a = $value;
$v->b = &$v->a;
$ser = igbinary_serialize($v);
printf("for %s: %s\n", var_export($value, true), urlencode($ser));
return $ser;
}
$serInt = create_ser(1);
$serNull = create_ser(null);
$serStr = create_ser('x');
var_dump(igbinary_unserialize(str_replace('X', 'A', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'B', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'E', $serInt)));
try {
var_dump(igbinary_unserialize(str_replace('X', 'A', $serNull)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'B', $serNull)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'C', $serInt)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'C', $serStr)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'D', $serInt)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
for 1: %00%00%00%02%17%01X%14%02%11%01a%25%06%01%11%01b%25%01%01
for NULL: %00%00%00%02%17%01X%14%02%11%01a%25%00%11%01b%25%01%01
for 'x': %00%00%00%02%17%01X%14%02%11%01a%25%11%01x%11%01b%25%01%01
object(A)#1 (2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
object(B)#1 (2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
object(E)#1 (2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
Cannot assign null to property A::$a of type int
Cannot assign null to property B::$b of type int
Cannot assign int to property C::$b of type string
Cannot assign string to property C::$a of type int
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float
igbinary-3.2.15/tests/typed_property_refs_php74.phpt 0000664 0001750 0001750 00000004510 14532662345 021725 0 ustar tyson tyson --TEST--
unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
= 80000) die("skip requires php 7.4 error message"); ?>
--FILE--
a = $value;
$v->b = &$v->a;
$ser = igbinary_serialize($v);
printf("for %s: %s\n", var_export($value, true), urlencode($ser));
return $ser;
}
$serInt = create_ser(1);
$serNull = create_ser(null);
$serStr = create_ser('x');
var_dump(igbinary_unserialize(str_replace('X', 'A', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'B', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'E', $serInt)));
try {
var_dump(igbinary_unserialize(str_replace('X', 'A', $serNull)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'B', $serNull)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'C', $serInt)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'C', $serStr)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(igbinary_unserialize(str_replace('X', 'D', $serInt)));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
for 1: %00%00%00%02%17%01X%14%02%11%01a%25%06%01%11%01b%25%01%01
for NULL: %00%00%00%02%17%01X%14%02%11%01a%25%00%11%01b%25%01%01
for 'x': %00%00%00%02%17%01X%14%02%11%01a%25%11%01x%11%01b%25%01%01
object(A)#1 (2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
object(B)#1 (2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
object(E)#1 (2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
Typed property A::$a must be int, null used
Typed property B::$b must be int, null used
Typed property C::$b must be string, int used
Typed property C::$a must be int, string used
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float
igbinary-3.2.15/config.m4 0000664 0001750 0001750 00000005353 14532662345 014251 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)
PHP_IGBINARY_SRC_FILES="src/php7/igbinary.c src/php7/hash_si.c src/php7/hash_si_ptr.c"
if test -n "$phpincludedir" -a -d "$phpincludedir"; then
IGBINARY_PHPINCLUDEDIR=$phpincludedir
else
IGBINARY_PHPINCLUDEDIR=$abs_srcdir
fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <$IGBINARY_PHPINCLUDEDIR/main/php_version.h>
]], [[
#if PHP_MAJOR_VERSION < 7
#error PHP < 7
#endif
]])],[
AC_MSG_RESULT([PHP 7 or newer])
],[
AC_MSG_ERROR([PHP 5 is not supported by igbinary 3. Use igbinary 2 instead for PHP5 support.])
])
AC_MSG_CHECKING([for APCu includes])
if test -f "$IGBINARY_PHPINCLUDEDIR/ext/apcu/apc_serializer.h"; then
apc_inc_path="$IGBINARY_PHPINCLUDEDIR"
AC_MSG_RESULT([APCu in $apc_inc_path])
AC_DEFINE(HAVE_APCU_SUPPORT,1,[Whether to enable APCu support])
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 -Wcast-align -Wwrite-strings -Wswitch"
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 src/php7/igbinary.h php_igbinary.h src/php7/php_igbinary.h])
PHP_NEW_EXTENSION(igbinary, $PHP_IGBINARY_SRC_FILES, $ext_shared,, $PHP_IGBINARY_CFLAGS)
PHP_ADD_EXTENSION_DEP(igbinary, session, true)
AC_DEFINE(HAVE_IGBINARY, 1, [Have igbinary support])
PHP_ADD_BUILD_DIR($abs_builddir/src/php7, 1)
PHP_SUBST(IGBINARY_SHARED_LIBADD)
fi
igbinary-3.2.15/config.w32 0000664 0001750 0001750 00000003435 14532662345 014343 0 ustar tyson tyson // 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/);
// php 8.x also uses src/php7
var is_php7_or_newer = !is_php5 && null != dll.match(/^php[78]/)
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")
}
}
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) {
ERROR("PHP 5 is not supported by igbinary 3 - Use igbinary 2.x");
} else if (is_php7_or_newer) {
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', true);
PHP_INSTALL_HEADERS('ext/igbinary', 'igbinary.h php_igbinary.h ' + subdir + '\\igbinary.h ' + subdir + '\\php_igbinary.h');
}
igbinary-3.2.15/igbinary.h 0000664 0001750 0001750 00000000405 14532662345 014510 0 ustar tyson tyson #ifndef PHPEXT_IGBINARY_BASE_IGBINARY_H
#define PHPEXT_IGBINARY_BASE_IGBINARY_H
#include "php_version.h"
#if PHP_MAJOR_VERSION == 7 || PHP_MAJOR_VERSION == 8
#include "src/php7/igbinary.h"
#else
#error "Unsupported php version for igbinary build"
#endif
#endif
igbinary-3.2.15/php_igbinary.h 0000664 0001750 0001750 00000001424 14532662345 015361 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 == 7 || PHP_MAJOR_VERSION == 8
#include "ext/igbinary/src/php7/php_igbinary.h"
#else
#error "Unsupported php version for igbinary build"
#endif
/**
* The below line is redundant
* (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-3.2.15/src/php7/hash.h 0000664 0001750 0001750 00000007644 14532662345 015310 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) (or 1 if hash is truncated to 0). 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, uint32_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 through 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 through 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 through 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.
*/
static zend_always_inline size_t hash_si_size(struct hash_si *h) {
return h->used;
}
/** Returns capacity of hash_si.
* @param h Pointer to hash_si struct.
* @return Capacity of hash_si.
*/
static zend_always_inline size_t hash_si_capacity(struct hash_si *h) {
return h->mask + 1;
}
#endif /* HASH_H */
igbinary-3.2.15/src/php7/hash_ptr.h 0000664 0001750 0001750 00000006666 14532662345 016200 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 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 {
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 uintptr_t key, uint32_t value);
*/
/** Finds value from hash_si_ptr.
* Value returned through 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 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.
*/
static zend_always_inline size_t hash_si_ptr_size(struct hash_si_ptr *h) {
return h->used;
}
/**
* 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 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.
*/
zend_always_inline static size_t hash_si_ptr_capacity(struct hash_si_ptr *h) {
return h->size;
}
#endif /* HASH_PTR_H */
igbinary-3.2.15/src/php7/hash_si.c 0000664 0001750 0001750 00000011450 14532662345 015764 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"
/* {{{ hash_si_init */
/**
* Initializes a hash_si value with the given capacity
*/
int hash_si_init(struct hash_si *h, uint32_t size) {
ZEND_ASSERT((size & (size - 1)) == 0 && size > 0);
h->mask = size - 1;
h->used = 0;
h->data = (struct hash_si_pair *)ecalloc(size, sizeof(struct hash_si_pair));
if (h->data == NULL) {
return 1;
}
return 0;
}
/* }}} */
/* {{{ hash_si_deinit */
void hash_si_deinit(struct hash_si *h) {
struct hash_si_pair *const data = h->data;
if (h->used > 0) {
size_t i;
const size_t mask = h->mask;
for (i = 0; i <= mask; i++) {
if (data[i].key_zstr != NULL) {
zend_string_release(data[i].key_zstr);
}
}
}
efree(data);
}
/* }}} */
/* {{{ get_key_hash */
zend_always_inline static uint32_t get_key_hash(zend_string *key_zstr) {
/* Fetch the hash, computing and storing it in key_zstr if it was not computed before. */
uint32_t key_hash = ZSTR_HASH(key_zstr);
#if SIZEOF_ZEND_LONG > 4
if (UNEXPECTED(key_hash == 0)) {
/* A key_hash of uint32_t(0) would be treated like a gap when inserted. Change the hash used to 1 instead. */
/* uint32_t(ZSTR_HASH) is 0 for 1 in 4 billion - optimized builds may use cmove so there are no branch mispredicts, changing to key_hash >> 32 doesn't speed up benchmark/serialize-stringarray */
return 1;
}
#endif
return key_hash;
}
/* }}} */
/* {{{ hash_si_rehash */
/** Rehash/resize hash_si.
* @param h Pointer to hash_si struct.
*/
zend_always_inline static void hash_si_rehash(struct hash_si *h) {
size_t i;
size_t old_size;
size_t new_size;
size_t new_mask;
struct hash_si_pair *old_data;
struct hash_si_pair *new_data;
/* Allocate a table with double the capacity (the next power of 2). */
ZEND_ASSERT(h != NULL);
old_size = h->mask + 1;
new_size = old_size * 2;
new_mask = new_size - 1;
old_data = h->data;
new_data = (struct hash_si_pair *)ecalloc(new_size, sizeof(struct hash_si_pair));
h->data = new_data;
h->mask = new_mask;
/* Copy old entries to new entries */
for (i = 0; i < old_size; i++) {
const struct hash_si_pair *old_pair = &old_data[i];
if (old_pair->key_zstr != NULL) {
uint32_t hv = old_pair->key_hash & new_mask;
/* We already computed the hash, avoid recomputing it. */
/* Do linear probing for the next free slot. */
while (new_data[hv].key_hash != 0) {
hv = (hv + 1) & new_mask;
}
new_data[hv] = old_data[i];
}
}
/* Free old entries */
efree(old_data);
}
/* }}} */
/* {{{ hash_si_find_or_insert */
/**
* If the string key already exists in the map, return the associated value.
* If it doesn't exist, indicate that to the caller.
*
* This is used in igbinary_serialize to deduplicate strings.
*/
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;
struct hash_si_pair *data;
uint32_t key_hash = get_key_hash(key_zstr);
size_t mask;
uint32_t hv;
ZEND_ASSERT(h != NULL);
mask = h->mask;
hv = key_hash & mask;
data = h->data;
while (1) {
pair = &data[hv];
if (pair->key_hash == 0) {
/* This is a brand new key */
pair->key_zstr = key_zstr;
pair->key_hash = key_hash;
pair->value = value;
h->used++;
/* The size increased, so check if we need to expand the map */
if (UNEXPECTED(h->mask * 3 / 4 < h->used)) {
hash_si_rehash(h);
}
result.code = hash_si_code_inserted;
zend_string_addref(key_zstr);
return result;
} else if (pair->key_hash == key_hash && EXPECTED(zend_string_equals(pair->key_zstr, key_zstr))) {
/* This already exists in the hash map */
result.code = hash_si_code_exists;
result.value = pair->value;
return result;
}
/* linear prob */
hv = (hv + 1) & mask;
}
}
/* }}} */
/* {{{ 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;
}
}
}
*/
/* }}} */
/*
* 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-3.2.15/src/php7/hash_si_ptr.c 0000664 0001750 0001750 00000010625 14532662345 016654 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 |
+----------------------------------------------------------------------+
*/
#include
#include
#include
#include
#include
#include "hash_ptr.h"
#include "zend.h"
#include "igbinary_bswap.h"
/* This assumes that pointers differ in low addresses rather than high addresses */
inline static uint32_t inline_hash_of_address(uintptr_t ptr) {
#if UINTPTR_MAX > UINT32_MAX
uint64_t hash = ptr;
hash *= 0x5e2d58d8b3bce8d9;
// This is a single assembly instruction on recent compilers/platforms
hash = bswap_64(hash);
return hash;
#else
uint32_t hash = ptr;
hash *= 0x5e2d58d9;
// This is a single assembly instruction on recent compilers/platforms
hash = bswap_32(hash);
return hash;
#endif
}
/* {{{ 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 */
/**
* @param h the pointer to the hash map that will be initialized in place
* @param size the new capacity of the hash map
*/
int hash_si_ptr_init(struct hash_si_ptr *h, size_t size) {
size = nextpow2(size);
h->size = size;
h->used = 0;
/* Set everything to 0. sets keys to HASH_PTR_KEY_INVALID. */
h->data = (struct hash_si_ptr_pair *)ecalloc(size, sizeof(struct hash_si_ptr_pair));
if (h->data == NULL) {
return 1;
}
return 0;
}
/* }}} */
/* {{{ hash_si_ptr_deinit */
/**
* Frees the hash map h
* @param h Pointer to the hash map (hash_si_ptr struct) to free internal data structures of
*/
void hash_si_ptr_deinit(struct hash_si_ptr *h) {
efree(h->data);
}
/* }}} */
/* {{{ 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) {
size_t i;
size_t old_size;
size_t size;
size_t mask;
struct hash_si_ptr_pair *old_data;
struct hash_si_ptr_pair *new_data;
ZEND_ASSERT(h != NULL);
/* Allocate a table with double the capacity (the next power of 2). */
old_size = h->size;
size = old_size * 2;
mask = size - 1;
old_data = h->data;
new_data = (struct hash_si_ptr_pair *)ecalloc(size, sizeof(struct hash_si_ptr_pair));
h->size = size;
h->data = new_data;
/* Copy old entries to new entries */
for (i = 0; i < old_size; i++) {
if (old_data[i].key != HASH_PTR_KEY_INVALID) {
uint32_t hv = inline_hash_of_address(old_data[i].key) & mask;
/* Do linear probing for the next free slot. */
while (new_data[hv].key != HASH_PTR_KEY_INVALID) {
ZEND_ASSERT(new_data[hv].key != old_data[i].key);
hv = (hv + 1) & mask;
}
new_data[hv] = old_data[i];
}
}
/* Free old entries */
efree(old_data);
}
/* }}} */
/* {{{ hash_si_ptr_find_or_insert */
/**
* @param h the pointer to the hash map.
* @param key the key (representing to look up (or insert, if it doesn't exist)
* @param value - If the key does not exist, this is the value to associate with key
* @return the old value, or SIZE_MAX if the key is brand new.
*/
size_t hash_si_ptr_find_or_insert(struct hash_si_ptr *h, const uintptr_t key, uint32_t value) {
size_t size;
size_t mask;
uint32_t hv;
ZEND_ASSERT(h != NULL);
size = h->size;
mask = size - 1;
hv = inline_hash_of_address(key) & mask;
while (1) {
if (h->data[hv].key == HASH_PTR_KEY_INVALID) {
/* This is a brand new key */
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 (UNEXPECTED((h->size >> 1) < h->used)) {
hash_si_ptr_rehash(h);
}
return SIZE_MAX;
} else if (h->data[hv].key == key) {
/* This already exists in the hash map */
return h->data[hv].value;
}
/* linear prob */
hv = (hv + 1) & mask;
}
}
/* }}} */
/*
* 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-3.2.15/src/php7/igbinary.c 0000664 0001750 0001750 00000357361 14532662345 016170 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/zend_alloc.h"
#include "Zend/zend_exceptions.h"
#include "Zend/zend_interfaces.h"
#include "Zend/zend_compile.h" /* ZEND_ACC_NOT_SERIALIZABLE */
#include "ext/standard/info.h"
#include "ext/standard/php_var.h"
#if PHP_VERSION_ID >= 80100
#include "Zend/zend_enum.h"
#endif
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
# include "ext/session/php_session.h"
#endif
#include "ext/standard/php_incomplete_class.h"
#if PHP_VERSION_ID < 70400
#define zend_get_properties_for(struc, purpose) Z_OBJPROP_P((struc))
#define zend_release_properties(ht) do {} while (0)
#endif
#if PHP_VERSION_ID < 70300
#define zend_string_efree(s) zend_string_release((s))
#define GC_ADDREF(p) (++GC_REFCOUNT((p)))
#endif
#if defined(HAVE_APCU_SUPPORT)
# include "ext/apcu/apc_serializer.h"
#endif /* HAVE_APCU_SUPPORT */
#include "php_igbinary.h"
#include "igbinary.h"
#include "igbinary_macros.h"
#include
#include
#ifndef PHP_WIN32
# include
# include
# include
#endif
#include
#include "hash.h"
#include "hash_ptr.h"
#include "zend_alloc.h"
#include "igbinary_zend_hash.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
static zend_always_inline HashTable *HASH_OF_OBJECT(zval *p) {
ZEND_ASSERT(Z_TYPE_P(p) == IS_OBJECT);
return Z_OBJ_HT_P(p)->get_properties(
#if PHP_VERSION_ID >= 80000
Z_OBJ_P(p)
#else
p
#endif
);
}
#if PHP_VERSION_ID < 70300
#define zend_string_release_ex(s, persistent) zend_string_release((s))
static zend_always_inline void zval_ptr_dtor_str(zval *zval_ptr)
{
if (Z_REFCOUNTED_P(zval_ptr) && !Z_DELREF_P(zval_ptr)) {
ZEND_ASSERT(Z_TYPE_P(zval_ptr) == IS_STRING);
ZEND_ASSERT(!ZSTR_IS_INTERNED(Z_STR_P(zval_ptr)));
ZEND_ASSERT(!(GC_FLAGS(Z_STR_P(zval_ptr)) & IS_STR_PERSISTENT));
efree(Z_STR_P(zval_ptr));
}
}
#endif
#define RETURN_1_IF_NON_ZERO(cmd) \
if (UNEXPECTED((cmd) != 0)) { \
return 1; \
}
#ifdef ZEND_ACC_NOT_SERIALIZABLE
# define IGBINARY_IS_NOT_SERIALIZABLE(ce) UNEXPECTED((ce)->ce_flags & (ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ANON_CLASS))
# define IGBINARY_IS_NOT_UNSERIALIZABLE(ce) IGBINARY_IS_NOT_SERIALIZABLE(ce)
#elif PHP_VERSION_ID >= 70400
# define IGBINARY_IS_NOT_SERIALIZABLE(ce) UNEXPECTED((ce)->serialize == zend_class_serialize_deny)
# define IGBINARY_IS_NOT_UNSERIALIZABLE(ce) UNEXPECTED((ce)->unserialize == zend_class_unserialize_deny)
#else
// Because '__serialize' is not available prior to 7.4, this check is redundant.
# define IGBINARY_IS_NOT_SERIALIZABLE(ce) (0)
# define IGBINARY_IS_NOT_UNSERIALIZABLE(ce) (0)
#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 class name string id. */
/* 1b */ igbinary_type_object_id16, /**< Object class name string id. */
/* 1c */ igbinary_type_object_id32, /**< Object class name 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 */
/* 26 */ igbinary_type_string64, /**< String larger than 4GB (originally, php strings had a limit of 32-bit lengths). */
/* 27 */ igbinary_type_enum_case, /**< PHP 8.1 Enum case. */
};
/* Defers calls to zval_ptr_dtor for values that are refcounted. */
struct deferred_dtor_tracker {
zval *zvals; /**< refcounted objects and arrays to call dtor on after unserializing. See i_zval_ptr_dtor */
size_t count; /**< count of refcounted in array for calls to dtor */
size_t capacity; /**< capacity of refcounted in array for calls to dtor */
};
/** 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) */
uint32_t references_id; /**< Number of things that the unserializer might think are references. >= length of references */
uint32_t string_count; /**< Serialized string count, used for back referencing */
struct deferred_dtor_tracker deferred_dtor_tracker; /**< refcounted objects and arrays to call dtor on after serializing. See i_zval_ptr_dtor */
};
/*
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)
empty array {} (use ZVAL_EMPTY_ARRAY to create zvals)
}
*/
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_array
#if PHP_VERSION_ID >= 70300
IG_REF_IS_EMPTY_ARRAY, // Use the macro ZVAL_EMPTY_ARRAY to create a pointer to the empty array with the correct type info flags.
#endif
};
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;
};
struct deferred_unserialize_call {
zval param; /* The array parameter passed to the __unserialize call */
zend_object *object; /* The object which has a deferred call to __unserialize that is going to get called. */
};
struct deferred_call {
union {
zend_object *wakeup;
#if PHP_VERSION_ID >= 70400
/* Currently, zvals are safe to relocate */
struct deferred_unserialize_call unserialize;
#endif
} data;
#if PHP_VERSION_ID >= 70400
zend_bool is_unserialize;
#endif
};
/** Unserializer data.
* @author Oleg Grenrus
*/
struct igbinary_unserialize_data {
const uint8_t *buffer; /**< Buffer with bytes to unserialize. */
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. */
struct deferred_call *deferred; /**< objects&data for calls to __unserialize/__wakeup */
size_t deferred_capacity; /**< capacity of objects in array for calls to __unserialize/__wakeup */
uint32_t deferred_count; /**< count of objects in array for calls to __unserialize/__wakeup. NOTE: Current php releases including 8.1 limit the total number of objects to a 32-bit integer. */
zend_bool deferred_finished; /**< whether the deferred calls were performed */
struct deferred_dtor_tracker deferred_dtor_tracker; /**< refcounted objects and arrays to call dtor on after unserializing. See i_zval_ptr_dtor */
#if PHP_VERSION_ID >= 70400
HashTable *ref_props; /**< objects&data for calls to __unserialize/__wakeup */
#endif
};
#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)
/* }}} */
/* {{{ Serializing functions prototypes */
zend_always_inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar);
zend_always_inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd);
zend_always_inline static void igbinary_serialize_header(struct igbinary_serialize_data *igsd);
zend_always_inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i);
zend_always_inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i);
zend_always_inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i);
zend_always_inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i);
zend_always_inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd);
zend_always_inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b);
zend_always_inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, zend_long l);
zend_always_inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d);
zend_always_inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, zend_string *s);
zend_always_inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len);
zend_always_inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class, bool serialize_props);
zend_always_inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object);
zend_always_inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *ht, zend_class_entry *ce);
zend_always_inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, zend_string *name);
zend_always_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 */
zend_always_inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd);
zend_always_inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd);
zend_always_inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd);
zend_always_inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd);
zend_always_inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd);
zend_always_inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd);
zend_always_inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd);
zend_always_inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zend_long *ret);
zend_always_inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, double *ret);
zend_always_inline static zend_string *igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t);
zend_always_inline static zend_string *igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zend_bool check_interned);
zend_always_inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags, zend_bool create_ref);
zend_always_inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags);
static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, zend_class_entry *ce);
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 = {
STANDARD_MODULE_HEADER_EX, NULL,
igbinary_module_deps,
"igbinary",
igbinary_functions,
PHP_MINIT(igbinary),
PHP_MSHUTDOWN(igbinary),
NULL,
NULL,
PHP_MINFO(igbinary),
PHP_IGBINARY_VERSION,
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 */
/**
* The module init function.
* This allocates the persistent resources of this PHP module.
*/
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 */
/**
* The module shutdown function.
* This cleans up all persistent resources of this PHP module.
*/
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 APCu 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 zend_always_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) {
igsd->references_capacity *= 2;
struct igbinary_value_ref *new_references = erealloc(igsd->references, sizeof(igsd->references[0]) * igsd->references_capacity);
if (UNEXPECTED(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 zend_always_inline int igsd_ensure_defer_capacity(struct igbinary_unserialize_data *igsd) {
if (igsd->deferred_count >= igsd->deferred_capacity) {
if (igsd->deferred_capacity == 0) {
igsd->deferred_capacity = 2;
igsd->deferred = emalloc(sizeof(igsd->deferred[0]) * igsd->deferred_capacity);
} else {
igsd->deferred_capacity *= 2;
struct deferred_call *old_deferred = igsd->deferred;
igsd->deferred = erealloc(old_deferred, sizeof(igsd->deferred[0]) * igsd->deferred_capacity);
if (UNEXPECTED(igsd->deferred == NULL)) {
igsd->deferred = old_deferred;
return 1;
}
}
}
return 0;
}
static inline int igsd_defer_wakeup(struct igbinary_unserialize_data *igsd, zend_object *object) {
// TODO: This won't be properly garbage collected if there is an OOM error, but would php terminate instead?
RETURN_1_IF_NON_ZERO(igsd_ensure_defer_capacity(igsd));
struct deferred_call *c = &igsd->deferred[igsd->deferred_count++];
c->data.wakeup = object;
#if PHP_VERSION_ID >= 70400
c->is_unserialize = 0;
#endif
return 0;
}
/* igsd_defer_unserialize {{{ */
#if PHP_VERSION_ID >= 70400
static inline int igsd_defer_unserialize(struct igbinary_unserialize_data *igsd, zend_object *object, zval param) {
RETURN_1_IF_NON_ZERO(igsd_ensure_defer_capacity(igsd));
struct deferred_call *c = &igsd->deferred[igsd->deferred_count++];
struct deferred_unserialize_call* call = &c->data.unserialize;
call->object = object;
ZEND_ASSERT(Z_TYPE(param) == IS_ARRAY);
call->param = param;
c->is_unserialize = 1;
return 0;
}
#endif
/* }}} */
/* {{{ igbinary_finish_deferred_calls
* After all object instances were unserialized, perform the deferred calls to __wakeup() on all of the objects implementing that method.
*/
static int igbinary_finish_deferred_calls(struct igbinary_unserialize_data *igsd) {
#if PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 80000
zval unserialize_name;
#endif
zval wakeup_name;
uint32_t i;
struct deferred_call *deferred_arr;
uint32_t deferred_count = igsd->deferred_count;
zend_bool delayed_call_failed = 0;
igsd->deferred_finished = 1;
if (deferred_count == 0) { /* nothing to do */
return 0;
}
deferred_arr = igsd->deferred;
#if PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 80000
ZVAL_STRINGL(&unserialize_name, "__unserialize", sizeof("__unserialize") - 1);
#endif
ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1);
for (i = 0; i < deferred_count; i++) {
struct deferred_call *deferred = &deferred_arr[i];
#if PHP_VERSION_ID >= 70400
if (deferred->is_unserialize) {
struct deferred_unserialize_call *unserialize_call = &deferred->data.unserialize;
zend_object *const obj = unserialize_call->object;
ZEND_ASSERT(Z_TYPE(unserialize_call->param) == IS_ARRAY);
if (!delayed_call_failed) {
#if PHP_VERSION_ID >= 80000
/* Copy the parameter for __unserialize so that changes in __unserialize won't mutate the original. */
// ZVAL_COPY(¶m, &unserialize_call->param);
BG(serialize_lock)++;
zend_call_known_instance_method_with_1_params(
obj->ce->__unserialize, obj, NULL, &unserialize_call->param);
if (EG(exception)) {
delayed_call_failed = 1;
GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED);
}
BG(serialize_lock)--;
#else
zval retval;
zval zv;
ZVAL_OBJ(&zv, obj);
/* Copy the parameter for __unserialize so that changes in __unserialize won't mutate the original. */
// ZVAL_COPY(¶m, &unserialize_call->param);
BG(serialize_lock)++;
if (call_user_function(CG(function_table), &zv, &unserialize_name, &retval, 1, &unserialize_call->param) == FAILURE || Z_ISUNDEF(retval))
{
delayed_call_failed = 1;
GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED);
}
BG(serialize_lock)--;
zval_ptr_dtor(&retval);
#endif
} else {
GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED);
}
zval_ptr_dtor(&unserialize_call->param);
} else
#endif
{
zend_object *obj = deferred->data.wakeup;
if (!delayed_call_failed) {
zval retval; /* return value of __wakeup */
zval rval;
ZVAL_OBJ(&rval, obj);
if (UNEXPECTED(call_user_function(CG(function_table), &rval, &wakeup_name, &retval, 0, 0) == FAILURE || Z_ISUNDEF(retval))) {
delayed_call_failed = 1;
GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED);
}
zval_ptr_dtor(&retval);
} else {
GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED);
}
}
}
zval_ptr_dtor_str(&wakeup_name);
#if PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 80000
zval_ptr_dtor_str(&unserialize_name);
#endif
return delayed_call_failed;
}
/* }}} */
/* }}} */
/* {{{ igsd_ensure_deferred_dtor_capacity(struct igbinary_serialize_data *igsd) */
static inline int igsd_ensure_deferred_dtor_capacity(struct deferred_dtor_tracker *tracker) {
if (tracker->count >= tracker->capacity) {
if (tracker->capacity == 0) {
tracker->capacity = 2;
tracker->zvals = emalloc(sizeof(tracker->zvals[0]) * tracker->capacity);
} else {
tracker->capacity *= 2;
zval *old_deferred_dtor = tracker->zvals;
tracker->zvals = erealloc(old_deferred_dtor, sizeof(tracker->zvals[0]) * tracker->capacity);
if (UNEXPECTED(tracker->zvals == NULL)) {
tracker->zvals = old_deferred_dtor;
return 1;
}
}
}
return 0;
}
/* }}} */
/* {{{ free_deferred_dtors(struct deferred_dtor_tracker *tracker) */
static zend_always_inline void free_deferred_dtors(struct deferred_dtor_tracker *tracker) {
zval *const zvals = tracker->zvals;
if (zvals) {
const size_t n = tracker->count;
size_t i;
for (i = 0; i < n; i++) {
/* fprintf(stderr, "freeing i=%d id=%d refcount=%d\n", (int)i, (int)Z_OBJ_HANDLE(zvals[i]), (int)Z_REFCOUNT(zvals[i])); */
zval_ptr_dtor(&zvals[i]);
}
efree(zvals);
}
}
/* }}} */
/* {{{ igsd_addref_and_defer_dtor(struct igbinary_serialize_data *igsd, zval *z) */
static zend_always_inline int igsd_addref_and_defer_dtor(struct deferred_dtor_tracker *tracker, zval *z) {
if (!Z_REFCOUNTED_P(z)) {
return 0;
}
if (UNEXPECTED(igsd_ensure_deferred_dtor_capacity(tracker))) {
return 1;
}
ZEND_ASSERT(Z_REFCOUNT_P(z) >= 1); /* Expect that there were references at the time this was serialized */
ZVAL_COPY(&tracker->zvals[tracker->count++], z); /* Copy and increase reference count */
return 0;
}
/* }}} */
/* {{{ igsd_defer_dtor(struct igbinary_serialize_data *igsd, zval *z) */
static inline int igsd_defer_dtor(struct deferred_dtor_tracker *tracker, zval *z) {
if (!Z_REFCOUNTED_P(z)) {
return 0;
}
if (igsd_ensure_deferred_dtor_capacity(tracker)) {
return 1;
}
ZEND_ASSERT(Z_REFCOUNT_P(z) >= 1); /* Expect that there were references at the time this was serialized */
ZVAL_COPY_VALUE(&tracker->zvals[tracker->count++], z); /* Copy without increasing reference count */
return 0;
}
/* }}} */
/* {{{ 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*) */
/**
* Serializes data, and writes the allocated byte buffer into ret and the buffer's length into ret_len.
* @param ret output parameter
* @param ret_len length of byte buffer ret
* @param z the zval (data) to serialize
* @param memory_manager (nullable) the memory manager to use for allocating/reallocating the buffer of serialized data. Used by extensions such as APCu
* @return 0 on success, 1 on failure
*/
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;
int return_code;
// While we can't get passed references through the PHP_FUNCTIONs igbinary declares, third party code can invoke igbinary's methods with references.
// See https://github.com/php-memcached-dev/php-memcached/issues/326
if (UNEXPECTED(Z_TYPE_P(z) == IS_INDIRECT)) {
z = Z_INDIRECT_P(z);
}
ZVAL_DEREF(z);
if (UNEXPECTED(igbinary_serialize_data_init(&igsd, Z_TYPE_P(z) != IS_OBJECT && Z_TYPE_P(z) != IS_ARRAY))) {
zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
return 1;
}
igbinary_serialize_header(&igsd);
return_code = 0;
if (UNEXPECTED(igbinary_serialize_zval(&igsd, z) != 0)) {
return_code = 1;
goto cleanup;
}
/* Explicit null termination */
/* TODO: Stop doing this in the next major version, serialized data can contain nulls in the middle and callers should check length */
if (UNEXPECTED(igbinary_serialize8(&igsd, 0) != 0)) {
return_code = 1;
goto cleanup;
}
/* shrink buffer to the real length, ignore errors */
if (UNEXPECTED(memory_manager)) {
tmpbuf = memory_manager->alloc(igsd.buffer_size, memory_manager->context);
if (tmpbuf != NULL) {
memcpy(tmpbuf, igsd.buffer, igsd.buffer_size);
}
if (tmpbuf == NULL) {
return_code = 1;
goto cleanup;
}
*ret = tmpbuf;
*ret_len = igsd.buffer_size - 1;
} else {
/* Set return values */
*ret_len = igsd.buffer_size - 1;
*ret = igsd.buffer;
igsd.buffer = NULL;
}
cleanup:
igbinary_serialize_data_deinit(&igsd);
return return_code;
}
/* }}} */
/* {{{ int igbinary_unserialize(const uint8_t *, size_t, zval **) */
/**
* Unserializes the data into z
* @param buf the read-only buffer with the serialized data
* @param buf_len the length of that buffer.
* @param z output parameter. Will contain the unserialized value(zval).
* @return 0 on success, 1 on failure
*/
IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval *z) {
struct igbinary_unserialize_data igsd;
int ret = 0;
igbinary_unserialize_data_init(&igsd);
igsd.buffer = buf;
igsd.buffer_ptr = buf;
igsd.buffer_end = buf + buf_len;
if (UNEXPECTED(igbinary_unserialize_header(&igsd))) {
ret = 1;
goto cleanup;
}
if (UNEXPECTED(igbinary_unserialize_zval(&igsd, z, WANT_CLEAR))) {
ret = 1;
goto cleanup;
}
if (Z_REFCOUNTED_P(z)) {
#if PHP_VERSION_ID >= 70200
zend_refcounted *ref = Z_COUNTED_P(z);
gc_check_possible_root(ref);
#else
gc_check_possible_root(z);
#endif
}
if (UNEXPECTED(igsd.buffer_ptr < igsd.buffer_end)) {
// https://github.com/igbinary/igbinary/issues/64
zend_error(E_WARNING, "igbinary_unserialize: received more data to unserialize than expected");
ret = 1;
goto cleanup;
}
if (UNEXPECTED(igbinary_finish_deferred_calls(&igsd))) {
ret = 1;
goto cleanup;
}
cleanup:
igbinary_unserialize_data_deinit(&igsd);
return ret;
}
/* }}} */
/* {{{ proto string igbinary_unserialize(mixed value) */
/**
* @see igbinary.php for more detailed API documentation.
*/
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) */
/**
* @see igbinary.php for more detailed API documentation.
*/
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 */
/**
* This provides a serializer encode function for PHP's session module (using igbinary),
* if igbinary was compiled with session support.
*
* Session support has to be statically compiled into php to use igbinary,
* due to the lack of a cross-platform way to register a session serializer/unserializer
* when the session module isn't available.
*/
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 (igbinary_serialize_data_init(&igsd, false)) {
zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
return ZSTR_EMPTY_ALLOC();
}
igbinary_serialize_header(&igsd);
/** We serialize the passed in array of session_var (including the empty array, for #231) */
/** the same way we would serialize a regular array. */
/** The corresponding PS_SERIALIZER_DECODE_FUNC will unserialize the array and individually add the session variables. */
if (igbinary_serialize_array(&igsd, session_vars, false, false, true) != 0) {
zend_error(E_WARNING, "igbinary_serialize: cannot serialize session variables");
result = ZSTR_EMPTY_ALLOC();
} else {
/* Copy the buffer to a new zend_string */
result = zend_string_init((const char *)igsd.buffer, igsd.buffer_size, 0);
}
igbinary_serialize_data_deinit(&igsd);
return result;
}
/* }}} */
/* {{{ Serializer decode function */
/**
* This provides a serializer decode function for PHP's session module (using igbinary),
* if igbinary was compiled with session support.
*
* Session support has to be statically compiled into php to use igbinary,
* due to the lack of a cross-platform way to register a session serializer/unserializer
* when the session module isn't available.
*
* 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;
int ret = 0;
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 (UNEXPECTED(igbinary_unserialize_header(&igsd))) {
ret = 1;
goto deinit;
}
/** The serializer serialized the session variables as an array. So, we unserialize that array. */
/** We then iterate over the array to set the individual session variables (managing the reference counts), then free the original array. */
if (UNEXPECTED(igbinary_unserialize_zval(&igsd, &z, WANT_CLEAR))) {
ret = 1;
goto deinit;
}
ret = igbinary_finish_deferred_calls(&igsd);
deinit:
igbinary_unserialize_data_deinit(&igsd);
if (UNEXPECTED(ret)) {
return FAILURE;
}
/* Validate that this is of the correct data type */
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 - We return 1 to indicate success to APCu (and 0 for failure) */
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 - We return 1 to indicate success to APCu (and 0 for failure) */
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 */
/**
* Allocates data structures needed by igbinary_serialize_data,
* and sets properties of igsd to their defaults.
* @param igsd the struct to initialize
* @param scalar true if the data being serialized is a scalar
* @param memory_manager optional override of the memory manager
*/
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar) {
void *buffer = emalloc(32);
if (UNEXPECTED(buffer == NULL)) {
return 1;
}
igsd->buffer_size = 0;
igsd->buffer_capacity = 32;
igsd->string_count = 0;
igsd->buffer = buffer;
igsd->scalar = scalar;
if (scalar) {
igsd->compact_strings = 0;
} else {
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);
igsd->deferred_dtor_tracker.zvals = NULL;
igsd->deferred_dtor_tracker.count = 0;
igsd->deferred_dtor_tracker.capacity = 0;
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_data_deinit */
/** Deinits igbinary_serialize_data, freeing the allocated data structures. */
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd) {
bool scalar = igsd->scalar;
if (igsd->buffer) {
efree(igsd->buffer);
}
if (!scalar) {
hash_si_deinit(&igsd->strings);
hash_si_ptr_deinit(&igsd->references);
free_deferred_dtors(&igsd->deferred_dtor_tracker);
}
}
/* }}} */
/* {{{ igbinary_serialize_header */
/** Serializes header ("\x00\x00\x00\x02"). */
inline static void igbinary_serialize_header(struct igbinary_serialize_data *igsd) {
uint8_t* append_buffer = igsd->buffer;
ZEND_ASSERT(igsd->buffer_size == 0);
ZEND_ASSERT(igsd->buffer_capacity >= 4);
append_buffer[0] = 0;
append_buffer[1] = 0;
append_buffer[2] = 0;
append_buffer[3] = IGBINARY_FORMAT_VERSION;
igsd->buffer_size = 4;
}
/* }}} */
static int igbinary_raise_capacity(struct igbinary_serialize_data *igsd, size_t size) {
do {
igsd->buffer_capacity *= 2;
} while (igsd->buffer_size + size >= igsd->buffer_capacity);
uint8_t *const old_buffer = igsd->buffer;
igsd->buffer = erealloc(old_buffer, igsd->buffer_capacity);
if (UNEXPECTED(igsd->buffer == NULL)) {
/* We failed to allocate a larger buffer for the result. Free the memory used for the original buffer. */
efree(old_buffer);
return 1;
}
return 0;
}
/* {{{ igbinary_serialize_resize */
/** Expands igbinary_serialize_data if necessary. */
zend_always_inline static int igbinary_serialize_resize(struct igbinary_serialize_data *igsd, size_t size) {
if (igsd->buffer_size + size < igsd->buffer_capacity) {
return 0;
}
return igbinary_raise_capacity(igsd, size);
}
/* }}} */
/* {{{ igbinary_serialize8 */
/** Serialize 8bit value. */
zend_always_inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i) {
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 1));
igsd->buffer[igsd->buffer_size++] = i;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize16 */
/** Serialize 16bit value. */
zend_always_inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 2));
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. */
zend_always_inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 4));
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. */
zend_always_inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 8));
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_serialize8 */
/** Serialize 8bit value + 8bit value. */
zend_always_inline static int igbinary_serialize8_and_8(struct igbinary_serialize_data *igsd, uint8_t i, uint8_t v) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 2));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = i;
append_buffer[1] = v;
igsd->buffer_size += 2;
return 0;
}
/* }}} */
/** Serialize 8bit value + 16bit value. */
zend_always_inline static int igbinary_serialize8_and_16(struct igbinary_serialize_data *igsd, uint8_t i, uint16_t v) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 3));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = i;
append_buffer[1] = (uint8_t)(v >> 8 & 0xff);
append_buffer[2] = (uint8_t)(v & 0xff);
;
igsd->buffer_size += 3;
return 0;
}
/* }}} */
/** Serialize 8bit value + 32bit value. */
zend_always_inline static int igbinary_serialize8_and_32(struct igbinary_serialize_data *igsd, uint8_t i, uint32_t v) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 5));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = i;
append_buffer[1] = (uint8_t)(v >> 24 & 0xff);
append_buffer[2] = (uint8_t)(v >> 16 & 0xff);
append_buffer[3] = (uint8_t)(v >> 8 & 0xff);
append_buffer[4] = (uint8_t)(v & 0xff);
;
igsd->buffer_size += 5;
return 0;
}
/* }}} */
/** Serialize 8bit value + 64bit value. */
inline static int igbinary_serialize8_and_64(struct igbinary_serialize_data *igsd, uint8_t i, uint64_t v) {
uint8_t *append_buffer;
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, 9));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = i;
append_buffer[1] = (uint8_t)(v >> 56 & 0xff);
append_buffer[2] = (uint8_t)(v >> 48 & 0xff);
append_buffer[3] = (uint8_t)(v >> 40 & 0xff);
append_buffer[4] = (uint8_t)(v >> 32 & 0xff);
append_buffer[5] = (uint8_t)(v >> 24 & 0xff);
append_buffer[6] = (uint8_t)(v >> 16 & 0xff);
append_buffer[7] = (uint8_t)(v >> 8 & 0xff);
append_buffer[8] = (uint8_t)(v & 0xff);
;
igsd->buffer_size += 9;
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) {
const bool p = l >= 0;
// k is the absolute value of l
const zend_ulong k = p ? (zend_ulong)l : -(zend_ulong)l;
if (k <= 0xff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd,
p ? igbinary_type_long8p : igbinary_type_long8n,
(uint8_t)k
));
} else if (k <= 0xffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd,
p ? igbinary_type_long16p : igbinary_type_long16n,
(uint16_t)k
));
#if SIZEOF_ZEND_LONG == 8
} else if (k <= 0xffffffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd,
p ? igbinary_type_long32p : igbinary_type_long32n,
(uint32_t)k
));
} else {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_64(igsd,
p ? igbinary_type_long64p : igbinary_type_long64n,
(uint64_t)k
));
}
#elif SIZEOF_ZEND_LONG == 4
} else {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd,
p ? igbinary_type_long32p : igbinary_type_long32n,
(uint32_t)k
));
}
#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;
u.d = d;
return igbinary_serialize8_and_64(igsd, igbinary_type_double, u.u);
}
/* }}} */
/* {{{ igbinary_serialize_string */
/**
* Serializes string.
*
* When compact_strings is true,
* this will serialize the string as igbinary_type_string* (A length followed by a character array) the first time,
* and serialize subsequent references to the same string as igbinary_type_string_id*.
*
* When compact_strings is false, this will always serialize the string as a character array.
* compact_strings speeds up serialization, but slows down serialization and uses more space to represent the serialization.
*
* Serializes each string once.
* After first time uses pointers (igbinary_type_string_id*) instead of igbinary_type_string*.
*/
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, zend_string *s) {
const size_t len = ZSTR_LEN(s);
if (len == 0) {
/* The empty string is always serialized as igbinary_serialize_string (1 byte instead of 2) */
return igbinary_serialize8(igsd, igbinary_type_string_empty);
}
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) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd, (uint8_t)igbinary_type_string_id8, (uint8_t)value));
} else if (value <= 0xffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd, (uint8_t)igbinary_type_string_id16, (uint16_t)value));
} else {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd, (uint8_t)igbinary_type_string_id32, value));
}
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 (UNEXPECTED(igsd->string_count == 0)) {
zend_error(E_WARNING, "igbinary_serialize: Saw too many strings");
return 1;
}
return igbinary_serialize_chararray(igsd, ZSTR_VAL(s), len);
}
/* }}} */
#if SIZEOF_SIZE_T > 4
static ZEND_COLD zend_never_inline int igbinary_serialize_extremely_long_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len) {
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, len + 9));
uint8_t *append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = igbinary_type_string64;
append_buffer[1] = (uint8_t)(len >> 56 & 0xff);
append_buffer[2] = (uint8_t)(len >> 48 & 0xff);
append_buffer[3] = (uint8_t)(len >> 40 & 0xff);
append_buffer[4] = (uint8_t)(len >> 32 & 0xff);
append_buffer[5] = (uint8_t)(len >> 24 & 0xff);
append_buffer[6] = (uint8_t)(len >> 16 & 0xff);
append_buffer[7] = (uint8_t)(len >> 8 & 0xff);
append_buffer[8] = (uint8_t)(len & 0xff);
memcpy(append_buffer + 9, s, len);
igsd->buffer_size += 9 + len;
return 0;
}
#endif
/* {{{ igbinary_serialize_chararray */
/** Serializes string data as the type followed by the length followed by the raw character array. */
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len) {
uint8_t *append_buffer;
int offset;
if (len <= 0xff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, len + 2));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = igbinary_type_string8;
append_buffer[1] = len;
offset = 2;
} else if (len <= 0xffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, len + 3));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = igbinary_type_string16;
append_buffer[1] = (uint8_t)(len >> 8 & 0xff);
append_buffer[2] = (uint8_t)(len & 0xff);
offset = 3;
} else {
#if SIZEOF_SIZE_T > 4
if (UNEXPECTED(len > 0xffffffff)) {
return igbinary_serialize_extremely_long_chararray(igsd, s, len);
}
#endif
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, len + 5));
append_buffer = &igsd->buffer[igsd->buffer_size];
append_buffer[0] = igbinary_type_string32;
append_buffer[1] = (uint8_t)(len >> 24 & 0xff);
append_buffer[2] = (uint8_t)(len >> 16 & 0xff);
append_buffer[3] = (uint8_t)(len >> 8 & 0xff);
append_buffer[4] = (uint8_t)(len & 0xff);
offset = 5;
}
memcpy(append_buffer + offset, s, len);
igsd->buffer_size += offset + len;
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_array */
/**
* Serializes an array's or object's inner properties.
* If properties or keys are unexpectedly added (e.g. by __sleep() or serialize() elsewhere), this will skip serializing them.
* If properties or keys are unexpectedly removed, this will add igbinary_type_null as padding for the corresponding entries.
*/
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class, bool serialize_props) {
/* 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;
/* At the time of writing, struct _zend_array had uint32_t nNumOfElements */
uint32_t n;
zval *d;
zval *z_original;
zend_string *key;
zend_long key_index;
z_original = z;
ZVAL_DEREF(z);
ZEND_ASSERT((!object || !serialize_props) && (object || !incomplete_class));
/* hash */
if (object) {
h = zend_get_properties_for(z, ZEND_PROP_PURPOSE_SERIALIZE);
n = h ? zend_hash_num_elements(h) : 0;
/* incomplete class magic member */
if (incomplete_class && n > 0) {
--n;
}
} else {
h = Z_ARRVAL_P(z);
n = zend_hash_num_elements(h);
/* if it is an array or a reference to an array, then add a reference unique to that **reference** to that array */
if (serialize_props) {
int ref_ser = igbinary_serialize_array_ref(igsd, z_original, false);
if (ref_ser != 2) {
/* 1 means out of memory or error, 0 means this already exists, 2 means this is new. */
return ref_ser;
}
}
}
if (n <= 0xff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd, igbinary_type_array8, (uint8_t)n));
if (n == 0) {
if (object) {
zend_release_properties(h);
}
return 0;
}
} else if (n <= 0xffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd, igbinary_type_array16, (uint16_t)n));
} else {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd, igbinary_type_array32, n));
}
/* serialize properties. */
ZEND_HASH_FOREACH_KEY_VAL(h, key_index, key, d) {
/* skip magic member in incomplete classes */
/* Match it exactly and permit null bytes in the middle so that the counts will match. */
if (incomplete_class && zend_string_equals_literal(key, MAGIC_MEMBER)) {
continue;
}
/* https://wiki.php.net/phpng-int - This is a declared property of an object, or an element of $GLOBALS */
if (Z_TYPE_P(d) == IS_INDIRECT) {
d = Z_INDIRECT_P(d);
}
if (Z_TYPE_P(d) == IS_UNDEF) {
/* This is an undefined declared typed property of an object. */
/* This can't be a value or a reference in an array - except maybe for $GLOBALS, which has other issues. */
ZEND_ASSERT(!serialize_props);
RETURN_1_IF_NON_ZERO(igbinary_serialize_null(igsd));
continue;
}
if (key == NULL) {
/* Key is numeric */
RETURN_1_IF_NON_ZERO(igbinary_serialize_long(igsd, key_index));
} else {
/* Key is string */
RETURN_1_IF_NON_ZERO(igbinary_serialize_string(igsd, key));
}
/* we should still add element even if it's not OK,
* since we already wrote the length of the array before */
RETURN_1_IF_NON_ZERO(igbinary_serialize_zval(igsd, d));
} ZEND_HASH_FOREACH_END();
if (object) {
zend_release_properties(h);
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_array_ref */
/** Serializes array reference (or reference in an object). Returns 0 on success. */
/* TODO: Use different result codes for missing keys and errors */
zend_always_inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval * const z, bool object) {
size_t t;
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 won't 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_ASSERT(Z_ISREF_P(z) || (object && Z_TYPE_P(z) == IS_OBJECT) || Z_TYPE_P(z) == IS_ARRAY);
// 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 */
// NOTE: The original code would always use the same memory address - Z_COUNTED_P is the start of an object/array/reference
// if (object && Z_TYPE_P(z) == IS_OBJECT) {
// key = (uintptr_t)Z_OBJ_P(z); /* expand object handle(uint32_t), cast to 32-bit/64-bit pointer */
// } else if (is_ref) {
// /* NOTE: PHP 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 if (and only if) the references are the same. */
// /* is_ref implies there is a unique reference counting pointer for the reference */
// key = (uintptr_t)Z_COUNTED_P(z);
// } else if (EXPECTED(Z_TYPE_P(z) == IS_ARRAY)) {
// key = (uintptr_t)Z_ARR_P(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 = (uintptr_t)&INVALID_KEY;
} else {
key = (uintptr_t)z->value.ptr;
}
t = hash_si_ptr_find_or_insert(&igsd->references, key, igsd->references_id);
if (t == SIZE_MAX) {
/* This is a brand new object/array/reference entry with a key equal to igsd->references_id */
igsd->references_id++;
if (UNEXPECTED(igsd->references_id == 0)) {
zend_error(E_WARNING, "igbinary_serialize: Saw too many references");
return 1;
}
/* We only need to call this if the array/object is new, in case __serialize or other methods return temporary arrays or modify arrays that were serialized earlier */
igsd_addref_and_defer_dtor(&igsd->deferred_dtor_tracker, z);
return 2;
}
/* TODO: Properly handle running out of memory in this helper function. */
/* It returns 1 both for running out of memory and inserting a new entry. */
enum igbinary_type type;
if (t <= 0xff) {
type = object ? igbinary_type_objref8 : igbinary_type_ref8;
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd, (uint8_t)type, (uint8_t)t));
} else if (t <= 0xffff) {
type = object ? igbinary_type_objref16 : igbinary_type_ref16;
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd, (uint8_t)type, (uint16_t)t))
} else {
type = object ? igbinary_type_objref32 : igbinary_type_ref32;
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd, (uint8_t)type, (uint32_t)t))
}
return 0;
}
/* }}} */
/* {{{ igbinary_serialize_array_sleep_single_prop_value */
/** Serializes one value of an object's properties array, for use with the __sleep function. */
inline static int igbinary_serialize_array_sleep_single_prop_value(struct igbinary_serialize_data *igsd, zval *z, zval *v, zend_class_entry *ce, zend_string *prop_name) {
/* Precondition: All args are non-null */
if (Z_TYPE_P(v) == IS_INDIRECT) {
v = Z_INDIRECT_P(v);
if (UNEXPECTED(Z_TYPE_P(v) == IS_UNDEF)) {
#if PHP_VERSION_ID >= 70400
if (UNEXPECTED(zend_get_typed_property_info_for_slot(Z_OBJ_P(z), v) != NULL)) {
zend_throw_error(NULL, "Typed property %s::$%s must not be accessed before initialization (in __sleep)", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
return 1;
}
#endif
goto serialize_untyped_uninitialized_prop;
}
} else {
if (UNEXPECTED(Z_TYPE_P(v) == IS_UNDEF)) {
serialize_untyped_uninitialized_prop:
php_error_docref(NULL, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(prop_name));
return igbinary_serialize_null(igsd);
}
}
return igbinary_serialize_zval(igsd, v);
}
/* }}} */
/* {{{ igbinary_serialize_array_sleep_inner */
/** Serializes object's properties array with __sleep -function. */
inline static int igbinary_serialize_array_sleep_inner(struct igbinary_serialize_data *igsd, zval *z, HashTable *h, HashTable *object_properties, zend_class_entry *ce) {
zval *d;
zval *v;
ZEND_HASH_FOREACH_VAL(h, d) {
if (UNEXPECTED(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 */
/* TODO: Allow creating a tmp string, like php's serialize() */
RETURN_1_IF_NON_ZERO(igbinary_serialize_null(igsd));
continue;
}
zend_string *prop_name = Z_STR_P(d);
if ((v = zend_hash_find(object_properties, prop_name)) != NULL) {
RETURN_1_IF_NON_ZERO(igbinary_serialize_string(igsd, prop_name));
RETURN_1_IF_NON_ZERO(igbinary_serialize_array_sleep_single_prop_value(igsd, z, v, ce, prop_name));
} else {
zend_string *mangled_prop_name;
v = NULL;
int res;
/* try private */
mangled_prop_name = zend_mangle_property_name(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), 0);
v = zend_hash_find(object_properties, mangled_prop_name);
/* try protected */
if (v == NULL) {
zend_string_efree(mangled_prop_name);
mangled_prop_name = zend_mangle_property_name("*", 1,
ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), 0);
v = zend_hash_find(object_properties, mangled_prop_name);
/* Neither protected nor private property exists */
if (v == NULL) {
zend_string_efree(mangled_prop_name);
php_error_docref(NULL, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(prop_name));
RETURN_1_IF_NON_ZERO(igbinary_serialize_string(igsd, prop_name));
RETURN_1_IF_NON_ZERO(igbinary_serialize_null(igsd));
continue;
}
}
res = igbinary_serialize_string(igsd, mangled_prop_name);
/* igbinary_serialize_string will increase the reference count. */
zend_string_release_ex(mangled_prop_name, 0);
RETURN_1_IF_NON_ZERO(res);
RETURN_1_IF_NON_ZERO(igbinary_serialize_array_sleep_single_prop_value(igsd, z, v, ce, prop_name));
}
} ZEND_HASH_FOREACH_END();
return 0;
}
/* }}} */
/* {{{ 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) {
HashTable *object_properties;
uint32_t n = zend_hash_num_elements(h);
/* Serialize array id. */
if (n <= 0xff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd, igbinary_type_array8, (uint8_t)n))
if (n == 0) {
return 0;
}
} else if (n <= 0xffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd, igbinary_type_array16, (uint16_t)n))
} else {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd, igbinary_type_array32, n))
}
object_properties = zend_get_properties_for(z, ZEND_PROP_PURPOSE_SERIALIZE);
int r = igbinary_serialize_array_sleep_inner(igsd, z, h, object_properties, ce);
zend_release_properties(object_properties);
return r;
}
/* }}} */
/* {{{ igbinary_serialize_object_name */
/**
* Serialize a PHP object's class name.
* Note that this deliberately ignores the compact_strings setting.
*/
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 (UNEXPECTED(igsd->string_count == 0)) {
zend_error(E_WARNING, "igbinary_serialize: Saw too many strings");
return 1;
}
if (name_len <= 0xff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd, igbinary_type_object8, (uint8_t)name_len))
} else if (EXPECTED(name_len <= 0xffff)) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd, igbinary_type_object16, (uint16_t)name_len))
} else {
#if SIZEOF_SIZE_T > 4
if (UNEXPECTED(name_len > 0xffffffff)) {
zend_error(E_WARNING, "igbinary_serialize_object_name: class name does not fit in 32 bits");
return 1;
}
#endif
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd, igbinary_type_object32, (uint32_t)name_len))
}
RETURN_1_IF_NON_ZERO(igbinary_serialize_resize(igsd, name_len));
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) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_8(igsd, (uint8_t)igbinary_type_object_id8, (uint8_t)value))
} else if (value <= 0xffff) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_16(igsd, (uint8_t)igbinary_type_object_id16, (uint16_t)value))
} else {
RETURN_1_IF_NON_ZERO(igbinary_serialize8_and_32(igsd, (uint8_t)igbinary_type_object_id32, (uint32_t)value))
}
} else {
return 1; /* Failed to allocate copy of string */
}
return 0;
}
/* }}} */
/* igbinary_serialize_object_old_serializer_class {{{ */
static ZEND_COLD int igbinary_serialize_object_old_serializer_class(struct igbinary_serialize_data* igsd, zval *z, zend_class_entry *ce) {
unsigned char *serialized_data = NULL;
size_t serialized_len;
int r = 0;
if (ce->serialize(z, &serialized_data, &serialized_len, (zend_serialize_data *)NULL) == SUCCESS && !EG(exception)) {
if (UNEXPECTED(igbinary_serialize_object_name(igsd, ce->name) != 0)) {
goto failure;
}
if (serialized_len <= 0xff) {
if (UNEXPECTED(igbinary_serialize8_and_8(igsd, igbinary_type_object_ser8, (uint8_t)serialized_len) != 0)) {
goto failure;
}
} else if (serialized_len <= 0xffff) {
if (UNEXPECTED(igbinary_serialize8_and_16(igsd, (uint8_t)igbinary_type_object_ser16, (uint16_t)serialized_len) != 0)) {
goto failure;
}
} else {
#if SIZEOF_ZEND_LONG > 4
if (UNEXPECTED(serialized_len > 0xffffffff)) {
zend_error(E_WARNING, "igbinary_serialize_object_old_serializer_class: serialize() data 4GB or larger is not supported");
goto failure;
}
#endif
if (UNEXPECTED(igbinary_serialize8_and_32(igsd, (uint8_t)igbinary_type_object_ser32, (uint32_t)serialized_len) != 0)) {
goto failure;
}
}
if (UNEXPECTED(igbinary_serialize_resize(igsd, serialized_len))) {
goto failure;
}
memcpy(igsd->buffer + igsd->buffer_size, serialized_data, serialized_len);
igsd->buffer_size += serialized_len;
} else if (EG(exception)) {
/* exception, return failure */
failure:
r = 1;
} else {
/* Serialization callback failed, assume null output */
r = igbinary_serialize_null(igsd);
}
if (serialized_data) {
efree(serialized_data);
}
return r;
}
/* }}} */
/* igbinary_var_serialize_call_magic_serialize {{{ */
// Source: ext/standard/var.c from php-src
#if PHP_VERSION_ID >= 70400
inline static int igbinary_var_serialize_call_magic_serialize(zval *retval, zval *obj)
{
#if PHP_VERSION_ID >= 80000
BG(serialize_lock)++;
zend_call_known_instance_method_with_0_params(
Z_OBJCE_P(obj)->__serialize, Z_OBJ_P(obj), retval);
BG(serialize_lock)--;
if (EG(exception)) {
zval_ptr_dtor(retval);
return 1;
}
#else
zval fname;
int res;
ZVAL_STRINGL(&fname, "__serialize", sizeof("__serialize") - 1);
// XXX does this work with the standard serializer?
BG(serialize_lock)++;
res = call_user_function(CG(function_table), obj, &fname, retval, 0, 0);
BG(serialize_lock)--;
zval_ptr_dtor_str(&fname);
if (res == FAILURE || Z_ISUNDEF_P(retval)) {
zval_ptr_dtor(retval);
return 1;
}
#endif
if (Z_TYPE_P(retval) != IS_ARRAY) {
zval_ptr_dtor(retval);
zend_type_error("%s::__serialize() must return an array", ZSTR_VAL(Z_OBJCE_P(obj)->name));
return 1;
}
return 0;
}
#endif
/* }}} */
/* igbinary_serialize_object_new_serializer {{{ */
#if PHP_VERSION_ID >= 70400
inline static int igbinary_serialize_object_new_serializer(struct igbinary_serialize_data* igsd, zval *z, zend_class_entry *ce) {
zval retval;
int r = 0;
// Call retval = __serialize(z), which returns an array or fails.
if (igbinary_var_serialize_call_magic_serialize(&retval, z)) {
// retval is already freed
if (!EG(exception)) {
// When does this happen?
igbinary_serialize_null(igsd);
return 0;
}
return 1;
}
// fprintf(stderr, "Serialize returned a value of type %d\n", Z_TYPE(retval));
if (UNEXPECTED(igbinary_serialize_object_name(igsd, ce->name) != 0)) {
zval_ptr_dtor(&retval);
return 1;
}
// This serializes an object name followed by an array, in the same format used when no serializers exist.
// object is false because this is the array returned by __serialize() for the object.
// TODO: Add tests that this works properly when the same array is reused.
r = igbinary_serialize_array(igsd, &retval, false, false, false);
zval_ptr_dtor(&retval);
if (UNEXPECTED(r)) {
return 1;
}
return EG(exception) != NULL;
}
#endif
/* }}} */
/* {{{ igbinary_serialize_object_enum_case */
#if PHP_VERSION_ID >= 80100
inline static int igbinary_serialize_object_enum_case(struct igbinary_serialize_data *igsd, zend_object *obj, zend_class_entry *ce) {
if (UNEXPECTED(igbinary_serialize_object_name(igsd, ce->name) != 0)) {
return 1;
}
if (UNEXPECTED(igbinary_serialize8(igsd, (uint8_t)igbinary_type_enum_case))) {
return 1;
}
zval *case_name = zend_enum_fetch_case_name(obj);
ZEND_ASSERT(Z_TYPE_P(case_name) == IS_STRING);
return igbinary_serialize_string(igsd, Z_STR_P(case_name));
}
#endif
/* }}} */
/* {{{ 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;
int r = 0;
int ref_ser = igbinary_serialize_array_ref(igsd, z, true);
if (ref_ser != 2) {
return ref_ser;
}
ce = Z_OBJCE_P(z);
if (IGBINARY_IS_NOT_SERIALIZABLE(ce)) {
zend_throw_exception_ex(NULL, 0, "Serialization of '%s' is not allowed", ZSTR_VAL(ce->name));
return 1;
}
#if PHP_VERSION_ID >= 80100
if (ce->ce_flags & ZEND_ACC_ENUM) {
return igbinary_serialize_object_enum_case(igsd, Z_OBJ_P(z), ce);
}
#endif
#if PHP_VERSION_ID >= 70400
#if PHP_VERSION_ID >= 80000
if (ce->__serialize)
#else
if (zend_hash_str_exists(&ce->function_table, "__serialize", sizeof("__serialize")-1))
#endif
{
// fprintf(stderr, "Going to serialize %s\n", ZSTR_VAL(ce->name));
return igbinary_serialize_object_new_serializer(igsd, z, ce);
}
#endif
if (ce->serialize != NULL) {
return igbinary_serialize_object_old_serializer_class(igsd, z, ce);
}
/* 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)) {
zval h;
zval f;
/* function name string */
/* TODO use ZSTR_KNOWN(ZEND_STR_SLEEP) instead when available*/
/* zval *zv = zend_hash_find_known_hash(&ce->function_table, ZSTR_KNOWN(ZEND_STR_SLEEP)); */
ZVAL_STRINGL(&f, "__sleep", sizeof("__sleep") - 1);
/* calling z->__sleep */
r = call_user_function(CG(function_table), z, &f, &h, 0, 0);
zval_ptr_dtor_str(&f);
if (r == SUCCESS && !EG(exception)) {
HashTable *ht;
r = 0;
if (Z_TYPE(h) == IS_UNDEF) {
/* FIXME: is this ok? */
/* Valid, but skip */
} else if ((ht = HASH_OF(&h)) != NULL) {
/* NOTE: PHP permits returning an object in __sleep */
r = igbinary_serialize_array_sleep(igsd, z, ht, ce);
} 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_and_8(igsd, igbinary_type_array8, 0);
}
} else {
r = 1;
}
/* cleanup */
zval_ptr_dtor(&h);
return r;
}
return igbinary_serialize_array(igsd, z, true, incomplete_class, false);
}
/* }}} */
/* {{{ igbinary_warn_serialize_resource */
static ZEND_COLD int igbinary_warn_serialize_resource(zval *z) {
const char *resource_type;
resource_type = zend_rsrc_list_get_rsrc_type(Z_RES_P(z));
if (!resource_type) {
resource_type = "Unknown";
}
php_error_docref(NULL, E_DEPRECATED, "Cannot serialize resource(%s) and resources may be converted to objects that cannot be serialized in future php releases. Serializing the value as null instead", resource_type);
return EG(exception) != NULL;
}
/* }}} */
/* {{{ igbinary_serialize_zval */
/** Serialize zval. */
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z) {
if (Z_ISREF_P(z)) {
if (Z_REFCOUNT_P(z) >= 2) {
RETURN_1_IF_NON_ZERO(igbinary_serialize8(igsd, (uint8_t)igbinary_type_ref))
switch (Z_TYPE_P(Z_REFVAL_P(z))) {
case IS_ARRAY:
return igbinary_serialize_array(igsd, z, false, false, true);
case IS_OBJECT:
break; /* Fall through */
default:
{
/* Serialize a reference if zval already added */
int ref_ser = igbinary_serialize_array_ref(igsd, z, false);
if (ref_ser != 2) {
return ref_ser;
}
/* Fall through */
}
}
}
z = Z_REFVAL_P(z);
}
switch (Z_TYPE_P(z)) {
case IS_RESOURCE:
if (igbinary_warn_serialize_resource(z)) {
return 1;
}
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, true);
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_UNDEF:
// https://github.com/igbinary/igbinary/issues/134
// TODO: In a new major version, could have a separate type for IS_UNDEF, which would unset the property in an object context?
// fallthrough
case IS_NULL:
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));
return 1;
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_data_init */
/** Inits igbinary_unserialize_data. */
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd) {
struct igbinary_value_ref *references = emalloc(sizeof(igsd->references[0]) * 4);
zend_string **strings;
if (UNEXPECTED(references == NULL)) {
return 1;
}
strings = (zend_string **)emalloc(sizeof(zend_string *) * 4);
if (UNEXPECTED(strings == NULL)) {
/* We failed to allocate memory for strings. Fail and free everything we allocated */
efree(references);
return 1;
}
igsd->buffer = NULL;
igsd->buffer_end = NULL;
igsd->buffer_ptr = NULL;
igsd->strings = NULL;
igsd->strings_count = 0;
igsd->strings_capacity = 4;
igsd->references = references;
igsd->references_count = 0;
igsd->references_capacity = 4;
igsd->strings = strings;
/** Don't bother allocating zvals which __wakeup or __unserialize, probably not common */
igsd->deferred = NULL;
igsd->deferred_count = 0;
igsd->deferred_capacity = 0;
igsd->deferred_finished = 0;
igsd->deferred_dtor_tracker.zvals = NULL;
igsd->deferred_dtor_tracker.count = 0;
igsd->deferred_dtor_tracker.capacity = 0;
#if PHP_VERSION_ID >= 70400
igsd->ref_props = NULL;
#endif
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_data_deinit */
/** Deinits igbinary_unserialize_data. */
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd) {
if (igsd->strings) {
size_t i;
size_t strings_count = igsd->strings_count;
zend_string **strings = igsd->strings;
for (i = 0; i < strings_count; i++) {
zend_string *s = strings[i];
#if ZEND_DEBUG
ZEND_ASSERT(GC_REFCOUNT(s) >= 1);
#endif
zend_string_release_ex(s, 0); /* Should only create interned or non-persistent strings when unserializing */
}
efree(strings);
}
if (igsd->references) {
efree(igsd->references);
}
if (igsd->deferred) {
struct deferred_call *calls = igsd->deferred;
#if PHP_VERSION_ID >= 70400
uint32_t i;
uint32_t n = igsd->deferred_count;
for (i = 0; i < n; i++) {
struct deferred_call *call = &calls[i];
if (call->is_unserialize) {
if (!igsd->deferred_finished) {
struct deferred_unserialize_call *unserialize_call = &call->data.unserialize;
GC_ADD_FLAGS(unserialize_call->object, IS_OBJ_DESTRUCTOR_CALLED);
zval_ptr_dtor(&unserialize_call->param);
}
}
}
#endif
efree(calls);
}
free_deferred_dtors(&igsd->deferred_dtor_tracker);
#if PHP_VERSION_ID >= 70400
if (igsd->ref_props) {
zend_hash_destroy(igsd->ref_props);
FREE_HASHTABLE(igsd->ref_props);
}
#endif
return;
}
/* }}} */
/* {{{ igbinary_unserialize_header_emit_warning */
/**
* Warns about invalid byte headers
* Precondition: igsd->buffer_size >= 4 */
static ZEND_COLD 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;
}
}
/* To avoid confusion, if the first 4 bytes are all printable, print those instead of the integer representation to make debugging easier. */
/* E.g. strings such as "a:2:" are emitted when an Array is serialized with serialize() instead of igbinary_serialize(), */
/* and subsequently passed to igbinary_unserialize instead of unserialize(). */
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 (EXPECTED(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 (perform only one comparison in common case) */
tmp32 = igbinary_unserialize32(igsd);
#if SIZEOF_ZEND_LONG == 4
if (UNEXPECTED(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 {
ZEND_ASSERT(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 (perform only one comparison in common case) */
tmp64 = igbinary_unserialize64(igsd);
if (UNEXPECTED(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
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_double */
/** Unserializes double. */
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, double *ret) {
union {
double d;
uint64_t u;
} u;
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, (size_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 (currently not using any interned strings) - Callers of this will decrease refs as needed
#if PHP_VERSION_ID >= 80100
zend_string_addref(zstr);
#else
ZEND_ASSERT(!ZSTR_IS_INTERNED(zstr));
GC_ADDREF(zstr);
#endif
return zstr;
}
/* }}} */
/* igbinary_unserialize_extremely_long_chararray {{{ */
static ZEND_COLD zend_never_inline zend_string* igbinary_unserialize_extremely_long_chararray(struct igbinary_unserialize_data *igsd) {
#if SIZEOF_SIZE_T <= 4
(void)igsd;
zend_error(E_WARNING, "igbinary_unserialize_chararray: cannot unserialize 64-bit data on 32-bit platform");
return NULL;
#else
if (IGB_NEEDS_MORE_DATA(igsd, 8)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
return NULL;
}
size_t l = igbinary_unserialize64(igsd);
if (IGB_NEEDS_MORE_DATA(igsd, l)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
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;
}
zend_string *zstr = zend_string_init((const char*)igsd->buffer_ptr, l, 0);
igsd->buffer_ptr += l;
GC_ADDREF(zstr); /* definitely not interned. Add a reference in case the first reference gets deleted before reusing the temporary string */
igsd->strings[igsd->strings_count] = zstr;
igsd->strings_count += 1;
return zstr;
#endif
}
/* }}} */
/* {{{ 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, zend_bool check_interned) {
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);
/* 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);
} else if (EXPECTED(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);
} else if (t == igbinary_type_string64) {
return igbinary_unserialize_extremely_long_chararray(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_chararray: unknown type '%02x', position %zu", t, (size_t)IGB_BUFFER_OFFSET(igsd));
return NULL;
}
if (IGB_NEEDS_MORE_DATA(igsd, l)) {
zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
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;
}
#if PHP_VERSION_ID >= 80100
if (check_interned && l < 100) {
/*
* Reuse interned strings if possible for the following reasons:
* 1. Save memory (e.g. for strings in property default values of classes, for arrays repeating string field names, etc.)
* 2. Speed up checking if strings are identical.
* 3. Speed up the code that ends up using the return value of igbinary_unserialize().
*
* Note that this change has mixed results. unserialize-object-array and unserialize-stdclass have performance improve because all strings are already interned,
* but unserialize-stringarray on unstructured text has worse performance.
*/
zstr = zend_string_init_existing_interned((const char*)igsd->buffer_ptr, l, 0);
zend_string_addref(zstr);
} else
#endif
{
zstr = zend_string_init((const char*)igsd->buffer_ptr, l, 0);
GC_ADDREF(zstr); /* definitely not interned. Add a reference in case the first reference gets deleted before reusing the temporary string */
}
igsd->buffer_ptr += l;
igsd->strings[igsd->strings_count] = zstr;
igsd->strings_count += 1;
return zstr;
}
/* }}} */
/* {{{ igbinary_unserialize_array */
/** Unserializes a PHP array. */
zend_always_inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, int flags, zend_bool create_ref) {
/* WANT_REF means that z will be wrapped by an IS_REFERENCE */
uint32_t n;
uint32_t i;
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);
if (n == 0) {
if (create_ref) {
/* NOTE: igbinary uses ZVAL_ARR() when reading the created reference, which assumes that the original array is refcounted. */
/* This would have to be fixed to switch to ZVAL_EMPTY_ARRAY for the empty array (there's probably not benefit to making that switch). */
/* Otherwise, using ZVAL_EMPTY_ARRAY would segfault. */
#if PHP_VERSION_ID >= 70300
ZVAL_EMPTY_ARRAY(z);
#else
array_init_size(z, 0);
#endif
struct igbinary_value_ref ref;
if (flags & WANT_REF) {
ZVAL_NEW_REF(z, z);
ref.reference.reference = Z_REF_P(z);
ref.type = IG_REF_IS_REFERENCE;
} else {
#if PHP_VERSION_ID >= 70300
ref.type = IG_REF_IS_EMPTY_ARRAY;
#else
ref.reference.array = Z_ARR_P(z);
ref.type = IG_REF_IS_ARRAY;
#endif
}
/* add the new array to the list of unserialized references */
RETURN_1_IF_NON_ZERO(igsd_append_ref(igsd, ref) == SIZE_MAX);
} else {
/* This only matters if __unserialize() would get called with an empty array */
#if PHP_VERSION_ID >= 70300
ZVAL_EMPTY_ARRAY(z);
#else
array_init_size(z, 0);
#endif
}
return 0;
}
} 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, (size_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.", (size_t)IGB_REMAINING_BYTES(igsd), (size_t)n);
return 1;
}
zval *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);
h = Z_ARRVAL_P(z_deref);
#if PHP_VERSION_ID >= 70200
/* The array may contain references to itself, in which case we'll be modifying an
* rc>1 array. This is okay, since the array is, ostensibly, only visible to
* unserialize (in practice unserialization handlers also see it). */
HT_ALLOW_COW_VIOLATION(h);
#endif
if (create_ref) {
/* Only create a reference if this is not from __unserialize(), because the existence of __unserialize can change */
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 */
RETURN_1_IF_NON_ZERO(igsd_append_ref(igsd, ref) == SIZE_MAX);
}
for (i = 0; i < n; i++) {
zval *vp;
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");
cleanup:
zval_dtor(z);
ZVAL_NULL(z);
return 1;
}
key_type = (enum igbinary_type)igbinary_unserialize8(igsd);
switch (key_type) {
case igbinary_type_long8p:
/* Manually inline igbinary_unserialize_long() for array keys from 0 to 255, because they're the most common among integers. */
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
goto cleanup;
}
key_index = igbinary_unserialize8(igsd);
break;
case igbinary_type_long16p:
/* and for array keys from 0 to 65535. */
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
goto cleanup;
}
key_index = igbinary_unserialize16(igsd);
break;
case igbinary_type_long8n:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
if (UNEXPECTED(igbinary_unserialize_long(igsd, key_type, &key_index))) {
goto cleanup;
}
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)) {
goto cleanup;
}
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
case igbinary_type_string64:
key_str = igbinary_unserialize_chararray(igsd, key_type, 1);
if (UNEXPECTED(key_str == NULL)) {
goto cleanup;
}
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, (size_t)IGB_BUFFER_OFFSET(igsd));
goto cleanup;
}
/* 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 */
if (key_str != NULL) {
vp = igbinary_zend_hash_add_or_find(h, key_str);
/* If there was an old value instead of an inserted IS_NULL zval (unlikely) and that old value was refcounted, then add a reference and defer freeing that reference */
if (UNEXPECTED(igsd_addref_and_defer_dtor(&igsd->deferred_dtor_tracker, vp))) {
return 1;
}
zend_string_release(key_str);
} else {
/* If there was an old value instead of an inserted IS_NULL zval (unlikely) and that old value was refcounted, then add a reference and defer freeing that reference */
vp = igbinary_zend_hash_index_add_or_find(h, key_index);
if (UNEXPECTED(igsd_addref_and_defer_dtor(&igsd->deferred_dtor_tracker, vp))) {
return 1;
}
}
ZEND_ASSERT(vp != NULL);
if (Z_TYPE_P(vp) == IS_INDIRECT) {
/* TODO: In php 8.1+, IS_INDIRECT checks and macros may become unnecessary
* due to $GLOBALS being converted to a regular array in https://wiki.php.net/rfc/restrict_globals_usage */
vp = Z_INDIRECT_P(vp);
}
ZEND_ASSERT(vp != NULL);
if (UNEXPECTED(igbinary_unserialize_zval(igsd, vp, WANT_CLEAR))) {
return 1;
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object_properties */
/** Unserializes the array of object properties and adds those to the object z. */
inline static int igbinary_unserialize_object_properties(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *const z, const zend_class_entry *ce) {
/* WANT_REF means that z will be wrapped by an IS_REFERENCE */
uint32_t n;
zval v;
zval *z_deref;
HashTable *h;
zend_bool did_extend;
if (t == igbinary_type_array8) {
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_object_properties: 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_object_properties: 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_object_properties: end-of-data");
return 1;
}
n = igbinary_unserialize32(igsd);
} else {
zend_error(E_WARNING, "igbinary_unserialize_object_properties: unknown type '%02x', position %zu", t, (size_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_object_properties", (size_t)IGB_REMAINING_BYTES(igsd), (size_t)n);
return 1;
}
z_deref = z;
ZVAL_DEREF(z_deref);
/* empty array */
if (n == 0) {
return 0;
}
h = HASH_OF_OBJECT(z_deref);
did_extend = 0;
do {
n--;
zval *vp;
enum igbinary_type key_type;
zend_string *key_str = NULL; /* NULL means use key_index */
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_object_properties: 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 (UNEXPECTED(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:
case igbinary_type_string64:
key_str = igbinary_unserialize_chararray(igsd, key_type, 1);
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_object_properties: unknown key type '%02x', position %zu", key_type, (size_t)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 PHP_VERSION_ID >= 70400
zend_property_info *info = NULL;
#endif
if (prototype_value != NULL) {
if (Z_TYPE_P(prototype_value) == IS_INDIRECT) {
/* This is a declared object property */
prototype_value = Z_INDIRECT_P(prototype_value);
#if PHP_VERSION_ID >= 70400
info = zend_get_typed_property_info_for_slot(Z_OBJ_P(z_deref), prototype_value);
if (info) {
if (Z_ISREF_P(prototype_value)) {
/* If the value is overwritten, remove old type source from ref. */
ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(prototype_value), info);
}
if (igsd->ref_props) {
/* Remove old entry from ref_props table, if it exists. */
zend_hash_index_del(
igsd->ref_props, ((uintptr_t) prototype_value) >> ZEND_MM_ALIGNMENT_LOG2);
}
}
#endif
}
/* This is written to avoid the overhead of a second zend_hash_update call. See https://github.com/php/php-src/pull/5095 */
/* Use igsd_addref_and_defer_dtor instead (like php-src), in case of gc causing issues. */
/* Something already added a reference, so just defer the destructor */
if (UNEXPECTED(igsd_defer_dtor(&igsd->deferred_dtor_tracker, prototype_value))) {
zend_string_release(key_str);
return 1;
}
/* Just override the original value directly */
ZVAL_COPY_VALUE(prototype_value, &v);
vp = prototype_value;
} else {
#if PHP_VERSION_ID >= 80000
/* ZEND_ACC_NO_DYNAMIC_PROPERTIES was introduced in php 8.0 but was largely used with zend_class_unserialize_deny, though external pecls might set this flag. */
if (UNEXPECTED(ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
zend_throw_error(NULL, "Cannot create dynamic property %s::$%s in igbinary_unserialize",
ZSTR_VAL(ce->name), zend_get_unmangled_property_name(key_str));
zend_string_release(key_str);
return 1;
}
#endif
#if PHP_VERSION_ID >= 80200
/* PHP 8.2 deprecated the creation of dynamic properties by default without `#[AllowDynamicProperties]`. */
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES))) {
php_error_docref(NULL, E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
ZSTR_VAL(ce->name), zend_get_unmangled_property_name(key_str));
if (UNEXPECTED(EG(exception))) {
zend_string_release(key_str);
return 1;
}
}
#endif
if (!did_extend) {
/* remaining_elements is at least one, because we're looping from n-1..0 */
uint32_t remaining_elements = n + 1;
/* 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);
/* Should only be indirect for typed properties? */
ZEND_ASSERT(Z_TYPE_P(vp) != IS_INDIRECT);
if (UNEXPECTED(igbinary_unserialize_zval(igsd, vp, WANT_CLEAR))) {
#if PHP_VERSION_ID >= 70400
if (info && Z_ISREF_P(vp)) {
/* Add type source even if we failed to unserialize.
* The data is still stored in the property. */
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(vp), info);
}
#endif
/* Unserializing a property into this zval has failed. */
/* zval_ptr_dtor(z); */
/* zval_ptr_dtor(vp); */
return 1;
}
#if PHP_VERSION_ID >= 70400
if (UNEXPECTED(info)) {
if (!zend_verify_prop_assignable_by_ref(info, vp, /* strict */ 1)) {
zval_ptr_dtor(vp);
ZVAL_UNDEF(vp);
return 1;
}
if (Z_ISREF_P(vp)) {
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(vp), info);
} else {
/* Remember to which property this slot belongs, so we can add a
* type source if it is turned into a reference lateron. */
if (!igsd->ref_props) {
igsd->ref_props = emalloc(sizeof(HashTable));
zend_hash_init(igsd->ref_props, 8, NULL, NULL, 0);
}
zend_hash_index_update_ptr(
igsd->ref_props, ((uintptr_t) vp) >> ZEND_MM_ALIGNMENT_LOG2, info);
}
}
#endif
} while (n > 0);
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_object_ser */
/** Unserializes object's property array. This is used to serialize objects implementing Serializable -interface. */
static ZEND_COLD 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) {
/* Should be impossible. */
zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
return 1;
}
if (IGBINARY_IS_NOT_UNSERIALIZABLE(ce)) {
zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed", ZSTR_VAL(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, (size_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_enum_case */
#if PHP_VERSION_ID >= 80100
/** Unserializes object's property array. This is used to serialize objects implementing Serializable -interface. */
static int igbinary_unserialize_object_enum_case(struct igbinary_unserialize_data *igsd, zval *const z, zend_class_entry *ce) {
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_ENUM))) {
zend_error(E_WARNING, "igbinary_unserialize_object_enum_case: Class '%s' is not an enum", ZSTR_VAL(ce->name));
return 1;
}
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_object_enum_case: end-of-data");
return 1;
}
enum igbinary_type t = (enum igbinary_type)igbinary_unserialize8(igsd);
zend_string *case_name;
switch (t) {
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
case igbinary_type_string64:
case_name = igbinary_unserialize_chararray(igsd, t, 1);
break;
default:
case_name = igbinary_unserialize_string(igsd, t);
break;
}
if (UNEXPECTED(!case_name)) {
return 1;
}
zval *zv = zend_hash_find(CE_CONSTANTS_TABLE(ce), case_name);
if (UNEXPECTED(!zv)) {
zend_error(E_WARNING, "igbinary_unserialize_object_enum_case: Undefined constant %s::%s", ZSTR_VAL(ce->name), ZSTR_VAL(case_name));
zend_string_release(case_name);
return 1;
}
zend_class_constant *c = Z_PTR_P(zv);
if (UNEXPECTED(!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE))) {
zend_error(E_WARNING, "igbinary_unserialize_object_enum_case: %s::%s is not an enum case", ZSTR_VAL(ce->name), ZSTR_VAL(case_name));
zend_string_release(case_name);
return 1;
}
zend_string_release(case_name);
zval *value = &c->value;
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
zval_update_constant_ex(value, c->ce);
if (UNEXPECTED(EG(exception) != NULL)) {
return 1;
}
}
ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT);
/* increment the reference count and copy the enum case object into the constructed value. */
ZVAL_COPY(z, value);
return 0;
}
#endif
/* }}} */
/* {{{ igbinary_unserialize_object */
/** Unserialize an object.
* @see ext/standard/var_unserializer.c in the php-src repo. Parts of this code are based on that.
*/
zend_always_inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval *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;
if (t == igbinary_type_object8 || t == igbinary_type_object16 || t == igbinary_type_object32) {
class_name = igbinary_unserialize_chararray(igsd, t, 1);
} 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, (size_t)IGB_BUFFER_OFFSET(igsd));
return 1;
}
if (class_name == NULL) {
return 1;
}
do {
zval user_func;
zval retval;
zval args[1];
const char* user_func_name;
/* Try to find class directly */
if (EXPECTED((ce = zend_lookup_class(class_name)) != NULL)) {
/* FIXME: lookup class may cause exception in load callback */
break;
}
user_func_name = PG(unserialize_callback_func);
/* Check for unserialize callback */
if ((user_func_name == NULL) || (user_func_name[0] == '\0')) {
incomplete_class = 1;
ce = PHP_IC_ENTRY;
break;
}
/* Call unserialize callback */
ZVAL_STRING(&user_func, user_func_name);
ZVAL_STR(&args[0], class_name);
if (call_user_function(CG(function_table), NULL, &user_func, &retval, 1, args) != SUCCESS) {
php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func));
incomplete_class = 1;
ce = PHP_IC_ENTRY;
zval_ptr_dtor_nogc(&user_func);
break;
}
/* FIXME: always safe? */
zval_ptr_dtor(&retval);
zval_ptr_dtor_str(&user_func);
/* User function call may have raised an exception */
if (EG(exception)) {
zend_string_release_ex(class_name, 0);
return 1;
}
/* 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", PG(unserialize_callback_func));
incomplete_class = true;
ce = PHP_IC_ENTRY;
}
} while (0);
if (IGBINARY_IS_NOT_UNSERIALIZABLE(ce)) {
zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed", ZSTR_VAL(ce->name));
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;
}
{
/* The actual value of ref is unused. We use ref_n later in this function, after creating the object. */
struct igbinary_value_ref ref = {{0}, 0};
ref_n = igsd_append_ref(igsd, ref);
if (UNEXPECTED(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 (UNEXPECTED(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) {
#if PHP_VERSION_ID >= 80000
php_store_class_name(z, class_name);
#else
php_store_class_name(z, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
#endif
#if PHP_VERSION_ID >= 70400
} else {
#if PHP_VERSION_ID >= 80000
if (ce->__unserialize)
#else
if (zend_hash_str_exists(&ce->function_table, "__unserialize", sizeof("__unserialize") - 1))
#endif
{
ZEND_ASSERT(Z_TYPE_P(z) == IS_OBJECT);
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;
}
/* Unserialize the array as an array for a deferred call to __unserialize */
zval param;
int result;
zend_string_release(class_name);
result = igbinary_unserialize_array(igsd, t, ¶m, 0, false);
ZVAL_DEREF(z);
ZEND_ASSERT(Z_TYPE_P(z) == IS_OBJECT);
igsd_defer_unserialize(igsd, Z_OBJ_P(z), param);
return result;
}
#endif
}
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, ce);
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) {
#if PHP_VERSION_ID >= 80000
php_store_class_name(z, class_name);
#else
php_store_class_name(z, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
#endif
}
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;
}
case igbinary_type_enum_case:
#if PHP_VERSION_ID >= 80100
if (UNEXPECTED(incomplete_class)) {
zend_error(E_WARNING, "igbinary_unserialize_object_enum_case: Class '%s' does not exist", ZSTR_VAL(class_name));
zend_string_release(class_name);
return 1;
}
zend_string_release(class_name);
r = igbinary_unserialize_object_enum_case(igsd, z, ce);
if (r) {
return r;
}
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;
}
return 0;
#else
zend_error(E_WARNING, "igbinary_unserialize_object: Cannot unserialize enum cases prior to php 8.1 at position %zu", (size_t)IGB_BUFFER_OFFSET(igsd));
r = 1;
#endif
break;
default:
zend_error(E_WARNING, "igbinary_unserialize_object: unknown object inner type '%02x', position %zu", t, (size_t)IGB_BUFFER_OFFSET(igsd));
r = 1;
}
zend_string_release(class_name);
class_name = NULL;
/* If unserialize was successful, defer the call to __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);
zend_object *object;
if (ref->type == IG_REF_IS_OBJECT) {
object = ref->reference.object;
} else if (EXPECTED(ref->type == IG_REF_IS_REFERENCE)) {
/* May have created a reference while deserializing an object, if it was recursive. */
zval ztemp = ref->reference.reference->val;
if (UNEXPECTED(Z_TYPE(ztemp) != IS_OBJECT)) {
zend_error(E_WARNING, "igbinary_unserialize_object preparing to __wakeup/__unserialize: got reference to non-object somehow (inner type '%02x', position %zu)", t, (size_t)IGB_BUFFER_OFFSET(igsd));
return 1;
}
object = Z_OBJ(ztemp);
} else {
zend_error(E_WARNING, "igbinary_unserialize_object preparing to __wakeup/__unserialize: created non-object somehow (inner type '%02x', position %zu)", t, (size_t)IGB_BUFFER_OFFSET(igsd));
return 1;
}
if (object->ce != PHP_IC_ENTRY) {
if (zend_hash_str_exists(&object->ce->function_table, "__wakeup", sizeof("__wakeup") - 1)) {
if (UNEXPECTED(igsd_defer_wakeup(igsd, object))) {
return 1;
}
}
}
}
return r;
}
/* }}} */
/* {{{ igbinary_unserialize_ref */
/** Unserializes an array or object by reference. */
zend_always_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, (size_t)IGB_BUFFER_OFFSET(igsd));
return 1;
}
if (n >= igsd->references_count) {
zend_error(E_WARNING, "igbinary_unserialize_ref: invalid reference %zu >= %zu", (size_t)n, (size_t)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_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);
/* All arrays built by igbinary when unserializing are refcounted, except IG_REF_IS_EMPTY_ARRAY. */
/* If they were not refcounted, the ZVAL_ARR call would probably also need to be changed. */
Z_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;
#if PHP_VERSION_ID >= 70300
case IG_REF_IS_EMPTY_ARRAY:
ZVAL_EMPTY_ARRAY(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;
#endif
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_ADDREF_P(z);
break;
case IG_REF_IS_ARRAY:
ZVAL_ARR(z, ref.reference.array);
Z_ADDREF_P(z);
break;
#if PHP_VERSION_ID >= 70300
case IG_REF_IS_EMPTY_ARRAY:
ZVAL_EMPTY_ARRAY(z);
break;
#endif
case IG_REF_IS_REFERENCE:
ZVAL_COPY(z, &(ref.reference.reference->val));
break;
}
}
return 0;
}
/* }}} */
/* {{{ igbinary_unserialize_zval */
/** Unserialize a zval of any serializable type (zval is PHP's internal representation of a value). */
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 (UNEXPECTED(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:" */
if (!Z_ISREF_P(z)) {
#if PHP_VERSION_ID >= 70400
zend_property_info *info = NULL;
if (igsd->ref_props) {
info = zend_hash_index_find_ptr(igsd->ref_props, ((uintptr_t) z) >> ZEND_MM_ALIGNMENT_LOG2);
}
#endif
ZVAL_NEW_REF(z, z);
#if PHP_VERSION_ID >= 70400
if (info) {
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(z), info);
}
#endif
}
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. */
RETURN_1_IF_NON_ZERO(igsd_append_ref(igsd, ref) == SIZE_MAX);
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 (UNEXPECTED(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 (UNEXPECTED(igbinary_unserialize_object(igsd, t, z, flags))) {
return 1;
}
break;
case igbinary_type_array8:
case igbinary_type_array16:
case igbinary_type_array32:
if (UNEXPECTED(igbinary_unserialize_array(igsd, t, z, flags, true))) {
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 (UNEXPECTED(tmp_str == NULL)) {
return 1;
}
ZVAL_STR(z, tmp_str);
break;
case igbinary_type_string8:
case igbinary_type_string16:
case igbinary_type_string32:
case igbinary_type_string64:
tmp_str = igbinary_unserialize_chararray(igsd, t, 0);
if (UNEXPECTED(tmp_str == NULL)) {
return 1;
}
ZVAL_STR(z, tmp_str);
break;
case igbinary_type_long8p:
/* Manually inline igbinary_unserialize_long() for values from 0 to 255, because they're the most common among integers in many applications. */
if (IGB_NEEDS_MORE_DATA(igsd, 1)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
ZVAL_LONG(z, igbinary_unserialize8(igsd));
break;
case igbinary_type_long16p:
/* Manually inline igbinary_unserialize_long() for values from 0 to 255, because they're the most common among integers in many applications. */
if (IGB_NEEDS_MORE_DATA(igsd, 2)) {
zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
return 1;
}
ZVAL_LONG(z, igbinary_unserialize16(igsd));
break;
case igbinary_type_long8n:
case igbinary_type_long16n:
case igbinary_type_long32p:
case igbinary_type_long32n:
case igbinary_type_long64p:
case igbinary_type_long64n:
if (UNEXPECTED(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 (UNEXPECTED(igbinary_unserialize_double(igsd, &tmp_double))) {
return 1;
}
ZVAL_DOUBLE(z, tmp_double);
break;
default:
zend_error(E_WARNING, "igbinary_unserialize_zval: unknown type '%02x', position %zu", t, (size_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-3.2.15/src/php7/igbinary.h 0000664 0001750 0001750 00000006465 14532662345 016171 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| Author: Oleg Grenrus |
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
#ifndef IGBINARY_H
#define IGBINARY_H
#include
/* Forward declarations. */
struct zval;
/* Constants and constant macros */
/** Binary protocol version of igbinary. */
#define IGBINARY_FORMAT_VERSION 0x00000002
#define PHP_IGBINARY_VERSION "3.2.15"
/* 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);
static zend_always_inline int _igbinary_has_valid_header(const uint8_t *buf, size_t buf_len) {
if (buf_len < 5) {
/* Must have 4 header bytes and at least one byte of data */
return 0;
}
/* Unserialize 32bit value the same way on big-endian and little-endian architectures.
* This compiles to a load+optional bswap when compiler optimizations are enabled. */
const uint32_t ret =
((uint32_t)(buf[0]) << 24) |
((uint32_t)(buf[1]) << 16) |
((uint32_t)(buf[2]) << 8) |
((uint32_t)(buf[3]));
return ret == 1 || ret == 2;
}
/** This is defined as a macro and a static C function
* to allow callers to use the macro from newer igbinary versions even with older igbinary installations. */
#define igbinary_has_valid_header(buf, buf_len) _igbinary_has_valid_header((buf), (buf_len))
#endif /* IGBINARY_H */
igbinary-3.2.15/src/php7/igbinary_bswap.h 0000664 0001750 0001750 00000004277 14532662345 017364 0 ustar tyson tyson #ifndef IGBINARY_BSWAP
#define IGBINARY_BSWAP
#ifdef _MSC_VER
// bswap compiler checks copied from https://github.com/google/cityhash/blob/8af9b8c2b889d80c22d6bc26ba0df1afb79a30db/src/city.cc#L50
// The original code for detecting bswap had the MIT License below.
//
// Copyright (c) 2011 Google, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include
#define bswap_32(x) _byteswap_ulong(x)
#define bswap_64(x) _byteswap_uint64(x)
#elif defined(__APPLE__)
// Mac OS X / Darwin features
#include
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)
#elif defined(__sun) || defined(sun)
#include
#define bswap_32(x) BSWAP_32(x)
#define bswap_64(x) BSWAP_64(x)
#elif defined(__FreeBSD__)
#include
#define bswap_32(x) bswap32(x)
#define bswap_64(x) bswap64(x)
#elif defined(__OpenBSD__)
#include
#define bswap_32(x) swap32(x)
#define bswap_64(x) swap64(x)
#elif defined(__NetBSD__)
#include
#include
#if defined(__BSWAP_RENAME) && !defined(__bswap_32)
#define bswap_32(x) bswap32(x)
#define bswap_64(x) bswap64(x)
#endif
#else
#include
#endif
#endif
igbinary-3.2.15/src/php7/igbinary_macros.h 0000664 0001750 0001750 00000001172 14532662345 017523 0 ustar tyson tyson /*
+----------------------------------------------------------------------+
| See COPYING file for further copyright information |
+----------------------------------------------------------------------+
| See CREDITS for contributors |
+----------------------------------------------------------------------+
*/
// If a macro is needed by *only* igbinary, put it in this file.
#ifndef PHP_IGBINARY_MACROS_H
#define PHP_IGBINARY_MACROS_H
/** Backport macros from php 7.3 */
#ifndef GC_ADD_FLAGS
#define GC_ADD_FLAGS(obj, flag) GC_FLAGS(obj) |= flag
#endif
#endif
igbinary-3.2.15/src/php7/igbinary_zend_hash.h 0000664 0001750 0001750 00000025575 14532662345 020217 0 ustar tyson tyson #ifndef IGBINARY_ZEND_HASH
#define IGBINARY_ZEND_HASH
/*
+----------------------------------------------------------------------+
| igbinary optimizations for find_or_insert adapted from Zend Engine. |
| Adaptations written by Tyson Andre for igbinary. |
| original license of php-src/Zend/zend_hash.c is below. |
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
| Dmitry Stogov |
+----------------------------------------------------------------------+
*/
/* See https://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html for an overview of PHP's hash table information */
#if PHP_VERSION_ID < 70200 || PHP_VERSION_ID >= 80100 || IGBINARY_FORCE_REFERENCE_HASH_TABLE_FUNCTIONS
/* {{{ igbinary_zend_hash_add_or_find(HashTable *ht, zend_string *key) unoptimized reference implementation. */
/* This will either return the pointer to the existing value, or add a brand new entry to the hash table with a PHP IS_NULL value. */
static zend_always_inline zval *igbinary_zend_hash_add_or_find(HashTable *ht, zend_string *key) {
zval *vp;
zval val;
if (UNEXPECTED((vp = zend_hash_find(ht, key)) != NULL)) {
return vp;
}
ZVAL_NULL(&val);
return zend_hash_add_new(ht, key, &val);
}
/* }}} */
/* {{{ igbinary_zend_hash_add_or_find(HashTable *ht, zend_long key) unoptimized reference implementation. */
/* This will either return the pointer to the existing value, or add a brand new entry to the hash table with a PHP IS_NULL value. */
static zend_always_inline zval *igbinary_zend_hash_index_add_or_find(HashTable *ht, zend_long key) {
zval *vp;
zval val;
if (UNEXPECTED((vp = zend_hash_index_find(ht, key)) != NULL)) {
return vp;
}
ZVAL_NULL(&val);
return zend_hash_index_add_new(ht, key, &val);
}
/* }}} */
/* This is either too old to bother implementing specializations for, or too new for the HashTable implementation to be finalized and tested */
#else
/* PHP 7.2 to 8.0 */
#if PHP_VERSION_ID < 70300
# define IS_ARRAY_PERSISTENT HASH_FLAG_PERSISTENT
# define zend_hash_real_init_mixed(ht) zend_hash_real_init((ht), 0)
# define zend_hash_real_init_packed(ht) zend_hash_real_init((ht), 1)
# define HT_SIZE_TO_MASK(size) (-(size))
# define HT_FLAGS(ht) ((ht)->u.flags)
static zend_always_inline zend_bool zend_string_equal_content(zend_string *s1, zend_string *s2)
{
return ZSTR_LEN(s1) == ZSTR_LEN(s2) && !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1));
}
#endif /* PHP_VERSION_ID < 70300 */
/* {{{ igbinary_zend_hash_find_bucket(const HashTable *ht, zend_string *key, zend_bool known_hash) */
static zend_always_inline Bucket *igbinary_zend_hash_find_bucket(const HashTable *ht, zend_string *key, zend_bool known_hash)
{
zend_ulong h;
uint32_t nIndex;
uint32_t idx;
Bucket *p, *arData;
if (known_hash) {
h = ZSTR_H(key);
} else {
h = zend_string_hash_val(key);
}
arData = ht->arData;
nIndex = h | ht->nTableMask;
idx = HT_HASH_EX(arData, nIndex);
if (UNEXPECTED(idx == HT_INVALID_IDX)) {
return NULL;
}
p = HT_HASH_TO_BUCKET_EX(arData, idx);
if (p->key == key) { /* check for the same interned string */
return p;
}
while (1) {
if (p->h == ZSTR_H(key) &&
EXPECTED(p->key) &&
zend_string_equal_content(p->key, key)) {
return p;
}
idx = Z_NEXT(p->val);
if (idx == HT_INVALID_IDX) {
return NULL;
}
p = HT_HASH_TO_BUCKET_EX(arData, idx);
if (p->key == key) { /* check for the same interned string */
return p;
}
}
}
/* }}} */
/* {{{ void igbinary_zend_hash_do_resize(HashTable *ht) */
static void ZEND_FASTCALL igbinary_zend_hash_do_resize(HashTable *ht)
{
// IS_CONSISTENT(ht);
// HT_ASSERT_RC1(ht);
if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */
zend_hash_rehash(ht);
} else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
uint32_t nSize = ht->nTableSize + ht->nTableSize;
Bucket *old_buckets = ht->arData;
ht->nTableSize = nSize;
#if PHP_VERSION_ID >= 70300
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
#else
new_data = pemalloc(HT_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
#endif
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
HT_SET_DATA_ADDR(ht, new_data);
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
zend_hash_rehash(ht);
} else {
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket));
}
}
/* }}} */
static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) /* {{{ */
{
// HT_ASSERT_RC1(ht);
if (ht->nTableSize >= HT_MAX_SIZE) {
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
}
ht->nTableSize += ht->nTableSize;
HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
}
/* }}} */
static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h) /* {{{ */
{
uint32_t nIndex;
uint32_t idx;
Bucket *p, *arData;
arData = ht->arData;
nIndex = h | ht->nTableMask;
idx = HT_HASH_EX(arData, nIndex);
while (idx != HT_INVALID_IDX) {
ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
p = HT_HASH_TO_BUCKET_EX(arData, idx);
if (p->h == h && !p->key) {
return p;
}
idx = Z_NEXT(p->val);
}
return NULL;
} /* }}} */
/* Methods used by igbinary.c */
/* {{{ zval *igbinary_zend_hash_add_or_find(HashTable *ht, zend_string *key) */
/* Source: zend_hash_add_or_update_i with adaptions */
static zend_always_inline zval *igbinary_zend_hash_add_or_find(HashTable *ht, zend_string *key)
{
zend_ulong h;
uint32_t nIndex;
uint32_t idx;
Bucket *p, *arData;
// IS_CONSISTENT(ht);
// HT_ASSERT_RC1(ht);
#if PHP_VERSION_ID >= 70400
if (UNEXPECTED(HT_FLAGS(ht) & (HASH_FLAG_UNINITIALIZED|HASH_FLAG_PACKED)))
#else
if (UNEXPECTED(((HT_FLAGS(ht) ^ HASH_FLAG_INITIALIZED) & (HASH_FLAG_INITIALIZED|HASH_FLAG_PACKED))))
#endif
{
#if PHP_VERSION_ID >= 70400
if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED))
#else
if (EXPECTED(!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)))
#endif
{
zend_hash_real_init_mixed(ht);
if (!ZSTR_IS_INTERNED(key)) {
zend_string_addref(key);
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
zend_string_hash_val(key);
}
goto add_to_hash;
} else {
zend_hash_packed_to_hash(ht);
if (!ZSTR_IS_INTERNED(key)) {
zend_string_addref(key);
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
zend_string_hash_val(key);
}
}
} else {
p = igbinary_zend_hash_find_bucket(ht, key, 0);
if (p) {
return &p->val;
}
if (!ZSTR_IS_INTERNED(key)) {
zend_string_addref(key);
HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
}
}
/* If the Hash table is full, resize it */
if ((ht)->nNumUsed >= (ht)->nTableSize) {
igbinary_zend_hash_do_resize(ht);
}
add_to_hash:
idx = ht->nNumUsed++;
ht->nNumOfElements++;
#if PHP_VERSION_ID < 70300
if (ht->nInternalPointer == HT_INVALID_IDX) {
ht->nInternalPointer = idx;
}
zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
#endif
arData = ht->arData;
p = arData + idx;
p->key = key;
p->h = h = ZSTR_H(key);
nIndex = h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex);
HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);
ZVAL_NULL(&p->val);
return &p->val;
}
/* }}} */
static zend_always_inline zval *igbinary_zend_hash_index_add_or_find(HashTable *ht, zend_ulong h) /* {{{ */
{
uint32_t nIndex;
uint32_t idx;
Bucket *p;
// IS_CONSISTENT(ht);
// HT_ASSERT_RC1(ht);
if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
if (h < ht->nNumUsed) {
p = ht->arData + h;
if (Z_TYPE(p->val) != IS_UNDEF) {
replace:
return &p->val;
} else { /* we have to keep the order :( */
goto convert_to_hash;
}
} else if (EXPECTED(h < ht->nTableSize)) {
add_to_packed:
p = ht->arData + h;
/* incremental initialization of empty Buckets */
if (h > ht->nNumUsed) {
Bucket *q = ht->arData + ht->nNumUsed;
while (q != p) {
ZVAL_UNDEF(&q->val);
q++;
}
}
ht->nNextFreeElement = ht->nNumUsed = h + 1;
goto add;
} else if ((h >> 1) < ht->nTableSize &&
(ht->nTableSize >> 1) < ht->nNumOfElements) {
zend_hash_packed_grow(ht);
goto add_to_packed;
} else {
if (ht->nNumUsed >= ht->nTableSize) {
ht->nTableSize += ht->nTableSize;
}
convert_to_hash:
zend_hash_packed_to_hash(ht);
}
#if PHP_VERSION_ID >= 70400
} else if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
#else
} else if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
#endif
if (h < ht->nTableSize) {
zend_hash_real_init_packed(ht);
goto add_to_packed;
}
zend_hash_real_init_mixed(ht);
} else {
p = zend_hash_index_find_bucket(ht, h);
if (p) {
goto replace;
}
/* If the Hash table is full, resize it */
if ((ht)->nNumUsed >= (ht)->nTableSize) {
igbinary_zend_hash_do_resize(ht);
}
}
idx = ht->nNumUsed++;
nIndex = h | ht->nTableMask;
p = ht->arData + idx;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
if ((zend_long)h >= ht->nNextFreeElement) {
ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
}
add:
ht->nNumOfElements++;
#if PHP_VERSION_ID < 70300
if (ht->nInternalPointer == HT_INVALID_IDX) {
ht->nInternalPointer = ht->nNumUsed - 1;
}
zend_hash_iterators_update(ht, HT_INVALID_IDX, ht->nNumUsed - 1);
#endif
p->h = h;
p->key = NULL;
ZVAL_NULL(&p->val);
return &p->val;
}
/* }}} */
#endif /* PHP 7.2 to 8.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
*/
#endif /* IGBINARY_ZEND_HASH */
igbinary-3.2.15/src/php7/php_igbinary.h 0000664 0001750 0001750 00000003732 14532662345 017032 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
// Note: php_igbinary.h should contain publicly exposed variables, functions, and macros of igbinary.
// If a macro is needed by *only* igbinary, put it in igbinary_macros.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
#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-3.2.15/src/php7/ig_win32.h 0000664 0001750 0001750 00000001163 14532662345 015774 0 ustar tyson tyson #ifndef _IG_WIN32_H
#define _IG_WIN32_H
#if PHP_WIN32
# if defined(_MSC_VER) && _MSC_VER >= 1800
# include
# include
# else
# include "win32/php_stdint.h"
# 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 */
# ifdef _DEBUG
# include
# endif
#endif /* PHP_WIN32 */
#endif /* _IG_WIN32_H */
igbinary-3.2.15/igbinary.php 0000664 0001750 0001750 00000006730 14532662345 015057 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 binary representation of value that can be stored anywhere.
* @link http://www.php.net/serialize PHP's 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,
* then after successfully reconstructing the object,
* PHP will automatically call the __wakeup() member function (if it exists).
*
* If the passed in string could not be unserialized,
* then NULL is returned and an E_WARNING is issued.
*
* @param string $str The serialized string.
* @return mixed The unserialized value is returned. It can be a boolean, integer, float, string, array, object or null.
* @link http://www.php.net/manual/en/function.unserialize.php PHP's default unserialize
* @link https://secure.php.net/serializable Serializable interface
*/
function igbinary_unserialize($str);
igbinary-3.2.15/igbinary.php.ini 0000644 0001750 0001750 00000000210 14532662345 015616 0 ustar tyson tyson [igbinary]
extension=igbinary.so
; Enable or disable compacting of duplicate strings
; The default is On.
;igbinary.compact_strings=On
igbinary-3.2.15/tags.sh 0000755 0001750 0001750 00000000323 14532662345 014025 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-3.2.15/igbinary.spec 0000644 0001750 0001750 00000003106 14532662345 015212 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-3.2.15/COPYING 0000644 0001750 0001750 00000003017 14532662345 013566 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-3.2.15/CREDITS 0000664 0001750 0001750 00000001045 14532662345 013554 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 (fixes, tests, docs, php 7.x support)
Other
* Original hash functions - Bob Jenkins
---
http://irc-galleria.net/ - a finnish social networking site
igbinary-3.2.15/README.md 0000664 0001750 0001750 00000014413 14532662345 014016 0 ustar tyson tyson igbinary
========
[](https://github.com/igbinary/igbinary/actions/workflows/main.yml?query=branch%3Amaster)
[](https://ci.appveyor.com/project/TysonAndre/igbinary-bemsx)
Igbinary is a drop in replacement for the standard php serializer.
Instead of the time and space consuming textual representation used by PHP's `serialize`,
igbinary stores php data structures in a compact binary form.
Memory savings are significant when using memcached, APCu, or similar memory based storages for serialized data.
The typical reduction in storage requirements are around 50%.
The exact percentage depends on your data.
Unserialization performance is [at least on par with the standard PHP serializer, and is much faster for repetitive data](benchmark/comparisons.php).
Serialization performance depends on the `igbinary.compact_strings` option which enables
duplicate string tracking.
String are inserted to a hash table, which adds some overhead when serializing.
In usual scenarios this does not have much of an impact,
because the typical usage pattern is "serialize rarely, unserialize often".
With the `compact_strings` option enabled,
igbinary is usually a bit slower than the standard serializer.
Without it, igbinary is a bit faster.
Features
--------
- Support for the same data types as the standard PHP serializer: null, bool, int,
float, string, array and object.
- `__autoload` & `unserialize_callback_func`
- `__sleep` & `__wakeup`
- `__serialize` & `__unserialize` (only used in php 7.4+)
- Serializable -interface
- Data portability between platforms (32/64bit, endianness)
- Tested on Linux amd64, Linux ARM, Mac OSX x86, HP-UX PA-RISC and NetBSD sparc64
- Hooks up to the APCu in-memory key-value store as a serialization handler.
- Compatible with 7.0 – 8.0 (The older igbinary [2.x releases](https://github.com/igbinary/igbinary/tree/v2) support 5.2 – 5.6, 7.0 – 7.3)
Implementation details
----------------------
Storing complex PHP data structures such as arrays of associative arrays
with the standard PHP serializer is not very space efficient.
The main reasons of this inefficiency are listed below, in order of significance (at least in our applications):
1. Array keys, property names, and class names are repeated redundantly.
2. Numerical values are plain text.
3. Human readability adds some overhead.
Igbinary uses two strategies to minimize the size of the serialized
output.
1. Repeated strings are stored only once (this also includes class and property names).
Collections of objects benefit significantly from this.
See the `igbinary.compact_strings` option.
2. Integer 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:
```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
; If uncommented, use igbinary as the serializer of APCu
; (APCu 5.1.10 or newer is strongly recommended)
;apc.serializer=igbinary
```
Then, in your php code, replace `serialize` and `unserialize` function calls
with [`igbinary_serialize` and `igbinary_unserialize`](./igbinary.php).
Installing
----------
### Linux
If PHP was installed through your package manager,
the package manager may also contain prebuilt packages for `igbinary`
(with a package name similar to php-igbinary).
- The packages from some package managers and OS versions may be out of date and have known bugs. The latest release of igbinary is [](https://github.com/igbinary/igbinary/releases)
Igbinary may also be installed with the command `pecl install igbinary` (You will need to enable igbinary in php.ini)
Alternately, you may wish to [build from source](#building-from-source)
### MacOS
`pecl install igbinary` is the recommended installation method (You will need to enable igbinary in php.ini)
Alternately, you may wish to [build from source](#building-from-source).
### Installing on Windows
Prebuilt DLLs can be [downloaded from PECL](https://pecl.php.net/package/igbinary).
If you are a contributor to/packager of igbinary, or need to build from source, see [WINDOWS.md](./WINDOWS.md)
### Building from source
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
Bugs & Contributions
--------------------
Mailing list for bug reports and other development discussion can be found
at http://groups.google.com/group/igbinary (no longer used)
File bug reports at
https://github.com/igbinary/igbinary/issues
The preferred way to contribute is with pull requests.
Feel free to fork this at http://github.com/igbinary/igbinary
See [TESTING.md](./TESTING.md) for advice for testing patches.
See [TECH\_NOTES.md](./TECH_NOTES.md) for information about how igbinary is implemented
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 straightforward
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-3.2.15/TECH_NOTES.md 0000664 0001750 0001750 00000016320 14532662345 014553 0 ustar tyson tyson Overview
--------
The implementation of `igbinary` is largely based on php's own serializer.
Refer to https://github.com/php/php-src/blob/master/ext/standard/var_unserializer.re
and https://github.com/php/php-src/blob/master/ext/standard/var.c
Format
------
Refer to the implementation for details of how this works - this section is an overview and is not comprehensive.
Values are serialized with a byte representing the type of the value,
followed by 0 or more bytes with the serialization of the value.
Values can also be references to reuse earlier values
- `igbinary_type_string_id8` refers to a string value that was already serialized, where the identifier of that string takes up 8 bits(1 byte)
- `igbinary_type_objref8` refers to the *array of properties in* an object value that was already serialized
- `igbinary_type_object_id8` refers to a object that was already serialized.
- `igbinary_type_ref8` refers to something of any type that's part of a PHP reference group.
`igbinary_type_ref` creates a reference group the first time it's used, and `igbinary_type_ref8` adds a value that's a reference to that reference group.
The header returned by `igbinary_serialize()` in the latest igbinary releases
always starts with `\x00\x00\x00\x02` (version 2) (long ago, this started with `\x00\x00\x00\x01`)
```c
// From src/php7/igbinary.c
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. (when Serializable::serialize() is used) */
/* 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 */
};
```
For example, `bin2hex(igbinary_serialize(['first', true]))` is `000000021402060011056669727374060105`
```
00000002 -- 4 byte header indicating this is igbinary serialized data, version 2
14 02 -- An array(igbinary_type_array8) of size 2 (8-bit length)
06 00 -- The first array key - an igbinary_type_long8p (positive unsigned 8-bit integer) with value `0` (index 0)
11 05 6669727374 -- The array value - igbinary_type_string8 with an 8-bit length of 5 and the string value `first`
06 01 -- The second array key - the value `0`
05 -- igbinary_type_bool_true representing the value `true`
```
A limitation of the current serialization format and unserializers is that there can only be one reference group to the same value. (`igbinary_type_ref`)
For example, `$b = $a; igbinary_serialize([&$a, &$a, &$b, &$b])` would be serialized the same way as `[&$a, &$a, &$a, &$a]`.
Serializing
-----------
See README.md for details about the format, performance, and ini options.
### Edge cases
The following types of PHP methods are invoked when serializing values.
`igbinary_serialize()` must ensure that the pointers it keeps to the values being serialized
(and temporary values returned by invoked methods) aren't modified during serialization.
1. `Serializable::serialize()` may have side effects if the serialized
object has
2. `__sleep` is called immediately, which may have side effects
3. `__serialize` may have immediate side effects.
4. The serializers of internal classes.
Edge cases are dealt with by adding a reference to all referenceable values
so that they can't be freed prematurely.
Unserializing
-------------
### Edge cases
`igbinary_unserialize()` must ensure that the pointers it keeps to the php values it creates don't become invalid
during unserialization.
The following types of magic methods can be called during unserialization:
1. `Serializable::unserialize(string $serialized)` may have global side effects,
but is assumed to be unable to read or modify other values that are being unserialized
(excluding values created during other calls to `Serializable::unserialize()`, but igbinary is only concerned with the resulting object instance)
because it must be called while unserializing everything else.
2. `__unserialize()` is expected to be safe, because everything else has already been unserialized before it gets called.
3. `__wakeup()` is expected to be safe, because everything else has already been unserialized before it gets called.
4. `__destruct()` is called, but only if&after everything was successfully unserialized
(e.g. if `__wakeup()` throws, `__destruct()` will not be called for any directly created objects)
Sessions
--------
The standard implementation of `igbinary_serialize` and `igbinary_unserialize` are used to serialize/unserialize session data.
Refer to https://github.com/php/php-src/blob/master/ext/session/session.c for reference implementations of `PS_SERIALIZER_ENCODE_FUNC` and `PS_SERIALIZER_DECODE_FUNC` and how they change in PHP minor versions.
APCu
----
`apc_register_serializer` is called if igbinary was called with APCu support to make APCu aware that the igbinary serializer is available to serialize data to store in memory.
See the parts of the code referring to `HAVE_APCU_SUPPORT`
Redis, Memcached, etc.
----------------------
These data stores often use binary flags (or any other unambiguous indicator) to indicate that the igbinary serializer was used when saving data to the database,
and read those flags to determine which unserializer (e.g. `json_decode()`, `unserialize()`, `igbinary_unserialize()`, msgpack) to use.
igbinary-3.2.15/NEWS 0000664 0001750 0001750 00000030776 14532662345 013250 0 ustar tyson tyson 3.2.15 2023-12-02
=======
* Properly fix crash in igbinary_unserialize_object_enum_case with opcache protected memory and non-constant value. (#380)
3.2.14 2023-02-06
=======
* Fix build error in PHP 8.3-dev
* Fix test expectation errors in php 8.3-dev due to change to php's TypeErrors.
3.2.13 2023-02-02
=======
* Speed up unserialization of typed properties by reducing hash table collisions when looking up property reference info.
3.2.12 2022-11-07
=======
* Fix symbol error seen in php 8.2.0 loading zend_class_unserialize_deny, due to failing to load a header defining a macro.
3.2.11 2022-11-06
=======
* Fix a bug that could prevent objects/arrays with reference cycles from being properly garbage collected.
* Fix bugs in unserializing PHP references to values found in php 7.4 typed properties (#363)
3.2.10 2022-11-06
=======
* Add a macro that callers can use to check if igbinary will accept the header for data being unserialized.
* Fix bug preventing the unserialization of data containing representations of strings larger than 4GB.
3.2.9 2022-10-17
=======
* Fix invalid release artifact name in job to build dlls for https://github.com/igbinary/igbinary
3.2.8 2022-10-17
=======
* Fix invalid release artifact name in job to build dlls for https://github.com/igbinary/igbinary
3.2.8 2022-10-16
=======
* Reduce excessive inlining to reduce shared library size.
* Miscellaneous optimizations.
* Set up CI job to build dlls on https://github.com/igbinary/igbinary - at the moment, the infrastructure used by the Windows for php team has been broken for months.
3.2.7 2022-01-12
=======
* Update test expectations for php 8.2.0-dev. Add `#[AllowDynamicProperties]` Attribute to some tests to avoid notices.
* In php 8.1+, make igbinary_unserialize check to see if an equivalent interned string already exists when unserializing object property names, array keys, and class names
and use that instead of creating a brand new string.
(This deliberately doesn't create a new interned string if one doesn't already exist.)
(Before this change, igbinary would deduplicate strings when serializing, but would not check if strings were interned by PHP itself when unserializing)
* Avoid debug build assertion failure for `HT_ASSERT_RC1` the same way as PHP's unserialize - this is a case where ostensibly there are no other references to the array being unserialized.
3.2.6 2021-08-11
=======
* Fix igbinary version found in Reflection.
3.2.5 2021-08-07
=======
* Fix change in behavior introduced in 3.2.2RC1 when unserializing arrays - the internal array pointer (for `next()`, `key()`, etc) pointed past the end of the array in php 7.0-7.2.
3.2.4 2021-07-24
=======
* Forbid serializing classes that deny serialization/unserialization (anonymous classes, CURLFile, etc.) even when subclasses implement '__serialize' and '__unserialize'
3.2.3 2021-06-09
=======
* Fix build for php 8.1 after changes to enum internals.
* Update tests to suppress deprecations in php 8.1 and support run-tests.php changes in php 8.1
* Don't emit a notice when unserialize_callback_func causes igbinary_unserialize to throw https://bugs.php.net/bug.php?id=81118
3.2.2 2021-04-18
=======
* Eliminate impossible/redundant checks.
* Add a new type code for serialization and unserialization of PHP strings that are larger than 4GB.
* Add additional checks for overflow when serializing extremely large data structures.
(e.g. serializing more than 2**32 strings or 2**32 objects/references/arrays)
* Support serializing and unserializing php 8.1 enums (can only be unserialized in php 8.1+)
3.2.2RC1 2021-01-11
=======
* Update php version check to allow igbinary to be statically built in PHP 8.0+
* Fix bug in out of memory error handling in __sleep, slightly speed up serializing with __sleep.
* Continue serializing remaining properties if a missing property name is returned from __sleep.
* Speed up serializing by optimizing for the case where there is no memory manager override.
When there is a memory manager override, only use that for allocating the string to return.
(benchmarks/serialize-scalar-int.b.php showed a speedup from 0.22 to 0.18 seconds for repeated serialization of a single scalar,
and from 0.186 to 0.180 seconds for benchmarks/serialize-stringarray.b.php for an array of strings)
* Speed up unserializing arrays in php 7.2-8.0 by adding optimized code for finding the hash bucket of
a string/integer key of an array, or creating a placeholder if it does not already exist.
3.2.1 2020-12-27
=======
* Fix crash when unserializing if __serialize was defined but __unserialize was undefined in php 8.0+ (due to typo).
3.2.0 2020-12-26
=======
* Use PHP's shared empty array instance when unserializing empty arrays in php 7.3+.
(helps slightly with memory usage when repeatedly unserializing,
when removing elements from arrays before unserializing them,
or when serializing values including an empty array that was unserialized)
* Emit a deprecation notice when serializing resources.
PHP itself is converting many resources to objects that throw an Error on serialization attempts.
Continue to represent resources as null in the serialized data.
* Fix memory management bug when unserializing invalid data (duplicate properties in objects (e.g. from `__sleep`) or duplicate fields in arrays (impossible for valid data)).
* Speed up calls to `__serialize`/`__unserialize` in php 8.0+.
* Fix error messages for unserialize_callback_func: make messages properly refer to the autoload function.
* Optimize unserializing alternative names for private/protected properties that were previously public.
3.1.6 2020-10-08
=======
* Fix build failure with older C standard (e.g. building on CentOS 6).
* Otherwise, identical to 3.1.6RC1.
3.1.6RC1 2020-10-07
=======
* Fix igbinary_serialize incorrectly deduplicating arrays/objects/references when they were garbage collected/freed during serialization.
3.1.5 2020-09-02
=======
* Update unit test expectation to match behavior in php 8 due to changes in php's handling of cyclic references in arrays.
* Support API changes in php 8.0.0beta3.
3.1.4 2020-07-05
=======
* Fix unserialization of PHP references to internal/user-defined classes using PHP 7.4's `__unserialize` (e.g. `ArrayObject`)
3.1.3 2020-07-04
=======
* Properly serialize reference groups of size 1 (these can be created by array_walk_recursive and other functions).
Note that this does not fix the general case where values not being serialized are in the same reference group as a value being serialized.
* PHP 8.0 compatibility fixes.
3.1.2 2020-01-16
=======
* Speed up object, array, reference, and string serialization.
* Speed up unserializing integers between 0 and 65535 (as values and array keys).
* Speed up unserializing objects with declared properties.
3.1.1 2020-01-16
=======
* Fix bug causing incorrect serialization for 1 in 2**32 strings on 64-bit php installations when string hashes collide.
(https://github.com/igbinary/igbinary/issues/260)
3.1.1a1 2020-01-11
=======
* Throw when an uninitialized php 7.4 typed property is included in the result of __sleep(),
instead of emitting a notice and attempting to represent the unset/uninitialized value as null (#258).
See https://bugs.php.net/bug.php?id=79002
Uninitialized properties without types (from __sleep) continue to cause igbinary to emit notices and are represented as null.
3.1.0 2019-12-27
=======
* Same as 3.1.0b4.
3.1.0b4 2019-12-20
=======
* Don't call __destruct for objects where deferred __unserialize calls were not started (e.g. due to Serializable::unserialize throwing).
3.1.0b3 2019-12-10
=======
* Skip over object properties that are uninitialized or unset when serializing, instead of serializing them as null.
This is done to avoid Errors when unserializing their values for php 7.4 typed properties.
3.1.0b2 2019-12-09
=======
* Fix crashes related to unserializing instances of classes with php 7.4 typed properties.
3.1.0b1 2019-12-08
=======
* Support php 7.4's __serialize/__unserialize the same way serialize()/unserialize() does.
This deliberately only supports __serialize/__unserialize in php 7.4, to making switching to/from serialize()/unserialize() as straightforward as possible.
3.0.1 2019-03-20
=======
* Fix version check when statically building igbinary inside of the php-src folder.
3.0.0 2019-02-17
=======
* Identical to 3.0.0a2
3.0.0a2 2019-02-13
=======
* Don't use empty string for serializing empty $_SESSION array, it breaks some save handlers. (Issue #231)
Continue treating the empty string as the empty $_SESSION array when unserializing.
3.0.0a1 2019-02-08
=======
* This release line drops support for PHP5.
* Drop support for APC (APC was only available for PHP5 - It is the predecessor of APCu)
* Emit a warning and return null if igbinary_unserialize() is passed more data to unserialize than expected.
* Fix compilation against PHP 7.4-dev. Igbinary does NOT yet properly serialize/unserialize all classes with PHP 7.4-dev's typed properties.
* The serialization format is exactly the same as igbinary 2.x
2.0.8 2018-10-20
=======
* Be more aggressive about deduplication when generating serialization of arrays in php 7.0+.
* Define HAVE_IGBINARY on Unix/Linux. (previously defined only on Windows)
* Update formatting/wording of documentation.
2.0.7 2018-06-27
=======
* Fix compiler warnings about format strings, for errors that should not occur during normal igbinary usage.
2.0.6 2018-05-12
=======
* Same as 2.0.6RC1
2.0.6RC1 2018-04-01
=======
* Fix a bug in Windows debug builds.
* Emit more specific warnings when __sleep() returns a declared property that was unset.
* Fix harmless compiler warnings during builds.
* Fix a build error on PHP7.3-dev.
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