- SPL:
. Fixed bug #69264 (__debugInfo() ignored while extending SPL classes). (cmb)
+ . Fixed bug #67369 (ArrayObject serialization drops the iterator class).
+ (Alex Dowad)
- Standard:
. Fixed bug #79468 (SIGSEGV when closing stream handle with a stream filter
ZVAL_ARR(&tmp, zend_std_get_properties(ZEND_THIS));
Z_TRY_ADDREF(tmp);
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+
+ /* iterator class */
+ if (intern->ce_get_iterator == spl_ce_ArrayIterator) {
+ ZVAL_NULL(&tmp);
+ } else {
+ ZVAL_STR_COPY(&tmp, intern->ce_get_iterator->name);
+ }
+ zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
}
/* }}} */
{
spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS);
HashTable *data;
- zval *flags_zv, *storage_zv, *members_zv;
+ zval *flags_zv, *storage_zv, *members_zv, *iterator_class_zv;
zend_long flags;
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
return;
}
- flags_zv = zend_hash_index_find(data, 0);
- storage_zv = zend_hash_index_find(data, 1);
- members_zv = zend_hash_index_find(data, 2);
+ flags_zv = zend_hash_index_find(data, 0);
+ storage_zv = zend_hash_index_find(data, 1);
+ members_zv = zend_hash_index_find(data, 2);
+ iterator_class_zv = zend_hash_index_find(data, 3);
+
if (!flags_zv || !storage_zv || !members_zv ||
- Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY) {
+ Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY ||
+ (iterator_class_zv && (Z_TYPE_P(iterator_class_zv) != IS_NULL &&
+ Z_TYPE_P(iterator_class_zv) != IS_STRING))) {
zend_throw_exception(spl_ce_UnexpectedValueException,
"Incomplete or ill-typed serialization data", 0);
return;
}
object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
+
+ if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) {
+ zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv));
+
+ if (!ce) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
+ "Cannot deserialize ArrayObject with iterator class '%s'; no such class exists",
+ ZSTR_VAL(Z_STR_P(iterator_class_zv)));
+ return;
+ } else if (!instanceof_function(ce, spl_ce_Iterator)) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
+ "Cannot deserialize ArrayObject with iterator class '%s'; this class does not implement the Iterator interface",
+ ZSTR_VAL(Z_STR_P(iterator_class_zv)));
+ return;
+ } else {
+ intern->ce_get_iterator = ce;
+ }
+ }
}
/* }}} */
--- /dev/null
+--TEST--
+ArrayObject::__serialize saves any iterator class set by ::setIteratorClass
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator {}
+$arrayObject = new ArrayObject(array(1, 2, 3));
+$arrayObject->setIteratorClass("MyArrayIterator");
+$serialized = serialize($arrayObject);
+$backAgain = unserialize($serialized);
+echo $backAgain->getIteratorClass(), "\n";
+
+?>
+--EXPECT--
+MyArrayIterator
)
)
-O:11:"ArrayObject":3:{i:0;i:0;i:1;O:11:"ArrayObject":3:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}}i:2;a:0:{}}
+O:11:"ArrayObject":4:{i:0;i:0;i:1;O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}i:3;N;}i:2;a:0:{}i:3;N;}
ArrayObject Object
(
[storage:ArrayObject:private] => ArrayObject Object
var_dump($s1);
var_dump($s2);
-$o1 =unserialize($s1);
+$o1 = unserialize($s1);
var_dump($o1[0] === $o1[1]);
var_dump($o1[2] === $o1);
--EXPECT--
bool(true)
bool(true)
-string(90) "O:11:"ArrayObject":3:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}}"
-string(131) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;O:11:"ArrayObject":3:{i:0;i:0;i:1;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;}i:2;a:0:{}}};m:a:0:{}"
+string(96) "O:11:"ArrayObject":4:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}i:3;N;}"
+string(137) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;O:11:"ArrayObject":4:{i:0;i:0;i:1;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;}i:2;a:0:{}i:3;N;}};m:a:0:{}"
bool(true)
bool(true)
bool(true)
#### Extending ArrayObject
bool(true)
bool(true)
-string(91) "O:12:"ArrayObject2":3:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}}"
-array(3) {
+string(97) "O:12:"ArrayObject2":4:{i:0;i:0;i:1;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;}i:2;a:0:{}i:3;N;}"
+array(4) {
[0]=>
int(0)
[1]=>
[2]=>
array(0) {
}
+ [3]=>
+ NULL
}
bool(true)
bool(true)
["foo"]=>
string(3) "bar"
}
-string(71) "O:9:"SelfArray":3:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}}"
+string(77) "O:9:"SelfArray":4:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}i:3;N;}"
object(SelfArray)#9 (1) {
["foo"]=>
string(3) "bar"
echo "ArrayObject:\n";
try {
+ // empty array
unserialize('O:11:"ArrayObject":0:{}');
} catch (Exception $e) {
echo $e->getMessage(), "\n";
echo $e->getMessage(), "\n";
}
+try {
+ // iterator class name is not a string
+ unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;i:0;i:2;a:0:{}i:3;i:0;}');
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+try {
+ unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}i:3;s:11:"NonExistent";}');
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
+class Existent {}
+
+try {
+ unserialize('O:11:"ArrayObject":4:{i:0;i:0;i:1;a:2:{i:0;i:1;i:1;i:2;}i:2;a:0:{}i:3;s:8:"Existent";}');
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+
echo "ArrayIterator:\n";
try {
}
?>
---EXPECTF--
+--EXPECT--
ArrayObject:
Incomplete or ill-typed serialization data
Incomplete or ill-typed serialization data
Incomplete or ill-typed serialization data
Passed variable is not an array or object
+Incomplete or ill-typed serialization data
+Cannot deserialize ArrayObject with iterator class 'NonExistent'; no such class exists
+Cannot deserialize ArrayObject with iterator class 'Existent'; this class does not implement the Iterator interface
ArrayIterator:
Incomplete or ill-typed serialization data
Incomplete or ill-typed serialization data
--EXPECTF--
array(2) {
[0]=>
- object(__PHP_Incomplete_Class)#3 (4) {
+ object(__PHP_Incomplete_Class)#3 (5) {
["__PHP_Incomplete_Class_Name"]=>
string(4) "Bar1"
["0"]=>
["2"]=>
array(0) {
}
+ ["3"]=>
+ NULL
}
[1]=>
object(__PHP_Incomplete_Class)#4 (1) {