From e6a3ff0dac5ad1c9f4565e5636a811d16337e4c9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 11 Aug 2013 19:21:59 +0100 Subject: [PATCH 01/16] Add new PHPAPI functions for serializing object and its properties --- ext/standard/php_var.h | 42 +++++++- ext/standard/var.c | 219 +++++++++++++++++++++++++++++------------ 2 files changed, 199 insertions(+), 62 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 35343b3d5d068..261aec730c3ab 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -38,8 +38,47 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC); + +#define PHP_SERIALIZE_FAILURE (FAILURE) +#define PHP_SERIALIZE_CUSTOM (SUCCESS) +#define PHP_SERIALIZE_OBJECT (SUCCESS + 1) + typedef HashTable* php_serialize_data_t; +/* serialize variable */ +PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); + +/* add object serialization string prefix */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC); + +/* append string that ends the object definition */ +PHPAPI void php_var_serialize_object_end(smart_str *buf); + +/* append null property */ +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key); + +/* append boolean property */ +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value); + +/* append long property */ +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value); + +/* append double property */ +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC); + +/* append string property */ +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value); + +/* append string property */ +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len); + +/* append string property zval */ +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC); + +/* append properties taken from HashTable */ +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC); + + struct php_unserialize_data { void *first; void *last; @@ -49,9 +88,10 @@ struct php_unserialize_data { typedef struct php_unserialize_data* php_unserialize_data_t; -PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); + + #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ do { \ /* fprintf(stderr, "SERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */ \ diff --git a/ext/standard/var.c b/ext/standard/var.c index c1e7c2f3ee346..81bb1a71d3025 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -584,6 +584,20 @@ static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old } /* }}} */ +static inline void php_var_serialize_null(smart_str *buf) /* {{{ */ +{ + smart_str_appendl(buf, "N;", 2); +} +/* }}} */ + +static inline void php_var_serialize_bool(smart_str *buf, long val) /* {{{ */ +{ + smart_str_appendl(buf, "b:", 2); + smart_str_append_long(buf, val); + smart_str_appendc(buf, ';'); +} +/* }}} */ + static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ { smart_str_appendl(buf, "i:", 2); @@ -592,7 +606,21 @@ static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ } /* }}} */ -static inline void php_var_serialize_string(smart_str *buf, char *str, int len) /* {{{ */ +static inline void php_var_serialize_double(smart_str *buf, double val TSRMLS_DC) /* {{{ */ +{ + char *s; + + smart_str_appendl(buf, "d:", 2); + s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); + php_gcvt(val, PG(serialize_precision), '.', 'E', s); + smart_str_appends(buf, s); + smart_str_appendc(buf, ';'); + efree(s); + return; +} +/* }}} */ + +static inline void php_var_serialize_string(smart_str *buf, const char *str, int len) /* {{{ */ { smart_str_appendl(buf, "s:", 2); smart_str_append_long(buf, len); @@ -602,6 +630,55 @@ static inline void php_var_serialize_string(smart_str *buf, char *str, int len) } /* }}} */ +static inline void php_var_serialize_hash_table(smart_str *buf, HashTable *myht, zval **pstruc, zend_bool incomplete_class, HashTable *var_hash TSRMLS_DC) /* {{{ */ +{ + int i; + char *key; + zval **data; + ulong index; + uint key_len; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(myht, &pos); + for (;; zend_hash_move_forward_ex(myht, &pos)) { + i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); + if (i == HASH_KEY_NON_EXISTENT) { + break; + } + if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { + continue; + } + + switch (i) { + case HASH_KEY_IS_LONG: + php_var_serialize_long(buf, index); + break; + case HASH_KEY_IS_STRING: + php_var_serialize_string(buf, key, key_len - 1); + break; + } + + /* we should still add element even if it's not OK, + * since we already wrote the length of the array before */ + if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS + || !data + || data == pstruc + || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) + ) { + smart_str_appendl(buf, "N;", 2); + } else { + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount++; + } + php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount--; + } + } + } +} +/* }}} */ + static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc TSRMLS_DC) /* {{{ */ { PHP_CLASS_ATTRIBUTES; @@ -734,30 +811,20 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var switch (Z_TYPE_P(struc)) { case IS_BOOL: - smart_str_appendl(buf, "b:", 2); - smart_str_append_long(buf, Z_LVAL_P(struc)); - smart_str_appendc(buf, ';'); + php_var_serialize_bool(buf, Z_LVAL_P(struc)); return; case IS_NULL: - smart_str_appendl(buf, "N;", 2); + php_var_serialize_null(buf); return; case IS_LONG: php_var_serialize_long(buf, Z_LVAL_P(struc)); return; - case IS_DOUBLE: { - char *s; - - smart_str_appendl(buf, "d:", 2); - s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); - php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s); - smart_str_appends(buf, s); - smart_str_appendc(buf, ';'); - efree(s); - return; - } + case IS_DOUBLE: + php_var_serialize_double(buf, Z_DVAL_P(struc) TSRMLS_CC); + return; case IS_STRING: php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc)); @@ -766,7 +833,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var case IS_OBJECT: { zval *retval_ptr = NULL; zval fname; - int res; + int res, serialize_rc; zend_class_entry *ce = NULL; if (Z_OBJ_HT_P(struc)->get_class_entry) { @@ -778,7 +845,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var unsigned char *serialized_data = NULL; zend_uint serialized_length; - if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC) == SUCCESS) { + serialize_rc = ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC); + if (serialize_rc == PHP_SERIALIZE_CUSTOM) { smart_str_appendl(buf, "C:", 2); smart_str_append_long(buf, (int)Z_OBJCE_P(struc)->name_length); smart_str_appendl(buf, ":\"", 2); @@ -789,6 +857,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_appendl(buf, ":{", 2); smart_str_appendl(buf, serialized_data, serialized_length); smart_str_appendc(buf, '}'); + } else if (serialize_rc == PHP_SERIALIZE_OBJECT) { + smart_str_appendl(buf, serialized_data, serialized_length); } else { smart_str_appendl(buf, "N;", 2); } @@ -851,49 +921,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_append_long(buf, i); smart_str_appendl(buf, ":{", 2); if (i > 0) { - char *key; - zval **data; - ulong index; - uint key_len; - HashPosition pos; - - zend_hash_internal_pointer_reset_ex(myht, &pos); - for (;; zend_hash_move_forward_ex(myht, &pos)) { - i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); - if (i == HASH_KEY_NON_EXISTENT) { - break; - } - if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { - continue; - } - - switch (i) { - case HASH_KEY_IS_LONG: - php_var_serialize_long(buf, index); - break; - case HASH_KEY_IS_STRING: - php_var_serialize_string(buf, key, key_len - 1); - break; - } - - /* we should still add element even if it's not OK, - * since we already wrote the length of the array before */ - if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS - || !data - || data == &struc - || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) - ) { - smart_str_appendl(buf, "N;", 2); - } else { - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount++; - } - php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount--; - } - } - } + php_var_serialize_hash_table(buf, myht, &struc, incomplete_class, var_hash TSRMLS_CC); } smart_str_appendc(buf, '}'); return; @@ -912,6 +940,75 @@ PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t } /* }}} */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_class_name(buf, object TSRMLS_CC); + smart_str_append_long(buf, nprops); + smart_str_appendl(buf, ":{", 2); +} +/* }}} */ + +PHPAPI void php_var_serialize_object_end(smart_str *buf) /* {{{ */ +{ + smart_str_appendc(buf, '}'); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_bool(buf, value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_long(buf, value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_double(buf, value TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, strlen(value)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, value_len); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_intern(buf, value, var_hash TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_hash_table(buf, properties, NULL, 0, var_hash TSRMLS_CC); +} +/* }}} */ + + /* {{{ proto string serialize(mixed variable) Returns a string representation of variable (which can later be unserialized) */ PHP_FUNCTION(serialize) From 172d862da06c408be66d04a1e7b5d5f2765c8924 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 1 Sep 2013 17:08:14 +0100 Subject: [PATCH 02/16] Call unserialize for non-custom object --- ext/standard/var_unserializer.c | 44 ++++++++++++++++++++------------ ext/standard/var_unserializer.re | 12 ++++++++- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index ddf43b02cf14d..e7a46a1343def 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 */ +/* Generated by re2c 0.13.6 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -354,7 +354,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ce->name); object_init_ex(*rval, ce); - } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -492,7 +492,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 785 "ext/standard/var_unserializer.re" +#line 795 "ext/standard/var_unserializer.re" { return 0; } #line 498 "ext/standard/var_unserializer.c" yy4: @@ -537,7 +537,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 779 "ext/standard/var_unserializer.re" +#line 789 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); @@ -715,9 +715,19 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } efree(class_name); + /* custom unserialization for non-custom objects */ + if (ce->unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + (*p) += ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 721 "ext/standard/var_unserializer.c" +#line 731 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -750,7 +760,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 754 "ext/standard/var_unserializer.c" +#line 764 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -791,7 +801,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 795 "ext/standard/var_unserializer.c" +#line 805 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -841,7 +851,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 845 "ext/standard/var_unserializer.c" +#line 855 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -890,7 +900,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 894 "ext/standard/var_unserializer.c" +#line 904 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -988,7 +998,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 992 "ext/standard/var_unserializer.c" +#line 1002 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1062,7 +1072,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1066 "ext/standard/var_unserializer.c" +#line 1076 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1116,7 +1126,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1120 "ext/standard/var_unserializer.c" +#line 1130 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1131,7 +1141,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1135 "ext/standard/var_unserializer.c" +#line 1145 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; #line 484 "ext/standard/var_unserializer.re" @@ -1141,7 +1151,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_NULL(*rval); return 1; } -#line 1145 "ext/standard/var_unserializer.c" +#line 1155 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1187,7 +1197,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1191 "ext/standard/var_unserializer.c" +#line 1201 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1231,9 +1241,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1235 "ext/standard/var_unserializer.c" +#line 1245 "ext/standard/var_unserializer.c" } -#line 787 "ext/standard/var_unserializer.re" +#line 797 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 4d99cbfd78944..22f853d7f17df 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -358,7 +358,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ce->name); object_init_ex(*rval, ce); - } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -773,6 +773,16 @@ object ":" uiv ":" ["] { } efree(class_name); + /* custom unserialization for non-custom objects */ + if (ce->unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + (*p) += ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } From 1402ce2c54e4eb091ce34905499fc3a98f89018c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 7 Sep 2013 18:26:50 +0100 Subject: [PATCH 03/16] Add new PHPAPI functions for unserializing object properties --- ext/standard/php_var.h | 6 ++ ext/standard/var_unserializer.c | 134 +++++++++++++++++++++++-------- ext/standard/var_unserializer.re | 74 ++++++++++++++++- 3 files changed, 178 insertions(+), 36 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 261aec730c3ab..21ba8c90624c2 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -88,8 +88,14 @@ struct php_unserialize_data { typedef struct php_unserialize_data* php_unserialize_data_t; +/* unserialize variable */ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); +/* unserialize one property (key and value) of the serialized object */ +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); + +/* unserialize all properties of the serialized object and save them to ht */ +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC); #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index e7a46a1343def..22085d62d56c2 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -411,6 +411,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -432,7 +499,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 436 "ext/standard/var_unserializer.c" +#line 503 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -492,9 +559,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 795 "ext/standard/var_unserializer.re" +#line 863 "ext/standard/var_unserializer.re" { return 0; } -#line 498 "ext/standard/var_unserializer.c" +#line 565 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -537,13 +604,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 789 "ext/standard/var_unserializer.re" +#line 857 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 547 "ext/standard/var_unserializer.c" +#line 614 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -573,7 +640,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 635 "ext/standard/var_unserializer.re" +#line 702 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -715,19 +782,20 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } efree(class_name); - /* custom unserialization for non-custom objects */ + /* custom unserialization for objects that are not custom (C: prefix) */ if (ce->unserialize) { - int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; } - (*p) += ret; + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; return finish_nested_data(UNSERIALIZE_PASSTHRU); } return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 731 "ext/standard/var_unserializer.c" +#line 799 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -752,7 +820,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 627 "ext/standard/var_unserializer.re" +#line 694 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -760,7 +828,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 764 "ext/standard/var_unserializer.c" +#line 832 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -781,7 +849,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 607 "ext/standard/var_unserializer.re" +#line 674 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -801,7 +869,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 805 "ext/standard/var_unserializer.c" +#line 873 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -822,7 +890,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 578 "ext/standard/var_unserializer.re" +#line 645 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -851,7 +919,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 855 "ext/standard/var_unserializer.c" +#line 923 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -872,7 +940,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 550 "ext/standard/var_unserializer.re" +#line 617 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -900,7 +968,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 904 "ext/standard/var_unserializer.c" +#line 972 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -988,7 +1056,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 540 "ext/standard/var_unserializer.re" +#line 607 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -998,7 +1066,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1002 "ext/standard/var_unserializer.c" +#line 1070 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1057,7 +1125,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 525 "ext/standard/var_unserializer.re" +#line 592 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -1072,7 +1140,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1076 "ext/standard/var_unserializer.c" +#line 1144 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1099,7 +1167,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 498 "ext/standard/var_unserializer.re" +#line 565 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1126,7 +1194,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1130 "ext/standard/var_unserializer.c" +#line 1198 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1134,24 +1202,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 491 "ext/standard/var_unserializer.re" +#line 558 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1145 "ext/standard/var_unserializer.c" +#line 1213 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 484 "ext/standard/var_unserializer.re" +#line 551 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1155 "ext/standard/var_unserializer.c" +#line 1223 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1174,7 +1242,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 461 "ext/standard/var_unserializer.re" +#line 528 "ext/standard/var_unserializer.re" { long id; @@ -1197,7 +1265,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1201 "ext/standard/var_unserializer.c" +#line 1269 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1220,7 +1288,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 440 "ext/standard/var_unserializer.re" +#line 507 "ext/standard/var_unserializer.re" { long id; @@ -1241,9 +1309,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1245 "ext/standard/var_unserializer.c" +#line 1313 "ext/standard/var_unserializer.c" } -#line 797 "ext/standard/var_unserializer.re" +#line 865 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 22f853d7f17df..190eb5c3258f1 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -415,6 +415,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -773,13 +840,14 @@ object ":" uiv ":" ["] { } efree(class_name); - /* custom unserialization for non-custom objects */ + /* custom unserialization for objects that are not custom (C: prefix) */ if (ce->unserialize) { - int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; } - (*p) += ret; + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; return finish_nested_data(UNSERIALIZE_PASSTHRU); } From ef668e8914be008c148091a63ff6ca9bb0da0ffc Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 8 Sep 2013 20:30:49 +0100 Subject: [PATCH 04/16] Use int when serialize bool --- ext/standard/php_var.h | 2 +- ext/standard/var.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 21ba8c90624c2..bed3aa391bb0f 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -58,7 +58,7 @@ PHPAPI void php_var_serialize_object_end(smart_str *buf); PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key); /* append boolean property */ -PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value); +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value); /* append long property */ PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value); diff --git a/ext/standard/var.c b/ext/standard/var.c index 81bb1a71d3025..2fe4d1e000c04 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -960,10 +960,10 @@ PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key) /* } /* }}} */ -PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value) /* {{{ */ +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value) /* {{{ */ { php_var_serialize_string(buf, key, strlen(key)); - php_var_serialize_bool(buf, value); + php_var_serialize_bool(buf, (long) value); } /* }}} */ From 0d81fbaef8bcd69e2be92ea92c43853cabe91a18 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 11 Sep 2013 20:21:31 +0100 Subject: [PATCH 05/16] Change vah_hash type for zval and ht serialization --- ext/standard/php_var.h | 4 ++-- ext/standard/var.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index bed3aa391bb0f..4f31e1a3e90d3 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -73,10 +73,10 @@ PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, c PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len); /* append string property zval */ -PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC); +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC); /* append properties taken from HashTable */ -PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC); +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC); struct php_unserialize_data { diff --git a/ext/standard/var.c b/ext/standard/var.c index 2fe4d1e000c04..4194873d57ccf 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -995,16 +995,16 @@ PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, } /* }}} */ -PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC) /* {{{ */ { php_var_serialize_string(buf, key, strlen(key)); - php_var_serialize_intern(buf, value, var_hash TSRMLS_CC); + php_var_serialize_intern(buf, value, (HashTable *) data TSRMLS_CC); } /* }}} */ -PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC) /* {{{ */ { - php_var_serialize_hash_table(buf, properties, NULL, 0, var_hash TSRMLS_CC); + php_var_serialize_hash_table(buf, properties, NULL, 0, (HashTable *) data TSRMLS_CC); } /* }}} */ From 1b793d6b09dac3ddc5f7aaf9e9dc9d22de9c485c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 14 Sep 2013 18:39:56 +0100 Subject: [PATCH 06/16] Use unserialize callback only for internal classes --- ext/standard/var_unserializer.c | 71 ++++++++++++++++---------------- ext/standard/var_unserializer.re | 9 ++-- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 22085d62d56c2..579d5f29c02ea 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -23,6 +23,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -201,7 +202,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 209 "ext/standard/var_unserializer.re" +#line 210 "ext/standard/var_unserializer.re" @@ -499,7 +500,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 503 "ext/standard/var_unserializer.c" +#line 504 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -559,9 +560,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 863 "ext/standard/var_unserializer.re" +#line 864 "ext/standard/var_unserializer.re" { return 0; } -#line 565 "ext/standard/var_unserializer.c" +#line 566 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -604,13 +605,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 857 "ext/standard/var_unserializer.re" +#line 858 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 614 "ext/standard/var_unserializer.c" +#line 615 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -640,7 +641,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 702 "ext/standard/var_unserializer.re" +#line 703 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -783,7 +784,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) efree(class_name); /* custom unserialization for objects that are not custom (C: prefix) */ - if (ce->unserialize) { + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; @@ -795,7 +796,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 799 "ext/standard/var_unserializer.c" +#line 800 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -820,7 +821,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 694 "ext/standard/var_unserializer.re" +#line 695 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -828,7 +829,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 832 "ext/standard/var_unserializer.c" +#line 833 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -849,7 +850,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 674 "ext/standard/var_unserializer.re" +#line 675 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -869,7 +870,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 873 "ext/standard/var_unserializer.c" +#line 874 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -890,7 +891,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 645 "ext/standard/var_unserializer.re" +#line 646 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -919,7 +920,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 923 "ext/standard/var_unserializer.c" +#line 924 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -940,7 +941,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 617 "ext/standard/var_unserializer.re" +#line 618 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -968,7 +969,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 972 "ext/standard/var_unserializer.c" +#line 973 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1056,7 +1057,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 607 "ext/standard/var_unserializer.re" +#line 608 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1066,7 +1067,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1070 "ext/standard/var_unserializer.c" +#line 1071 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1125,22 +1126,22 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 592 "ext/standard/var_unserializer.re" +#line 593 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } return 1; } -#line 1144 "ext/standard/var_unserializer.c" +#line 1145 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1167,7 +1168,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 565 "ext/standard/var_unserializer.re" +#line 566 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1194,7 +1195,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1198 "ext/standard/var_unserializer.c" +#line 1199 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1202,24 +1203,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 558 "ext/standard/var_unserializer.re" +#line 559 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1213 "ext/standard/var_unserializer.c" +#line 1214 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 551 "ext/standard/var_unserializer.re" +#line 552 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1223 "ext/standard/var_unserializer.c" +#line 1224 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1242,7 +1243,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 528 "ext/standard/var_unserializer.re" +#line 529 "ext/standard/var_unserializer.re" { long id; @@ -1265,7 +1266,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1269 "ext/standard/var_unserializer.c" +#line 1270 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1288,7 +1289,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 507 "ext/standard/var_unserializer.re" +#line 508 "ext/standard/var_unserializer.re" { long id; @@ -1309,9 +1310,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1313 "ext/standard/var_unserializer.c" +#line 1314 "ext/standard/var_unserializer.c" } -#line 865 "ext/standard/var_unserializer.re" +#line 866 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 190eb5c3258f1..7f7da7c1ecdc8 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -21,6 +21,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -593,11 +594,11 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } @@ -841,7 +842,7 @@ object ":" uiv ":" ["] { efree(class_name); /* custom unserialization for objects that are not custom (C: prefix) */ - if (ce->unserialize) { + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; From 472e08577d3726d95101b7c492d2ce26bef8d5f9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 15 Sep 2013 19:36:58 +0100 Subject: [PATCH 07/16] Add new internal serialize API --- ext/standard/php_var.h | 48 ++++++- ext/standard/var.c | 219 ++++++++++++++++++++++--------- ext/standard/var_unserializer.c | 151 ++++++++++++++++----- ext/standard/var_unserializer.re | 87 +++++++++++- 4 files changed, 403 insertions(+), 102 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index afc5f178e4fcd..a6417b5b4c3b0 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -38,8 +38,47 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC); + +#define PHP_SERIALIZE_FAILURE (FAILURE) +#define PHP_SERIALIZE_CUSTOM (SUCCESS) +#define PHP_SERIALIZE_OBJECT (SUCCESS + 1) + typedef HashTable* php_serialize_data_t; +/* serialize variable */ +PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); + +/* add object serialization string prefix */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC); + +/* append string that ends the object definition */ +PHPAPI void php_var_serialize_object_end(smart_str *buf); + +/* append null property */ +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key); + +/* append boolean property */ +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value); + +/* append long property */ +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value); + +/* append double property */ +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC); + +/* append string property */ +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value); + +/* append string property */ +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len); + +/* append string property zval */ +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC); + +/* append properties taken from HashTable */ +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC); + + struct php_unserialize_data { void *first; void *last; @@ -49,9 +88,16 @@ struct php_unserialize_data { typedef struct php_unserialize_data* php_unserialize_data_t; -PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); +/* unserialize variable */ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); +/* unserialize one property (key and value) of the serialized object */ +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); + +/* unserialize all properties of the serialized object and save them to ht */ +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC); + + #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ do { \ /* fprintf(stderr, "SERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */ \ diff --git a/ext/standard/var.c b/ext/standard/var.c index c1e7c2f3ee346..4194873d57ccf 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -584,6 +584,20 @@ static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old } /* }}} */ +static inline void php_var_serialize_null(smart_str *buf) /* {{{ */ +{ + smart_str_appendl(buf, "N;", 2); +} +/* }}} */ + +static inline void php_var_serialize_bool(smart_str *buf, long val) /* {{{ */ +{ + smart_str_appendl(buf, "b:", 2); + smart_str_append_long(buf, val); + smart_str_appendc(buf, ';'); +} +/* }}} */ + static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ { smart_str_appendl(buf, "i:", 2); @@ -592,7 +606,21 @@ static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ } /* }}} */ -static inline void php_var_serialize_string(smart_str *buf, char *str, int len) /* {{{ */ +static inline void php_var_serialize_double(smart_str *buf, double val TSRMLS_DC) /* {{{ */ +{ + char *s; + + smart_str_appendl(buf, "d:", 2); + s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); + php_gcvt(val, PG(serialize_precision), '.', 'E', s); + smart_str_appends(buf, s); + smart_str_appendc(buf, ';'); + efree(s); + return; +} +/* }}} */ + +static inline void php_var_serialize_string(smart_str *buf, const char *str, int len) /* {{{ */ { smart_str_appendl(buf, "s:", 2); smart_str_append_long(buf, len); @@ -602,6 +630,55 @@ static inline void php_var_serialize_string(smart_str *buf, char *str, int len) } /* }}} */ +static inline void php_var_serialize_hash_table(smart_str *buf, HashTable *myht, zval **pstruc, zend_bool incomplete_class, HashTable *var_hash TSRMLS_DC) /* {{{ */ +{ + int i; + char *key; + zval **data; + ulong index; + uint key_len; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(myht, &pos); + for (;; zend_hash_move_forward_ex(myht, &pos)) { + i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); + if (i == HASH_KEY_NON_EXISTENT) { + break; + } + if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { + continue; + } + + switch (i) { + case HASH_KEY_IS_LONG: + php_var_serialize_long(buf, index); + break; + case HASH_KEY_IS_STRING: + php_var_serialize_string(buf, key, key_len - 1); + break; + } + + /* we should still add element even if it's not OK, + * since we already wrote the length of the array before */ + if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS + || !data + || data == pstruc + || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) + ) { + smart_str_appendl(buf, "N;", 2); + } else { + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount++; + } + php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount--; + } + } + } +} +/* }}} */ + static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc TSRMLS_DC) /* {{{ */ { PHP_CLASS_ATTRIBUTES; @@ -734,30 +811,20 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var switch (Z_TYPE_P(struc)) { case IS_BOOL: - smart_str_appendl(buf, "b:", 2); - smart_str_append_long(buf, Z_LVAL_P(struc)); - smart_str_appendc(buf, ';'); + php_var_serialize_bool(buf, Z_LVAL_P(struc)); return; case IS_NULL: - smart_str_appendl(buf, "N;", 2); + php_var_serialize_null(buf); return; case IS_LONG: php_var_serialize_long(buf, Z_LVAL_P(struc)); return; - case IS_DOUBLE: { - char *s; - - smart_str_appendl(buf, "d:", 2); - s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); - php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s); - smart_str_appends(buf, s); - smart_str_appendc(buf, ';'); - efree(s); - return; - } + case IS_DOUBLE: + php_var_serialize_double(buf, Z_DVAL_P(struc) TSRMLS_CC); + return; case IS_STRING: php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc)); @@ -766,7 +833,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var case IS_OBJECT: { zval *retval_ptr = NULL; zval fname; - int res; + int res, serialize_rc; zend_class_entry *ce = NULL; if (Z_OBJ_HT_P(struc)->get_class_entry) { @@ -778,7 +845,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var unsigned char *serialized_data = NULL; zend_uint serialized_length; - if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC) == SUCCESS) { + serialize_rc = ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC); + if (serialize_rc == PHP_SERIALIZE_CUSTOM) { smart_str_appendl(buf, "C:", 2); smart_str_append_long(buf, (int)Z_OBJCE_P(struc)->name_length); smart_str_appendl(buf, ":\"", 2); @@ -789,6 +857,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_appendl(buf, ":{", 2); smart_str_appendl(buf, serialized_data, serialized_length); smart_str_appendc(buf, '}'); + } else if (serialize_rc == PHP_SERIALIZE_OBJECT) { + smart_str_appendl(buf, serialized_data, serialized_length); } else { smart_str_appendl(buf, "N;", 2); } @@ -851,49 +921,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_append_long(buf, i); smart_str_appendl(buf, ":{", 2); if (i > 0) { - char *key; - zval **data; - ulong index; - uint key_len; - HashPosition pos; - - zend_hash_internal_pointer_reset_ex(myht, &pos); - for (;; zend_hash_move_forward_ex(myht, &pos)) { - i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); - if (i == HASH_KEY_NON_EXISTENT) { - break; - } - if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { - continue; - } - - switch (i) { - case HASH_KEY_IS_LONG: - php_var_serialize_long(buf, index); - break; - case HASH_KEY_IS_STRING: - php_var_serialize_string(buf, key, key_len - 1); - break; - } - - /* we should still add element even if it's not OK, - * since we already wrote the length of the array before */ - if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS - || !data - || data == &struc - || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) - ) { - smart_str_appendl(buf, "N;", 2); - } else { - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount++; - } - php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount--; - } - } - } + php_var_serialize_hash_table(buf, myht, &struc, incomplete_class, var_hash TSRMLS_CC); } smart_str_appendc(buf, '}'); return; @@ -912,6 +940,75 @@ PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t } /* }}} */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_class_name(buf, object TSRMLS_CC); + smart_str_append_long(buf, nprops); + smart_str_appendl(buf, ":{", 2); +} +/* }}} */ + +PHPAPI void php_var_serialize_object_end(smart_str *buf) /* {{{ */ +{ + smart_str_appendc(buf, '}'); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_bool(buf, (long) value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_long(buf, value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_double(buf, value TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, strlen(value)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, value_len); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_intern(buf, value, (HashTable *) data TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_hash_table(buf, properties, NULL, 0, (HashTable *) data TSRMLS_CC); +} +/* }}} */ + + /* {{{ proto string serialize(mixed variable) Returns a string representation of variable (which can later be unserialized) */ PHP_FUNCTION(serialize) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index f7546428b1e61..d8ace9591ceab 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 */ +/* Generated by re2c 0.13.6 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -23,6 +23,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -226,7 +227,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 234 "ext/standard/var_unserializer.re" +#line 235 "ext/standard/var_unserializer.re" @@ -379,7 +380,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ce->name); object_init_ex(*rval, ce); - } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -436,6 +437,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -457,7 +525,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 461 "ext/standard/var_unserializer.c" +#line 529 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -517,9 +585,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 812 "ext/standard/var_unserializer.re" +#line 891 "ext/standard/var_unserializer.re" { return 0; } -#line 523 "ext/standard/var_unserializer.c" +#line 591 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -562,13 +630,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 806 "ext/standard/var_unserializer.re" +#line 885 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 572 "ext/standard/var_unserializer.c" +#line 640 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -598,7 +666,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 660 "ext/standard/var_unserializer.re" +#line 728 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -742,9 +810,20 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } efree(class_name); + /* custom unserialization for objects that are not custom (C: prefix) */ + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 748 "ext/standard/var_unserializer.c" +#line 827 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -769,7 +848,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 652 "ext/standard/var_unserializer.re" +#line 720 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -777,7 +856,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 781 "ext/standard/var_unserializer.c" +#line 860 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -798,7 +877,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 632 "ext/standard/var_unserializer.re" +#line 700 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -818,7 +897,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 822 "ext/standard/var_unserializer.c" +#line 901 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -839,7 +918,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 603 "ext/standard/var_unserializer.re" +#line 671 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -868,7 +947,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 872 "ext/standard/var_unserializer.c" +#line 951 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -889,7 +968,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 575 "ext/standard/var_unserializer.re" +#line 643 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -917,7 +996,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 921 "ext/standard/var_unserializer.c" +#line 1000 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1005,7 +1084,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 565 "ext/standard/var_unserializer.re" +#line 633 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1015,7 +1094,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1019 "ext/standard/var_unserializer.c" +#line 1098 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1074,22 +1153,22 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 550 "ext/standard/var_unserializer.re" +#line 618 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } return 1; } -#line 1093 "ext/standard/var_unserializer.c" +#line 1172 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1116,7 +1195,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 523 "ext/standard/var_unserializer.re" +#line 591 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1143,7 +1222,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1147 "ext/standard/var_unserializer.c" +#line 1226 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1151,24 +1230,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 516 "ext/standard/var_unserializer.re" +#line 584 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1162 "ext/standard/var_unserializer.c" +#line 1241 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 509 "ext/standard/var_unserializer.re" +#line 577 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1172 "ext/standard/var_unserializer.c" +#line 1251 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1191,7 +1270,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 486 "ext/standard/var_unserializer.re" +#line 554 "ext/standard/var_unserializer.re" { long id; @@ -1214,7 +1293,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1218 "ext/standard/var_unserializer.c" +#line 1297 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1237,7 +1316,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 465 "ext/standard/var_unserializer.re" +#line 533 "ext/standard/var_unserializer.re" { long id; @@ -1258,9 +1337,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1262 "ext/standard/var_unserializer.c" +#line 1341 "ext/standard/var_unserializer.c" } -#line 814 "ext/standard/var_unserializer.re" +#line 893 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 76c501e1b58c9..0727077a3b7e9 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -21,6 +21,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -383,7 +384,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ce->name); object_init_ex(*rval, ce); - } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -440,6 +441,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -551,11 +619,11 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } @@ -800,6 +868,17 @@ object ":" uiv ":" ["] { } efree(class_name); + /* custom unserialization for objects that are not custom (C: prefix) */ + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } From cddd10f61a965268bd17a634a56e223b9f8b335a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 20 Sep 2013 21:10:15 +0100 Subject: [PATCH 08/16] Use new serialization API for DateTime --- ext/date/php_date.c | 81 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 7d3d1d739e113..295b7cff25684 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -26,6 +26,7 @@ #include "ext/standard/info.h" #include "ext/standard/php_versioning.h" #include "ext/standard/php_math.h" +#include "ext/standard/php_var.h" #include "php_date.h" #include "zend_interfaces.h" #include "lib/timelib.h" @@ -623,9 +624,11 @@ static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC); static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC); static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC); +static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC); + static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_DC); -static HashTable *date_object_get_properties(zval *object TSRMLS_DC); +static HashTable *date_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC); static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int *n TSRMLS_DC); static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC); @@ -1989,11 +1992,12 @@ static void date_register_classes(TSRMLS_D) INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date); ce_date.create_object = date_object_new_date; + ce_date.serialize = date_object_serialize; date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_date.clone_obj = date_object_clone_date; date_object_handlers_date.compare_objects = date_object_compare_date; - date_object_handlers_date.get_properties = date_object_get_properties; + date_object_handlers_date.get_debug_info = date_object_get_debug_info; date_object_handlers_date.get_gc = date_object_get_gc; zend_class_implements(date_ce_date TSRMLS_CC, 1, date_ce_interface); @@ -2014,11 +2018,12 @@ static void date_register_classes(TSRMLS_D) INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable); ce_immutable.create_object = date_object_new_date; + ce_immutable.serialize = date_object_serialize; date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_immutable, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_immutable.clone_obj = date_object_clone_date; date_object_handlers_immutable.compare_objects = date_object_compare_date; - date_object_handlers_immutable.get_properties = date_object_get_properties; + date_object_handlers_immutable.get_debug_info = date_object_get_debug_info; zend_class_implements(date_ce_immutable TSRMLS_CC, 1, date_ce_interface); INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone); @@ -2174,16 +2179,17 @@ static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int * return zend_std_get_properties(object TSRMLS_CC); } -static HashTable *date_object_get_properties(zval *object TSRMLS_DC) +static HashTable *date_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC) { HashTable *props; zval *zv; - php_date_obj *dateobj; - + php_date_obj *dateobj; dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - props = zend_std_get_properties(object TSRMLS_CC); + ALLOC_HASHTABLE(props); + zend_hash_init(props, 3, NULL, ZVAL_PTR_DTOR, 0); + *is_temp = 1; if (!dateobj->time || GC_G(gc_active)) { return props; @@ -2191,14 +2197,14 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC) /* first we add the date and time in ISO format */ MAKE_STD_ZVAL(zv); - ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, dateobj->time, 1), 0); - zend_hash_update(props, "date", 5, &zv, sizeof(zv), NULL); + ZVAL_STRING(zv, date_format("Y-m-d H:i:s", sizeof("Y-m-d H:i:s"), dateobj->time, 1), 0); + zend_hash_update(props, "date", sizeof("date"), &zv, sizeof(zv), NULL); /* then we add the timezone name (or similar) */ if (dateobj->time->is_localtime) { MAKE_STD_ZVAL(zv); ZVAL_LONG(zv, dateobj->time->zone_type); - zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zv), NULL); + zend_hash_update(props, "timezone_type", sizeof("timezone_type"), &zv, sizeof(zv), NULL); MAKE_STD_ZVAL(zv); switch (dateobj->time->zone_type) { @@ -2227,6 +2233,61 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC) return props; } +static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) +{ + char *format; + php_date_obj *dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); + smart_str buf = {0}; + + if (!dateobj->time) { + php_var_serialize_object_start(&buf, object, 0 TSRMLS_CC); + php_var_serialize_object_end(&buf); + goto date_serialize_end; + } + + format = date_format("Y-m-d H:i:s", sizeof("Y-m-d H:i:s"), dateobj->time, 1); + if (dateobj->time->is_localtime) { + php_var_serialize_object_start(&buf, object, 3 TSRMLS_CC); + php_var_serialize_property_string(&buf, "date", format); + php_var_serialize_property_long(&buf, "timezone_type", dateobj->time->zone_type); + switch (dateobj->time->zone_type) { + case TIMELIB_ZONETYPE_ID: + php_var_serialize_property_string(&buf, "timezone", dateobj->time->tz_info->name); + break; + case TIMELIB_ZONETYPE_OFFSET: { + char *tmpstr = emalloc(sizeof("UTC+05:00")); + timelib_sll utc_offset = dateobj->time->z; + + snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", + utc_offset > 0 ? '-' : '+', + abs(utc_offset / 60), + abs((utc_offset % 60))); + + php_var_serialize_property_string(&buf, "timezone", tmpstr); + efree(tmpstr); + } + break; + case TIMELIB_ZONETYPE_ABBR: + php_var_serialize_property_string(&buf, "timezone", dateobj->time->tz_abbr); + break; + } + php_var_serialize_object_end(&buf); + } else { + php_var_serialize_object_start(&buf, object, 1 TSRMLS_CC); + php_var_serialize_property_string(&buf, "date", format); + php_var_serialize_object_end(&buf); + } + efree(format); + +date_serialize_end: + smart_str_0(&buf); + *buffer = (unsigned char *) buf.c; + *buf_len = buf.len; + + return PHP_SERIALIZE_OBJECT; +} + + static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC) { php_timezone_obj *intern; From 52adc07a310ec488778c07c80c37b4f75459b7be Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 21 Sep 2013 17:17:57 +0100 Subject: [PATCH 09/16] Implement serialization and debug for DateTime user defined properties --- ext/date/php_date.c | 47 ++++++++++++++--------- ext/date/tests/DateTime_clone_basic2.phpt | 24 ++++++------ ext/date/tests/DateTime_serialize.phpt | 38 ++++++++++++++++++ 3 files changed, 78 insertions(+), 31 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 295b7cff25684..1ad74909944dc 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2181,30 +2181,30 @@ static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int * static HashTable *date_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC) { - HashTable *props; - zval *zv; + HashTable *debug_props, *object_props; + zval *zv, *tmp; php_date_obj *dateobj; dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - ALLOC_HASHTABLE(props); - zend_hash_init(props, 3, NULL, ZVAL_PTR_DTOR, 0); + ALLOC_HASHTABLE(debug_props); + zend_hash_init(debug_props, 3, NULL, ZVAL_PTR_DTOR, 0); *is_temp = 1; if (!dateobj->time || GC_G(gc_active)) { - return props; + return debug_props; } /* first we add the date and time in ISO format */ MAKE_STD_ZVAL(zv); ZVAL_STRING(zv, date_format("Y-m-d H:i:s", sizeof("Y-m-d H:i:s"), dateobj->time, 1), 0); - zend_hash_update(props, "date", sizeof("date"), &zv, sizeof(zv), NULL); + zend_hash_update(debug_props, "date", sizeof("date"), &zv, sizeof(zv), NULL); /* then we add the timezone name (or similar) */ if (dateobj->time->is_localtime) { MAKE_STD_ZVAL(zv); ZVAL_LONG(zv, dateobj->time->zone_type); - zend_hash_update(props, "timezone_type", sizeof("timezone_type"), &zv, sizeof(zv), NULL); + zend_hash_update(debug_props, "timezone_type", sizeof("timezone_type"), &zv, sizeof(zv), NULL); MAKE_STD_ZVAL(zv); switch (dateobj->time->zone_type) { @@ -2227,28 +2227,39 @@ static HashTable *date_object_get_debug_info(zval *object, int *is_temp TSRMLS_D ZVAL_STRING(zv, dateobj->time->tz_abbr, 1); break; } - zend_hash_update(props, "timezone", 9, &zv, sizeof(zv), NULL); + zend_hash_update(debug_props, "timezone", sizeof("timezone"), &zv, sizeof(zv), NULL); } - return props; + /* merge debug props with object props */ + object_props = zend_std_get_properties(object TSRMLS_CC); + zend_hash_merge(debug_props, object_props, (void (*)(void *pData)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); + + return debug_props; } static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) { + HashTable *object_props; + int object_props_num; char *format; php_date_obj *dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); smart_str buf = {0}; + object_props = zend_std_get_properties(object TSRMLS_CC); + object_props_num = zend_hash_num_elements(object_props); + if (!dateobj->time) { - php_var_serialize_object_start(&buf, object, 0 TSRMLS_CC); - php_var_serialize_object_end(&buf); + php_var_serialize_object_start(&buf, object, object_props_num TSRMLS_CC); goto date_serialize_end; } + php_var_serialize_object_start(&buf, object, (object_props_num + (dateobj->time->is_localtime ? 3 : 1)) TSRMLS_CC); + format = date_format("Y-m-d H:i:s", sizeof("Y-m-d H:i:s"), dateobj->time, 1); + php_var_serialize_property_string(&buf, "date", format); + efree(format); + if (dateobj->time->is_localtime) { - php_var_serialize_object_start(&buf, object, 3 TSRMLS_CC); - php_var_serialize_property_string(&buf, "date", format); php_var_serialize_property_long(&buf, "timezone_type", dateobj->time->zone_type); switch (dateobj->time->zone_type) { case TIMELIB_ZONETYPE_ID: @@ -2271,15 +2282,13 @@ static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint php_var_serialize_property_string(&buf, "timezone", dateobj->time->tz_abbr); break; } - php_var_serialize_object_end(&buf); - } else { - php_var_serialize_object_start(&buf, object, 1 TSRMLS_CC); - php_var_serialize_property_string(&buf, "date", format); - php_var_serialize_object_end(&buf); } - efree(format); date_serialize_end: + if (object_props_num > 0) { + php_var_serialize_properties(&buf, object_props, data TSRMLS_CC); + } + php_var_serialize_object_end(&buf); smart_str_0(&buf); *buffer = (unsigned char *) buf.c; *buf_len = buf.len; diff --git a/ext/date/tests/DateTime_clone_basic2.phpt b/ext/date/tests/DateTime_clone_basic2.phpt index db7ba2271939b..c12f3e4a3cf9d 100644 --- a/ext/date/tests/DateTime_clone_basic2.phpt +++ b/ext/date/tests/DateTime_clone_basic2.phpt @@ -32,30 +32,36 @@ var_dump($d2_clone); --EXPECTF-- *** Testing clone on objects whoose class derived from DateTime class *** object(DateTimeExt1)#%d (5) { + ["date"]=> + string(19) "2009-02-03 12:34:41" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(3) "GMT" ["property1"]=> int(99) ["property2"]=> string(5) "Hello" +} +object(DateTimeExt1)#%d (5) { ["date"]=> string(19) "2009-02-03 12:34:41" ["timezone_type"]=> int(2) ["timezone"]=> string(3) "GMT" -} -object(DateTimeExt1)#%d (5) { ["property1"]=> int(99) ["property2"]=> string(5) "Hello" +} +object(DateTimeExt2)#%d (7) { ["date"]=> string(19) "2009-02-03 12:34:41" ["timezone_type"]=> int(2) ["timezone"]=> string(3) "GMT" -} -object(DateTimeExt2)#%d (7) { ["property3"]=> bool(true) ["property4"]=> @@ -64,14 +70,14 @@ object(DateTimeExt2)#%d (7) { int(99) ["property2"]=> string(5) "Hello" +} +object(DateTimeExt2)#%d (7) { ["date"]=> string(19) "2009-02-03 12:34:41" ["timezone_type"]=> int(2) ["timezone"]=> string(3) "GMT" -} -object(DateTimeExt2)#%d (7) { ["property3"]=> bool(true) ["property4"]=> @@ -80,11 +86,5 @@ object(DateTimeExt2)#%d (7) { int(99) ["property2"]=> string(5) "Hello" - ["date"]=> - string(19) "2009-02-03 12:34:41" - ["timezone_type"]=> - int(2) - ["timezone"]=> - string(3) "GMT" } ===DONE=== diff --git a/ext/date/tests/DateTime_serialize.phpt b/ext/date/tests/DateTime_serialize.phpt index ff827360fb7fc..a7d3ba6337bb1 100644 --- a/ext/date/tests/DateTime_serialize.phpt +++ b/ext/date/tests/DateTime_serialize.phpt @@ -15,6 +15,18 @@ var_dump($date2); // Try to use unserialzied object var_dump( $date2->format( "F j, Y, g:i a") ); +$date3 = new DateTime("2013-09-22 16:43:23"); +$date3->name_day = "Darina"; +$date3->value = 23; +var_dump($date3); +$serialized = serialize($date3); +var_dump($serialized); + +$date4 = unserialize($serialized); +var_dump($date4); +// Try to use unserialzied object +var_dump( $date4->format( "F j, Y, g:i a") ); + ?> ===DONE=== --EXPECTF-- @@ -36,4 +48,30 @@ object(DateTime)#%d (3) { string(13) "Europe/London" } string(23) "July 14, 2005, 10:30 pm" +object(DateTime)#%d (5) { + ["date"]=> + string(19) "2013-09-22 16:43:23" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" + ["name_day"]=> + string(6) "Darina" + ["value"]=> + int(23) +} +string(163) "O:8:"DateTime":5:{s:4:"date";s:19:"2013-09-22 16:43:23";s:13:"timezone_type";i:3;s:8:"timezone";s:13:"Europe/London";s:8:"name_day";s:6:"Darina";s:5:"value";i:23;}" +object(DateTime)#%d (5) { + ["date"]=> + string(19) "2013-09-22 16:43:23" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" + ["name_day"]=> + string(6) "Darina" + ["value"]=> + int(23) +} +string(27) "September 22, 2013, 4:43 pm" ===DONE=== \ No newline at end of file From d6a3de3e6b0331b2ece940dbf1b81ee9219d14cc Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 22 Sep 2013 17:58:32 +0100 Subject: [PATCH 10/16] Add DateTime write property handler to prohibit redefining internal properties --- ext/date/php_date.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 1ad74909944dc..173e189b5e12f 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -626,6 +626,7 @@ static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC); static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC); +static void date_object_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_DC); static HashTable *date_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC); @@ -1995,6 +1996,7 @@ static void date_register_classes(TSRMLS_D) ce_date.serialize = date_object_serialize; date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + date_object_handlers_date.write_property = date_object_write_property; date_object_handlers_date.clone_obj = date_object_clone_date; date_object_handlers_date.compare_objects = date_object_compare_date; date_object_handlers_date.get_debug_info = date_object_get_debug_info; @@ -2145,6 +2147,19 @@ static zval* date_clone_immutable(zval *object TSRMLS_DC) return new_object; } +static void date_object_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) +{ + if (Z_TYPE_P(member) == IS_STRING && + (!strcmp(Z_STRVAL_P(member), "date") || + !strcmp(Z_STRVAL_P(member), "timezone") || + !strcmp(Z_STRVAL_P(member), "timezone_type"))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Redefining internal property '%s' is not allowed", Z_STRVAL_P(member)); + return; + } + zend_std_write_property(object, member, value, key TSRMLS_CC); +} + + static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC) { php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC); From 825f7f313b618b3a48fc180d7203fb55c26146cb Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 5 Oct 2013 17:58:50 +0100 Subject: [PATCH 11/16] Add php_var_unserialize_has_properties to find out the end of unserialized string --- ext/standard/php_var.h | 8 ++- ext/standard/var_unserializer.c | 103 ++++++++++++++++--------------- ext/standard/var_unserializer.re | 43 +++++++------ 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index a6417b5b4c3b0..78727d3923038 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -91,12 +91,14 @@ typedef struct php_unserialize_data* php_unserialize_data_t; /* unserialize variable */ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); -/* unserialize one property (key and value) of the serialized object */ -PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); +/* whether unserialization finished */ +PHPAPI int php_var_unserialize_has_properties(const unsigned char *buf, zend_uint buf_len); /* unserialize all properties of the serialized object and save them to ht */ -PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC); +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); +/* unserialize one property (key and value) of the serialized object */ +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ do { \ diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index d8ace9591ceab..3d1b8e4a7bec2 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -437,32 +437,18 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_has_properties(const unsigned char *buf, zend_uint buf_len) { - const unsigned char *max; - - max = *buf + *buf_len; - - if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { - zval_dtor(key); - return 0; - } - if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { - zval_dtor(key); - zval_dtor(value); - return 0; - } - *buf_len = max - *buf; - return 1; + return buf_len && *buf != '}'; } -PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) { const unsigned char *max; max = *buf + *buf_len; - while (elements-- > 0) { + while (php_var_unserialize_has_properties(*buf, *buf_len)) { zval *key, *value; ALLOC_INIT_ZVAL(key); @@ -494,7 +480,7 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b zval_dtor(key); FREE_ZVAL(key); - if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + if (php_var_unserialize_has_properties(*buf, *buf_len) && *(*buf-1) != ';' && *(*buf-1) != '}') { (*buf)--; return 0; } @@ -504,6 +490,25 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b return 1; } +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -525,7 +530,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 529 "ext/standard/var_unserializer.c" +#line 534 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -585,9 +590,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 891 "ext/standard/var_unserializer.re" +#line 896 "ext/standard/var_unserializer.re" { return 0; } -#line 591 "ext/standard/var_unserializer.c" +#line 596 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -630,13 +635,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 885 "ext/standard/var_unserializer.re" +#line 890 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 640 "ext/standard/var_unserializer.c" +#line 645 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -666,7 +671,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 728 "ext/standard/var_unserializer.re" +#line 733 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -823,7 +828,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 827 "ext/standard/var_unserializer.c" +#line 832 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -848,7 +853,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 720 "ext/standard/var_unserializer.re" +#line 725 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -856,7 +861,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 860 "ext/standard/var_unserializer.c" +#line 865 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -877,7 +882,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 700 "ext/standard/var_unserializer.re" +#line 705 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -897,7 +902,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 901 "ext/standard/var_unserializer.c" +#line 906 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -918,7 +923,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 671 "ext/standard/var_unserializer.re" +#line 676 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -947,7 +952,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 951 "ext/standard/var_unserializer.c" +#line 956 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -968,7 +973,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 643 "ext/standard/var_unserializer.re" +#line 648 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -996,7 +1001,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 1000 "ext/standard/var_unserializer.c" +#line 1005 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1084,7 +1089,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 633 "ext/standard/var_unserializer.re" +#line 638 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1094,7 +1099,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1098 "ext/standard/var_unserializer.c" +#line 1103 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1153,7 +1158,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 618 "ext/standard/var_unserializer.re" +#line 623 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -1168,7 +1173,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1172 "ext/standard/var_unserializer.c" +#line 1177 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1195,7 +1200,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 591 "ext/standard/var_unserializer.re" +#line 596 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1222,7 +1227,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1226 "ext/standard/var_unserializer.c" +#line 1231 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1230,24 +1235,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 584 "ext/standard/var_unserializer.re" +#line 589 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1241 "ext/standard/var_unserializer.c" +#line 1246 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 577 "ext/standard/var_unserializer.re" +#line 582 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1251 "ext/standard/var_unserializer.c" +#line 1256 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1270,7 +1275,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 554 "ext/standard/var_unserializer.re" +#line 559 "ext/standard/var_unserializer.re" { long id; @@ -1293,7 +1298,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1297 "ext/standard/var_unserializer.c" +#line 1302 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1316,7 +1321,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 533 "ext/standard/var_unserializer.re" +#line 538 "ext/standard/var_unserializer.re" { long id; @@ -1337,9 +1342,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1341 "ext/standard/var_unserializer.c" +#line 1346 "ext/standard/var_unserializer.c" } -#line 893 "ext/standard/var_unserializer.re" +#line 898 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 0727077a3b7e9..45914bf50418d 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -441,32 +441,18 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_has_properties(const unsigned char *buf, zend_uint buf_len) { - const unsigned char *max; - - max = *buf + *buf_len; - - if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { - zval_dtor(key); - return 0; - } - if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { - zval_dtor(key); - zval_dtor(value); - return 0; - } - *buf_len = max - *buf; - return 1; + return buf_len && *buf != '}'; } -PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) { const unsigned char *max; max = *buf + *buf_len; - while (elements-- > 0) { + while (php_var_unserialize_has_properties(*buf, *buf_len)) { zval *key, *value; ALLOC_INIT_ZVAL(key); @@ -498,7 +484,7 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b zval_dtor(key); FREE_ZVAL(key); - if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + if (php_var_unserialize_has_properties(*buf, *buf_len) && *(*buf-1) != ';' && *(*buf-1) != '}') { (*buf)--; return 0; } @@ -508,6 +494,25 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b return 1; } +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; From ee2f79ac4768aea8b9bf092716044c75e17fa2b0 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 13 Oct 2013 16:29:27 +0100 Subject: [PATCH 12/16] Use debug properties in var_export --- ext/standard/var.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ext/standard/var.c b/ext/standard/var.c index 01020dc0d71dc..9f9cd65f3450a 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -420,6 +420,7 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) int tmp_len, tmp_len2; const char *class_name; zend_uint class_name_len; + int is_temp; switch (Z_TYPE_PP(struc)) { case IS_BOOL: @@ -473,7 +474,7 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) break; case IS_OBJECT: - myht = Z_OBJPROP_PP(struc); + myht = Z_OBJDEBUG_PP(struc, is_temp); if(myht && myht->nApplyCount > 0){ smart_str_appendl(buf, "NULL", 4); zend_error(E_WARNING, "var_export does not handle circular references"); @@ -491,6 +492,11 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) efree((char*)class_name); if (myht) { zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_object_element_export, 1, level, buf); + + if (is_temp) { + zend_hash_destroy(myht); + efree(myht); + } } if (level > 1) { buffer_append_spaces(buf, level - 1); From 9b876850663be8dca0f98b66f9b382de5b42d785 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 18 Oct 2013 20:09:56 +0100 Subject: [PATCH 13/16] Replace DateTime __wakeup with unserialize (not tested) --- ext/date/php_date.c | 148 +++++++++++++++++++++++--------------------- ext/date/php_date.h | 1 - 2 files changed, 76 insertions(+), 73 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 173e189b5e12f..cacd560501304 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -457,7 +457,6 @@ static const zend_function_entry date_funcs_interface[] = { const zend_function_entry date_funcs_date[] = { PHP_ME(DateTime, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) - PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC) PHP_ME(DateTime, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(createFromFormat, date_create_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) @@ -479,7 +478,6 @@ const zend_function_entry date_funcs_date[] = { const zend_function_entry date_funcs_immutable[] = { PHP_ME(DateTimeImmutable, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) - PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC) PHP_ME(DateTimeImmutable, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(createFromFormat, date_create_immutable_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) @@ -625,6 +623,7 @@ static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC); static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC); static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC); +static int date_object_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC); static void date_object_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); @@ -1994,6 +1993,7 @@ static void date_register_classes(TSRMLS_D) INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date); ce_date.create_object = date_object_new_date; ce_date.serialize = date_object_serialize; + ce_date.unserialize = date_object_unserialize; date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_date.write_property = date_object_write_property; @@ -2021,6 +2021,7 @@ static void date_register_classes(TSRMLS_D) INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable); ce_immutable.create_object = date_object_new_date; ce_immutable.serialize = date_object_serialize; + ce_immutable.unserialize = date_object_unserialize; date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_immutable, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_immutable.clone_obj = date_object_clone_date; @@ -2311,6 +2312,77 @@ static int date_object_serialize(zval *object, unsigned char **buffer, zend_uint return PHP_SERIALIZE_OBJECT; } +static int date_object_initialize_from_hash(php_date_obj *dateobj, HashTable *myht TSRMLS_DC) +{ + zval **z_date = NULL; + zval **z_timezone = NULL; + zval **z_timezone_type = NULL; + zval *tmp_obj = NULL; + timelib_tzinfo *tzi; + php_timezone_obj *tzobj; + + if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) { + convert_to_string(*z_date); + if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { + convert_to_long(*z_timezone_type); + if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { + convert_to_string(*z_timezone); + + switch (Z_LVAL_PP(z_timezone_type)) { + case TIMELIB_ZONETYPE_OFFSET: + case TIMELIB_ZONETYPE_ABBR: { + char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2); + int ret; + snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone)); + ret = php_date_initialize(dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC); + efree(tmp); + return 1 == ret; + } + + case TIMELIB_ZONETYPE_ID: { + int ret; + convert_to_string(*z_timezone); + + tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC); + + ALLOC_INIT_ZVAL(tmp_obj); + tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC); + tzobj->type = TIMELIB_ZONETYPE_ID; + tzobj->tzi.tz = tzi; + tzobj->initialized = 1; + + ret = php_date_initialize(dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC); + zval_ptr_dtor(&tmp_obj); + return 1 == ret; + } + } + } + } + } + return 0; +} + +static int date_object_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + HashTable *ht; + php_date_obj *dateobj; + int retval; + + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 3, NULL, ZVAL_PTR_DTOR, 0); + + if (php_var_unserialize_properties(ht, &buf, &buf_len, data TSRMLS_CC)) { + dateobj = (php_date_obj *) zend_object_store_get_object(*object TSRMLS_CC); + date_object_initialize_from_hash(dateobj, ht TSRMLS_CC); + retval = (int) buf_len; + } else { + retval = -1; + } + + zend_hash_destroy(ht); + FREE_HASHTABLE(ht); + return retval; +} static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC) { @@ -2810,56 +2882,6 @@ PHP_METHOD(DateTimeImmutable, __construct) } /* }}} */ -static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC) -{ - zval **z_date = NULL; - zval **z_timezone = NULL; - zval **z_timezone_type = NULL; - zval *tmp_obj = NULL; - timelib_tzinfo *tzi; - php_timezone_obj *tzobj; - - if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) { - convert_to_string(*z_date); - if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { - convert_to_long(*z_timezone_type); - if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { - convert_to_string(*z_timezone); - - switch (Z_LVAL_PP(z_timezone_type)) { - case TIMELIB_ZONETYPE_OFFSET: - case TIMELIB_ZONETYPE_ABBR: { - char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2); - int ret; - snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone)); - ret = php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC); - efree(tmp); - return 1 == ret; - } - - case TIMELIB_ZONETYPE_ID: { - int ret; - convert_to_string(*z_timezone); - - tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC); - - ALLOC_INIT_ZVAL(tmp_obj); - tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC); - tzobj->type = TIMELIB_ZONETYPE_ID; - tzobj->tzi.tz = tzi; - tzobj->initialized = 1; - - ret = php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC); - zval_ptr_dtor(&tmp_obj); - return 1 == ret; - } - } - } - } - } - return 0; -} - /* {{{ proto DateTime::__set_state() */ PHP_METHOD(DateTime, __set_state) @@ -2876,7 +2898,7 @@ PHP_METHOD(DateTime, __set_state) php_date_instantiate(date_ce_date, return_value TSRMLS_CC); dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC); - if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) { + if (!date_object_initialize_from_hash(dateobj, myht TSRMLS_CC)) { php_error(E_ERROR, "Invalid serialization data for DateTime object"); } } @@ -2898,30 +2920,12 @@ PHP_METHOD(DateTimeImmutable, __set_state) php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC); dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC); - if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) { + if (!date_object_initialize_from_hash(dateobj, myht TSRMLS_CC)) { php_error(E_ERROR, "Invalid serialization data for DateTimeImmutable object"); } } /* }}} */ -/* {{{ proto DateTime::__wakeup() -*/ -PHP_METHOD(DateTime, __wakeup) -{ - zval *object = getThis(); - php_date_obj *dateobj; - HashTable *myht; - - dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - - myht = Z_OBJPROP_P(object); - - if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) { - php_error(E_ERROR, "Invalid serialization data for DateTime object"); - } -} -/* }}} */ - /* Helper function used to add an associative array of warnings and errors to a zval */ static void zval_from_error_container(zval *z, timelib_error_container *error) { diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 536629a25fa64..1c3accaaff279 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -48,7 +48,6 @@ PHP_FUNCTION(getdate); /* Advanced Interface */ PHP_METHOD(DateTime, __construct); -PHP_METHOD(DateTime, __wakeup); PHP_METHOD(DateTime, __set_state); PHP_FUNCTION(date_create); PHP_FUNCTION(date_create_immutable); From 993bcbf09afde9e2ceb1eac0973110b78e4232db Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 19 Oct 2013 17:13:05 +0100 Subject: [PATCH 14/16] Make new unserialization work --- ext/date/php_date.c | 5 ++-- ext/date/tests/DateTime_verify.phpt | 39 ++++++++++++----------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index cacd560501304..d4ed9cc3a450d 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -451,7 +451,6 @@ static const zend_function_entry date_funcs_interface[] = { PHP_ABSTRACT_ME(DateTimeInterface, getOffset, arginfo_date_method_offset_get) PHP_ABSTRACT_ME(DateTimeInterface, getTimestamp, arginfo_date_method_timestamp_get) PHP_ABSTRACT_ME(DateTimeInterface, diff, arginfo_date_method_diff) - PHP_ABSTRACT_ME(DateTimeInterface, __wakeup, NULL) PHP_FE_END }; @@ -2373,7 +2372,9 @@ static int date_object_unserialize(zval **object, zend_class_entry *ce, const un if (php_var_unserialize_properties(ht, &buf, &buf_len, data TSRMLS_CC)) { dateobj = (php_date_obj *) zend_object_store_get_object(*object TSRMLS_CC); - date_object_initialize_from_hash(dateobj, ht TSRMLS_CC); + if (!date_object_initialize_from_hash(dateobj, ht TSRMLS_CC)) { + php_error(E_ERROR, "Invalid serialization data for DateTime object"); + } retval = (int) buf_len; } else { retval = -1; diff --git a/ext/date/tests/DateTime_verify.phpt b/ext/date/tests/DateTime_verify.phpt index a03911f5c8298..14b3b68d07107 100644 --- a/ext/date/tests/DateTime_verify.phpt +++ b/ext/date/tests/DateTime_verify.phpt @@ -27,7 +27,7 @@ object(ReflectionClass)#%d (1) { string(8) "DateTime" } ..and get names of all its methods -array(18) { +array(17) { [0]=> &object(ReflectionMethod)#%d (2) { ["name"]=> @@ -36,118 +36,111 @@ array(18) { string(8) "DateTime" } [1]=> - &object(ReflectionMethod)#%d (2) { - ["name"]=> - string(8) "__wakeup" - ["class"]=> - string(8) "DateTime" - } - [2]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(11) "__set_state" ["class"]=> string(8) "DateTime" } - [3]=> + [2]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(16) "createFromFormat" ["class"]=> string(8) "DateTime" } - [4]=> + [3]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(13) "getLastErrors" ["class"]=> string(8) "DateTime" } - [5]=> + [4]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(6) "format" ["class"]=> string(8) "DateTime" } - [6]=> + [5]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(6) "modify" ["class"]=> string(8) "DateTime" } - [7]=> + [6]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(3) "add" ["class"]=> string(8) "DateTime" } - [8]=> + [7]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(3) "sub" ["class"]=> string(8) "DateTime" } - [9]=> + [8]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(11) "getTimezone" ["class"]=> string(8) "DateTime" } - [10]=> + [9]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(11) "setTimezone" ["class"]=> string(8) "DateTime" } - [11]=> + [10]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(9) "getOffset" ["class"]=> string(8) "DateTime" } - [12]=> + [11]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(7) "setTime" ["class"]=> string(8) "DateTime" } - [13]=> + [12]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(7) "setDate" ["class"]=> string(8) "DateTime" } - [14]=> + [13]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(10) "setISODate" ["class"]=> string(8) "DateTime" } - [15]=> + [14]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(12) "setTimestamp" ["class"]=> string(8) "DateTime" } - [16]=> + [15]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(12) "getTimestamp" ["class"]=> string(8) "DateTime" } - [17]=> + [16]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(4) "diff" From 038edfee393847c0f589a3b5c3b4268144613e93 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 20 Oct 2013 19:31:50 +0100 Subject: [PATCH 15/16] Copy additional properties from unserialization to object --- ext/date/php_date.c | 50 ++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index d4ed9cc3a450d..3d631ea50ee92 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2147,12 +2147,14 @@ static zval* date_clone_immutable(zval *object TSRMLS_DC) return new_object; } +static inline int date_object_internal_property_key(char *key) +{ + return key && (!strcmp(key, "date") || !strcmp(key, "timezone") ||!strcmp(key, "timezone_type")); +} + static void date_object_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { - if (Z_TYPE_P(member) == IS_STRING && - (!strcmp(Z_STRVAL_P(member), "date") || - !strcmp(Z_STRVAL_P(member), "timezone") || - !strcmp(Z_STRVAL_P(member), "timezone_type"))) { + if ( Z_TYPE_P(member) == IS_STRING && date_object_internal_property_key(Z_STRVAL_P(member))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Redefining internal property '%s' is not allowed", Z_STRVAL_P(member)); return; } @@ -2319,6 +2321,7 @@ static int date_object_initialize_from_hash(php_date_obj *dateobj, HashTable *my zval *tmp_obj = NULL; timelib_tzinfo *tzi; php_timezone_obj *tzobj; + int ret = 0; if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) { convert_to_string(*z_date); @@ -2331,15 +2334,12 @@ static int date_object_initialize_from_hash(php_date_obj *dateobj, HashTable *my case TIMELIB_ZONETYPE_OFFSET: case TIMELIB_ZONETYPE_ABBR: { char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2); - int ret; snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone)); ret = php_date_initialize(dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC); efree(tmp); - return 1 == ret; } case TIMELIB_ZONETYPE_ID: { - int ret; convert_to_string(*z_timezone); tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC); @@ -2352,27 +2352,45 @@ static int date_object_initialize_from_hash(php_date_obj *dateobj, HashTable *my ret = php_date_initialize(dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC); zval_ptr_dtor(&tmp_obj); - return 1 == ret; } } } } } - return 0; + if (ret && zend_hash_num_elements(myht) > 3) { + char *key = NULL; + uint key_len; + ulong index; + zval *value; + zval **z_data; + + if (!dateobj->std.properties) { + rebuild_object_properties(&dateobj->std); + } + for (zend_hash_internal_pointer_reset(myht); zend_hash_get_current_data(myht, (void **) &z_data) == SUCCESS; zend_hash_move_forward(myht)) { + zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, NULL); + if (!date_object_internal_property_key(key)) { + MAKE_STD_ZVAL(value); + ZVAL_ZVAL(value, *z_data, 1, 0); + zend_hash_update(dateobj->std.properties, key, key_len, (void *) &value, sizeof(zval *), NULL); + } + } + } + return ret; } static int date_object_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) { - HashTable *ht; + HashTable *myht; php_date_obj *dateobj; int retval; - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, 3, NULL, ZVAL_PTR_DTOR, 0); + ALLOC_HASHTABLE(myht); + zend_hash_init(myht, 3, NULL, ZVAL_PTR_DTOR, 0); - if (php_var_unserialize_properties(ht, &buf, &buf_len, data TSRMLS_CC)) { + if (php_var_unserialize_properties(myht, &buf, &buf_len, data TSRMLS_CC)) { dateobj = (php_date_obj *) zend_object_store_get_object(*object TSRMLS_CC); - if (!date_object_initialize_from_hash(dateobj, ht TSRMLS_CC)) { + if (!date_object_initialize_from_hash(dateobj, myht TSRMLS_CC)) { php_error(E_ERROR, "Invalid serialization data for DateTime object"); } retval = (int) buf_len; @@ -2380,8 +2398,8 @@ static int date_object_unserialize(zval **object, zend_class_entry *ce, const un retval = -1; } - zend_hash_destroy(ht); - FREE_HASHTABLE(ht); + zend_hash_destroy(myht); + FREE_HASHTABLE(myht); return retval; } From 74c291f63fc243474870ccc6bcec6919d095cf9a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 28 Oct 2013 19:16:28 +0000 Subject: [PATCH 16/16] Make date object serialization code a bit more readable --- ext/date/php_date.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 3d631ea50ee92..7114b109a2734 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2147,14 +2147,14 @@ static zval* date_clone_immutable(zval *object TSRMLS_DC) return new_object; } -static inline int date_object_internal_property_key(char *key) +static inline int date_object_is_internal_property_key(char *key) { return key && (!strcmp(key, "date") || !strcmp(key, "timezone") ||!strcmp(key, "timezone_type")); } static void date_object_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { - if ( Z_TYPE_P(member) == IS_STRING && date_object_internal_property_key(Z_STRVAL_P(member))) { + if ( Z_TYPE_P(member) == IS_STRING && date_object_is_internal_property_key(Z_STRVAL_P(member))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Redefining internal property '%s' is not allowed", Z_STRVAL_P(member)); return; } @@ -2369,7 +2369,7 @@ static int date_object_initialize_from_hash(php_date_obj *dateobj, HashTable *my } for (zend_hash_internal_pointer_reset(myht); zend_hash_get_current_data(myht, (void **) &z_data) == SUCCESS; zend_hash_move_forward(myht)) { zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, NULL); - if (!date_object_internal_property_key(key)) { + if (!date_object_is_internal_property_key(key)) { MAKE_STD_ZVAL(value); ZVAL_ZVAL(value, *z_data, 1, 0); zend_hash_update(dateobj->std.properties, key, key_len, (void *) &value, sizeof(zval *), NULL);