colder Mon Aug 25 18:40:46 2008 UTC
Added files: (Branch: PHP_5_3)
/php-src/ext/spl/tests bug45826.phpt
Modified files:
/php-src/ext/spl spl_array.c
/php-src NEWS
Log:
MFH: Fix #45826 (Custom serialization)
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_array.c?r1=1.71.2.17.2.13.2.21&r2=1.71.2.17.2.13.2.22&diff_format=u
Index: php-src/ext/spl/spl_array.c
diff -u php-src/ext/spl/spl_array.c:1.71.2.17.2.13.2.21
php-src/ext/spl/spl_array.c:1.71.2.17.2.13.2.22
--- php-src/ext/spl/spl_array.c:1.71.2.17.2.13.2.21 Fri Aug 8 22:07:07 2008
+++ php-src/ext/spl/spl_array.c Mon Aug 25 18:40:44 2008
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_array.c,v 1.71.2.17.2.13.2.21 2008/08/08 22:07:07 colder Exp $ */
+/* $Id: spl_array.c,v 1.71.2.17.2.13.2.22 2008/08/25 18:40:44 colder Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -59,18 +59,22 @@
#define SPL_ARRAY_CLONE_MASK 0x0300FFFF
typedef struct _spl_array_object {
- zend_object std;
- zval *array;
- zval *retval;
- HashPosition pos;
- int ar_flags;
- int is_self;
- zend_function *fptr_offset_get;
- zend_function *fptr_offset_set;
- zend_function *fptr_offset_has;
- zend_function *fptr_offset_del;
- zend_function *fptr_count;
- zend_class_entry* ce_get_iterator;
+ zend_object std;
+ zval *array;
+ zval *retval;
+ HashPosition pos;
+ int ar_flags;
+ int is_self;
+ zend_function *fptr_offset_get;
+ zend_function *fptr_offset_set;
+ zend_function *fptr_offset_has;
+ zend_function *fptr_offset_del;
+ zend_function *fptr_count;
+ zend_function *fptr_serialize;
+ zend_function *fptr_unserialize;
+ zend_class_entry *ce_get_iterator;
+ php_serialize_data_t *serialize_data;
+ php_unserialize_data_t *unserialize_data;
} spl_array_object;
static inline HashTable *spl_array_get_hash_table(spl_array_object* intern,
int check_std_props TSRMLS_DC) { /* {{{ */
@@ -124,6 +128,8 @@
/* }}} */
zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval
*object, int by_ref TSRMLS_DC);
+int spl_array_serialize(zval *object, unsigned char **buffer, zend_uint
*buf_len, zend_serialize_data *data TSRMLS_DC);
+int spl_array_unserialize(zval **object, zend_class_entry *ce, const unsigned
char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
/* {{{ spl_array_object_new_ex */
static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type,
spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
@@ -143,6 +149,8 @@
zend_hash_copy(intern->std.properties, &class_type->default_properties,
(copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
intern->ar_flags = 0;
+ intern->serialize_data = NULL;
+ intern->unserialize_data = NULL;
intern->ce_get_iterator = spl_ce_ArrayIterator;
if (orig) {
spl_array_object *other =
(spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
@@ -208,6 +216,14 @@
if (intern->fptr_count->common.scope == parent) {
intern->fptr_count = NULL;
}
+ zend_hash_find(&class_type->function_table, "serialize",
sizeof("serialize"), (void **) &intern->fptr_serialize);
+ if (intern->fptr_serialize->common.scope == parent) {
+ intern->fptr_serialize = NULL;
+ }
+ zend_hash_find(&class_type->function_table, "unserialize",
sizeof("unserialize"), (void **) &intern->fptr_unserialize);
+ if (intern->fptr_unserialize->common.scope == parent) {
+ intern->fptr_unserialize = NULL;
+ }
}
/* Cache iterator functions if ArrayIterator or derived. Check
current's */
/* cache since only current is always required */
@@ -1440,32 +1456,27 @@
}
/* }}} */
-/* {{{ proto string ArrayObject::serialize()
- * serialize the object
- */
-SPL_METHOD(Array, serialize)
-{
- zval *object = getThis();
- spl_array_object *intern =
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+smart_str spl_array_serialize_helper(spl_array_object *intern,
php_serialize_data_t *var_hash_p TSRMLS_DC) { /* {{{ */
HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
zval members, *pmembers;
- php_serialize_data_t var_hash;
smart_str buf = {0};
+ zval *flags;
if (!aht) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified
outside object and is no longer an array");
- return;
+ return buf;
}
- PHP_VAR_SERIALIZE_INIT(var_hash);
+ MAKE_STD_ZVAL(flags);
+ ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
/* storage */
- smart_str_appendl(&buf, "x:i:", 4);
- smart_str_append_long(&buf, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
- smart_str_appendc(&buf, ';');
+ smart_str_appendl(&buf, "x:", 2);
+ php_var_serialize(&buf, &flags, var_hash_p TSRMLS_CC);
+ zval_ptr_dtor(&flags);
if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
- php_var_serialize(&buf, &intern->array, &var_hash TSRMLS_CC);
+ php_var_serialize(&buf, &intern->array, var_hash_p TSRMLS_CC);
smart_str_appendc(&buf, ';');
}
@@ -1475,10 +1486,35 @@
Z_ARRVAL(members) = intern->std.properties;
Z_TYPE(members) = IS_ARRAY;
pmembers = &members;
- php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes
the string */
+ php_var_serialize(&buf, &pmembers, var_hash_p TSRMLS_CC); /* finishes
the string */
/* done */
- PHP_VAR_SERIALIZE_DESTROY(var_hash);
+ return buf;
+}
+/* }}} */
+
+/* {{{ proto string ArrayObject::serialize()
+ * serialize the object
+ */
+SPL_METHOD(Array, serialize)
+{
+ zval *object = getThis();
+ spl_array_object *intern =
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ int was_in_serialize = intern->serialize_data != NULL;
+ smart_str buf;
+
+ if (!was_in_serialize) {
+ intern->serialize_data = emalloc(sizeof(php_serialize_data_t));
+ PHP_VAR_SERIALIZE_INIT(*intern->serialize_data);
+ }
+
+ buf = spl_array_serialize_helper(intern, intern->serialize_data
TSRMLS_CC);
+
+ if (!was_in_serialize) {
+ PHP_VAR_SERIALIZE_DESTROY(*intern->serialize_data);
+ efree(intern->serialize_data);
+ intern->serialize_data = NULL;
+ }
if (buf.c) {
RETURN_STRINGL(buf.c, buf.len, 0);
@@ -1487,32 +1523,45 @@
RETURN_NULL();
} /* }}} */
-/* {{{ proto void ArrayObject::unserialize(string serialized)
- * unserialize the object
- */
-SPL_METHOD(Array, unserialize)
-{
- spl_array_object *intern =
(spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+int spl_array_serialize(zval *object, unsigned char **buffer, zend_uint
*buf_len, zend_serialize_data *data TSRMLS_DC) { /* {{{ */
+ spl_array_object *intern =
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
- char *buf;
- int buf_len;
+ if (intern->fptr_serialize) {
+ int retval;
+ php_serialize_data_t *before;
+
+ before = intern->serialize_data;
+ intern->serialize_data = (php_serialize_data_t *)data;
+
+ retval = zend_user_serialize(object, buffer, buf_len, data
TSRMLS_CC);
+
+ intern->serialize_data = before;
+
+ return retval;
+ } else {
+ smart_str buf;
+
+ buf = spl_array_serialize_helper(intern, (php_serialize_data_t
*)data TSRMLS_CC);
+
+ if (buf.c) {
+ *buffer = (unsigned char*)estrndup(buf.c, buf.len);
+ *buf_len = buf.len;
+ efree(buf.c);
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+ }
+}
+/* }}} */
+
+void spl_array_unserialize_helper(spl_array_object *intern, const unsigned
char *buf, int buf_len, php_unserialize_data_t *var_hash_p TSRMLS_DC) { /* {{{
*/
const unsigned char *p, *s;
- php_unserialize_data_t var_hash;
zval *pmembers, *pflags = NULL;
long flags;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf,
&buf_len) == FAILURE) {
- return;
- }
-
- if (buf_len == 0) {
- zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0
TSRMLS_CC, "Empty serialized string cannot be empty");
- return;
- }
/* storage */
- s = p = (const unsigned char*)buf;
- PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ s = p = buf;
if (*p!= 'x' || *++p != ':') {
goto outexcept;
@@ -1520,7 +1569,7 @@
++p;
ALLOC_INIT_ZVAL(pflags);
- if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC)
|| Z_TYPE_P(pflags) != IS_LONG) {
+ if (!php_var_unserialize(&pflags, &p, s + buf_len, var_hash_p
TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
zval_ptr_dtor(&pflags);
goto outexcept;
}
@@ -1546,7 +1595,7 @@
intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
zval_ptr_dtor(&intern->array);
ALLOC_INIT_ZVAL(intern->array);
- if (!php_var_unserialize(&intern->array, &p, s + buf_len,
&var_hash TSRMLS_CC)) {
+ if (!php_var_unserialize(&intern->array, &p, s + buf_len,
var_hash_p TSRMLS_CC)) {
goto outexcept;
}
}
@@ -1562,7 +1611,7 @@
++p;
ALLOC_INIT_ZVAL(pmembers);
- if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash
TSRMLS_CC)) {
+ if (!php_var_unserialize(&pmembers, &p, s + buf_len, var_hash_p
TSRMLS_CC)) {
zval_ptr_dtor(&pmembers);
goto outexcept;
}
@@ -1572,17 +1621,83 @@
zval_ptr_dtor(&pmembers);
/* done reading $serialized */
-
- PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return;
outexcept:
- PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
- zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Error at offset %ld of %d bytes", (long)((char*)p - (char *)buf), buf_len);
return;
+}
+/* }}} */
+
+/* {{{ proto void ArrayObject::unserialize(string serialized)
+ *
+ *
+ * unserialize the object
+ */
+SPL_METHOD(Array, unserialize)
+{
+ char *buf;
+ int buf_len;
+ spl_array_object *intern =
(spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ int was_in_unserialize = intern->unserialize_data != NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf,
&buf_len) == FAILURE) {
+ return;
+ }
+
+ if (buf_len == 0) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0
TSRMLS_CC, "Empty serialized string cannot be empty");
+ return;
+ }
+
+ if (!was_in_unserialize) {
+ intern->unserialize_data =
emalloc(sizeof(php_unserialize_data_t));
+ PHP_VAR_UNSERIALIZE_INIT(*intern->unserialize_data);
+ }
+
+ spl_array_unserialize_helper(intern, (const unsigned char *)buf,
buf_len, intern->unserialize_data TSRMLS_CC);
+
+ if (!was_in_unserialize) {
+ PHP_VAR_UNSERIALIZE_DESTROY(*intern->unserialize_data);
+ efree(intern->unserialize_data);
+ intern->unserialize_data = NULL;
+ }
} /* }}} */
+int spl_array_unserialize(zval **object, zend_class_entry *ce, int type, const
zstr buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC)
+{
+ spl_array_object *intern;
+
+ object_init_ex(*object, ce);
+ intern = (spl_array_object*)zend_object_store_get_object(*object
TSRMLS_CC);
+
+ if (intern->fptr_unserialize) {
+ zval *zdata;
+ php_unserialize_data_t *before;
+ MAKE_STD_ZVAL(zdata);
+ ZVAL_ZSTRL(zdata, type, buf, buf_len, 1);
+
+ before = intern->unserialize_data;
+ intern->unserialize_data = (php_unserialize_data_t *)data;
+
+ zend_call_method_with_1_params(object, ce,
&ce->unserialize_func, "unserialize", NULL, zdata);
+
+ intern->unserialize_data = before;
+
+ zval_ptr_dtor(&zdata);
+ } else {
+ spl_array_unserialize_helper(intern, buf, buf_len,
(php_unserialize_data_t *)data TSRMLS_CC);
+ }
+
+ if (EG(exception)) {
+ return FAILURE;
+ } else {
+ return SUCCESS;
+ }
+}
+/* }}} */
+
/* {{{ arginfo and function tbale */
static
ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
@@ -1705,6 +1820,8 @@
REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
+ spl_ce_ArrayObject->serialize = spl_array_serialize;
+ spl_ce_ArrayObject->unserialize = spl_array_unserialize;
memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
@@ -1727,6 +1844,8 @@
REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
+ spl_ce_ArrayIterator->serialize = spl_array_serialize;
+ spl_ce_ArrayIterator->unserialize = spl_array_unserialize;
memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject,
sizeof(zend_object_handlers));
spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.285&r2=1.2027.2.547.2.965.2.286&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.965.2.285
php-src/NEWS:1.2027.2.547.2.965.2.286
--- php-src/NEWS:1.2027.2.547.2.965.2.285 Mon Aug 25 08:37:10 2008
+++ php-src/NEWS Mon Aug 25 18:40:44 2008
@@ -52,6 +52,7 @@
- Fixed bug #43008 (php://filter uris ignore url encoded filternames and can't
handle slashes). (Arnaud)
- Fixed bug #35980 (touch() works on files but not on directories). (Pierre)
+- Fixed bug #45826 (custom ArrayObject serialization). (Etienne)
01 Aug 2008, PHP 5.3.0 Alpha 1
- Upgraded bundled PCRE to version 7.7. (Nuno)
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/bug45826.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/bug45826.phpt
+++ php-src/ext/spl/tests/bug45826.phpt
--TEST--
ArrayObject/ArrayIterator : serialization
--FILE--
<?php
$o = new ArrayObject();
$y = new StdClass;
$o->append($y);
$o->append($y);
$o->append($o);
var_dump($o[0] === $o[1]);
var_dump($o[2] === $o);
$s1 = serialize($o);
$s2 = $o->serialize();
var_dump($s1);
var_dump($s2);
$o1 =unserialize($s1);
var_dump($o1[0] === $o1[1]);
var_dump($o1[2] === $o1);
$o2 = new ArrayObject();
$o2->unserialize($s2);
var_dump($o2[0] === $o2[1]);
var_dump($o2[2] !== $o2);
var_dump($o2[2][2] === $o2[2]);
echo "#### Extending ArrayObject\n";
unset($o,$x,$s1,$s2,$o1,$o2);
class ArrayObject2 extends ArrayObject {
public function serialize() {
return parent::serialize();
}
public function unserialize($s) {
return parent::unserialize($s);
}
}
$o = new ArrayObject2();
$y = new StdClass;
$o->append($y);
$o->append($y);
$o->append($o);
var_dump($o[0] === $o[1]);
var_dump($o[2] === $o);
$s1 = serialize($o);
$s2 = $o->serialize();
var_dump($s1);
var_dump($s2);
$o1 =unserialize($s1);
var_dump($o1[0] === $o1[1]);
var_dump($o1[2] === $o1);
$o2 = new ArrayObject2();
$o2->unserialize($s2);
var_dump($o2[0] === $o2[1]);
var_dump($o2[2] !== $o2);
var_dump($o2[2][2] === $o2[2]);
?>
--EXPECT--
bool(true)
bool(true)
unicode(84)
"C:11:"ArrayObject":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}"
string(125)
"x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:11:"ArrayObject":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}"
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
#### Extending ArrayObject
bool(true)
bool(true)
unicode(85)
"C:12:"ArrayObject2":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}"
string(126)
"x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:12:"ArrayObject2":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}"
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php