diff options
-rw-r--r-- | ext/wddx/wddx.c | 155 |
1 files changed, 114 insertions, 41 deletions
diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index 3692b9fa25..3a1b3f6339 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -380,63 +380,122 @@ static void php_wddx_serialize_unset(wddx_packet *packet) } /* }}} */ -/* {{{ void php_wddx_serialize_hash(wddx_packet *packet, zval *var) */ -static void php_wddx_serialize_hash(wddx_packet *packet, zval *var) +static void php_wddx_serialize_object(wddx_packet *packet, zval *obj) { - zval **ent; + zval **ent, *retval, *fname, **varname; char *key; - int is_struct = 0, ent_type; ulong idx; - HashTable *target_hash; char tmp_buf[WDDX_BUF_LEN]; - target_hash = HASH_OF(var); - - /* If variable is an object, always use struct and serialize its classname */ - if (var->type == IS_OBJECT) { + MAKE_STD_ZVAL(fname); + ZVAL_STRING(fname, "__sleep", 1); + + /* + * We try to call __sleep() method on object. It's supposed to return an + * array of property names to be serialized. + */ + if (call_user_function_ex(CG(function_table), obj, fname, &retval, 0, 0, 1) == SUCCESS) { + if (retval && HASH_OF(retval)) { + php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); + sprintf(tmp_buf, WDDX_VAR_S, PHP_CLASS_NAME_VAR); + php_wddx_add_chunk(packet, tmp_buf); + php_wddx_add_chunk_static(packet, WDDX_STRING_S); + php_wddx_add_chunk_ex(packet, obj->value.obj.ce->name, obj->value.obj.ce->name_length); + php_wddx_add_chunk_static(packet, WDDX_STRING_E); + php_wddx_add_chunk_static(packet, WDDX_VAR_E); + + for (zend_hash_internal_pointer_reset(HASH_OF(retval)); + zend_hash_get_current_data(HASH_OF(retval), (void **)&varname) == SUCCESS; + zend_hash_move_forward(HASH_OF(retval))) { + if (Z_TYPE_PP(varname) != IS_STRING) { + php_error(E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize."); + continue; + } + + if (zend_hash_find(HASH_OF(obj), Z_STRVAL_PP(varname), Z_STRLEN_PP(varname)+1, (void **)&ent) == SUCCESS) { + php_wddx_serialize_var(packet, *ent, Z_STRVAL_PP(varname)); + } + } + + php_wddx_add_chunk_static(packet, WDDX_STRUCT_E); + } + } else { php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); sprintf(tmp_buf, WDDX_VAR_S, PHP_CLASS_NAME_VAR); php_wddx_add_chunk(packet, tmp_buf); php_wddx_add_chunk_static(packet, WDDX_STRING_S); - php_wddx_add_chunk_ex(packet, var->value.obj.ce->name, var->value.obj.ce->name_length); + php_wddx_add_chunk_ex(packet, obj->value.obj.ce->name, obj->value.obj.ce->name_length); php_wddx_add_chunk_static(packet, WDDX_STRING_E); php_wddx_add_chunk_static(packet, WDDX_VAR_E); - is_struct = 1; - } else { - int ind = 0,type; - - for (zend_hash_internal_pointer_reset(target_hash); - zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS; - zend_hash_move_forward(target_hash)) { + for (zend_hash_internal_pointer_reset(HASH_OF(obj)); + zend_hash_get_current_data(HASH_OF(obj), (void**)&ent) == SUCCESS; + zend_hash_move_forward(HASH_OF(obj))) { + if (*ent == obj) + continue; - type = zend_hash_get_current_key(target_hash, &key, &idx); - - if (type == HASH_KEY_IS_STRING) { - is_struct = 1; + if (zend_hash_get_current_key(HASH_OF(obj), &key, &idx) == HASH_KEY_IS_STRING) { + php_wddx_serialize_var(packet, *ent, key); efree(key); - break; + } else { + sprintf(tmp_buf, "%ld", idx); + php_wddx_serialize_var(packet, *ent, tmp_buf); } + } + php_wddx_add_chunk_static(packet, WDDX_STRUCT_E); + } - if (idx != ind) { - is_struct = 1; - break; - } + zval_dtor(fname); + FREE_ZVAL(fname); - ind++; - } + if (retval) { + zval_dtor(retval); + FREE_ZVAL(retval); + } +} - if (is_struct) { - php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); - } else { - sprintf(tmp_buf, WDDX_ARRAY_S, zend_hash_num_elements(target_hash)); - php_wddx_add_chunk(packet, tmp_buf); +static void php_wddx_serialize_array(wddx_packet *packet, zval *arr) +{ + zval **ent; + char *key; + int is_struct = 0, ent_type; + ulong idx; + HashTable *target_hash; + char tmp_buf[WDDX_BUF_LEN]; + int ind = 0,type; + + target_hash = HASH_OF(arr); + + for (zend_hash_internal_pointer_reset(target_hash); + zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS; + zend_hash_move_forward(target_hash)) { + + type = zend_hash_get_current_key(target_hash, &key, &idx); + + if (type == HASH_KEY_IS_STRING) { + is_struct = 1; + efree(key); + break; + } + + if (idx != ind) { + is_struct = 1; + break; } + + ind++; + } + + if (is_struct) { + php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); + } else { + sprintf(tmp_buf, WDDX_ARRAY_S, zend_hash_num_elements(target_hash)); + php_wddx_add_chunk(packet, tmp_buf); } for (zend_hash_internal_pointer_reset(target_hash); zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS; zend_hash_move_forward(target_hash)) { - if (*ent == var) + if (*ent == arr) continue; if (is_struct) { @@ -459,7 +518,6 @@ static void php_wddx_serialize_hash(wddx_packet *packet, zval *var) php_wddx_add_chunk_static(packet, WDDX_ARRAY_E); } } -/* }}} */ /* {{{ void php_wddx_serialize_var(wddx_packet *packet, zval *var, char *name) */ @@ -491,8 +549,11 @@ void php_wddx_serialize_var(wddx_packet *packet, zval *var, char *name) break; case IS_ARRAY: + php_wddx_serialize_array(packet, var); + break; + case IS_OBJECT: - php_wddx_serialize_hash(packet, var); + php_wddx_serialize_object(packet, var); break; } @@ -653,13 +714,12 @@ static void php_wddx_pop_element(void *user_data, const char *name) if (ent1->varname) { if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) && - ent1->data->type == IS_STRING && - ent1->data->value.str.len) - { + ent1->data->type == IS_STRING && ent1->data->value.str.len) { + zval *fname, *retval; + if (zend_hash_find(EG(class_table), ent1->data->value.str.val, ent1->data->value.str.len+1, (void **) &ce)==FAILURE) { - php_error(E_NOTICE, "Deserializing non-existant class: %s! No methods will be available!", - ent1->data->value.str.val); + php_error(E_NOTICE, "Deserializing non-existant class: %s! No methods will be available!", ent1->data->value.str.val); ce = &zend_standard_class_def; } @@ -684,6 +744,19 @@ static void php_wddx_pop_element(void *user_data, const char *name) /* Clean up class name var entry */ zval_dtor(ent1->data); efree(ent1->data); + + /* Call __wakeup() method on the object. */ + MAKE_STD_ZVAL(fname); + ZVAL_STRING(fname, "__wakeup", 1); + + call_user_function_ex(NULL, obj, fname, &retval, 0, 0, 0); + + zval_dtor(fname); + FREE_ZVAL(fname); + if (retval) { + zval_dtor(retval); + FREE_ZVAL(retval); + } } else zend_hash_update(target_hash, |