From c31faf0bd993d7be5de8599c56e91e8b5bc165bd Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 30 Oct 2000 17:10:06 +0000 Subject: [PATCH] Add support for serializing references. @- Add support for serializing references (Stas) # WDDX and shared memory functions not covered yet --- ext/session/session.c | 24 +++++++++-- ext/standard/php_var.h | 18 ++++++++- ext/standard/var.c | 91 +++++++++++++++++++++++++++++++++++------- ext/sysvshm/sysvshm.c | 2 +- 4 files changed, 114 insertions(+), 21 deletions(-) diff --git a/ext/session/session.c b/ext/session/session.c index 4be69bfd9f..1ed71dace0 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -248,12 +248,15 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) { zval *buf; char strbuf[MAX_STR + 1]; + php_serialize_data_t var_hash; ENCODE_VARS; buf = ecalloc(sizeof(*buf), 1); Z_TYPE_P(buf) = IS_STRING; buf->refcount++; + PHP_VAR_SERIALIZE_INIT(var_hash); + ENCODE_LOOP( size_t slen = strlen(key); @@ -262,7 +265,7 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) memcpy(strbuf + 1, key, slen); STR_CAT(buf, strbuf, slen + 1); - php_var_serialize(buf, struc); + php_var_serialize(buf, struc, &var_hash); } else { size_t slen = strlen(key); @@ -276,6 +279,7 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) if (newlen) *newlen = Z_STRLEN_P(buf); *newstr = Z_STRVAL_P(buf); efree(buf); + PHP_VAR_SERIALIZE_DESTROY(var_hash); return SUCCESS; } @@ -288,6 +292,9 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) zval *current; int namelen; int has_value; + php_serialize_data_t var_hash; + + PHP_VAR_UNSERIALIZE_INIT(var_hash); current = (zval *) ecalloc(sizeof(zval), 1); for (p = val; p < endptr; ) { @@ -299,7 +306,7 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) p += namelen + 1; if (has_value) { - if (php_var_unserialize(¤t, &p, endptr)) { + if (php_var_unserialize(¤t, &p, endptr, &var_hash)) { php_set_session_var(name, namelen, current PSLS_CC); zval_dtor(current); } @@ -308,6 +315,7 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) efree(name); } efree(current); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return SUCCESS; } @@ -319,12 +327,15 @@ PS_SERIALIZER_ENCODE_FUNC(php) { zval *buf; char strbuf[MAX_STR + 1]; + php_serialize_data_t var_hash; ENCODE_VARS; buf = ecalloc(sizeof(*buf), 1); Z_TYPE_P(buf) = IS_STRING; buf->refcount++; + PHP_VAR_SERIALIZE_INIT(var_hash); + ENCODE_LOOP( size_t slen = strlen(key); @@ -333,7 +344,7 @@ PS_SERIALIZER_ENCODE_FUNC(php) strbuf[slen] = PS_DELIMITER; STR_CAT(buf, strbuf, slen + 1); - php_var_serialize(buf, struc); + php_var_serialize(buf, struc, &var_hash); } else { size_t slen = strlen(key); @@ -349,6 +360,7 @@ PS_SERIALIZER_ENCODE_FUNC(php) *newstr = Z_STRVAL_P(buf); efree(buf); + PHP_VAR_SERIALIZE_DESTROY(var_hash); return SUCCESS; } @@ -360,6 +372,9 @@ PS_SERIALIZER_DECODE_FUNC(php) zval *current; int namelen; int has_value; + php_serialize_data_t var_hash; + + PHP_VAR_UNSERIALIZE_INIT(var_hash); current = (zval *) ecalloc(sizeof(zval), 1); for (p = q = val; (p < endptr) && (q = memchr(p, PS_DELIMITER, endptr - p)); p = q) { @@ -375,7 +390,7 @@ PS_SERIALIZER_DECODE_FUNC(php) q++; if (has_value) { - if (php_var_unserialize(¤t, &q, endptr)) { + if (php_var_unserialize(¤t, &q, endptr, &var_hash)) { php_set_session_var(name, namelen, current PSLS_CC); zval_dtor(current); } @@ -385,6 +400,7 @@ PS_SERIALIZER_DECODE_FUNC(php) } efree(current); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return SUCCESS; } diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 71ca6f3c8f..8ce3316e2b 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -26,8 +26,22 @@ PHP_FUNCTION(serialize); PHP_FUNCTION(unserialize); void php_var_dump(pval **struc, int level); -void php_var_serialize(pval *buf, pval **struc); -int php_var_unserialize(pval **rval, const char **p, const char *max); + +/* typdef HashTable php_serialize_data_t; */ +#define php_serialize_data_t HashTable + +void php_var_serialize(pval *buf, pval **struc, php_serialize_data_t *var_hash); +int php_var_unserialize(pval **rval, const char **p, const char *max, php_serialize_data_t *var_hash); + +#define PHP_VAR_SERIALIZE_INIT(var_hash) \ + zend_hash_init(&(var_hash),10,NULL,NULL,0) +#define PHP_VAR_SERIALIZE_DESTROY(var_hash) \ + zend_hash_destroy(&(var_hash)) + +#define PHP_VAR_UNSERIALIZE_INIT(var_hash) \ + zend_hash_init(&(var_hash),10,NULL,NULL,0) +#define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \ + zend_hash_destroy(&(var_hash)) PHPAPI zend_class_entry *php_create_empty_class(char *class_name,int len); diff --git a/ext/standard/var.c b/ext/standard/var.c index 04b7d5ba8e..d78bf51577 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -95,7 +95,7 @@ head_done: php_printf("%*c", level-1, ' '); } PUTS("}\n"); - break; + break; case IS_RESOURCE: { char *type_name; type_name = zend_rsrc_list_get_rsrc_type((*struc)->value.lval); @@ -154,14 +154,36 @@ PHP_FUNCTION(var_dump) /* }}} */ /* {{{ php_var_serialize */ -void php_var_serialize(pval *buf, pval **struc) +inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old) { + ulong var_no; + char id[sizeof(void *)*2+3]; + + snprintf(id,sizeof(id)-1,"%p",var); + id[sizeof(id)-1]='\0'; + if(var_old && zend_hash_find(var_hash,id,sizeof(void *)*2,var_old) == SUCCESS) { + return FAILURE; + } + + var_no = zend_hash_num_elements(var_hash)+1; /* +1 because otherwise hash will think we are trying to store NULL pointer */ + zend_hash_add(var_hash,id,sizeof(void *)*2,&var_no,sizeof(var_no),NULL); + return SUCCESS; +} + +void php_var_serialize(pval *buf, pval **struc, HashTable *var_hash) { char s[256]; ulong slen; int i; + ulong *var_already; HashTable *myht; BLS_FETCH(); + if(var_hash != NULL && php_add_var_hash(var_hash,*struc,(void *)&var_already) == FAILURE) { + slen = sprintf(s,"R:%ld;",*var_already); + STR_CAT(buf, s, slen); + return; + } + switch ((*struc)->type) { case IS_BOOL: slen = sprintf(s, "b:%ld;", (*struc)->value.lval); @@ -241,10 +263,10 @@ void php_var_serialize(pval *buf, pval **struc) continue; } - php_var_serialize(buf, name); + php_var_serialize(buf, name, NULL); if (zend_hash_find((*struc)->value.obj.properties,(*name)->value.str.val,(*name)->value.str.len+1,(void*)&d) == SUCCESS) { - php_var_serialize(buf,d); + php_var_serialize(buf,d,var_hash); } } } @@ -294,18 +316,18 @@ void php_var_serialize(pval *buf, pval **struc) if ((i = zend_hash_get_current_key_ex(myht, &key, NULL, &index, &pos)) == HASH_KEY_NON_EXISTANT) { break; } - if (zend_hash_get_current_data_ex(myht, (void **) (&data), &pos) != SUCCESS || !data || ((*data) == (*struc))) { + if (zend_hash_get_current_data_ex(myht, (void **) (&data), &pos) != SUCCESS || !data /* || ((*data) == (*struc)) */) { if (i == HASH_KEY_IS_STRING) efree(key); continue; } switch (i) { - case HASH_KEY_IS_LONG: + case HASH_KEY_IS_LONG: MAKE_STD_ZVAL(d); d->type = IS_LONG; d->value.lval = index; - php_var_serialize(buf, &d); + php_var_serialize(buf, &d, NULL); FREE_ZVAL(d); break; case HASH_KEY_IS_STRING: @@ -313,12 +335,12 @@ void php_var_serialize(pval *buf, pval **struc) d->type = IS_STRING; d->value.str.val = key; d->value.str.len = strlen(key); - php_var_serialize(buf, &d); + php_var_serialize(buf, &d, NULL); efree(key); FREE_ZVAL(d); break; } - php_var_serialize(buf, data); + php_var_serialize(buf, data, var_hash); } } STR_CAT(buf, "}", 1); @@ -333,17 +355,50 @@ void php_var_serialize(pval *buf, pval **struc) /* }}} */ /* {{{ php_var_dump */ -int php_var_unserialize(pval **rval, const char **p, const char *max) +int php_var_unserialize(pval **rval, const char **p, const char *max, HashTable *var_hash) { const char *q; char *str; int i; char cur; + ulong id; HashTable *myht; + pval **rval_ref; + ELS_FETCH(); BLS_FETCH(); + if(var_hash) { + zend_hash_next_index_insert(var_hash, rval, sizeof(*rval), NULL); + } + switch (cur = **p) { + case 'R': + if (*((*p) + 1) != ':') { + return 0; + } + q = *p; + while (**p && **p != ';') { + (*p)++; + } + if (**p != ';') { + return 0; + } + (*p)++; + id = atol(q + 2)-1; /* count starts with 1 */ + if(!var_hash) { + return 0; + } + if(zend_hash_index_find(var_hash, id, (void *)&rval_ref) != SUCCESS) { + return 0; + } + zval_dtor(*rval); + FREE_ZVAL(*rval); + *rval = *rval_ref; + (*rval)->refcount++; + (*rval)->is_ref = 1; + return 1; + case 'N': if (*((*p) + 1) != ';') { return 0; @@ -504,13 +559,13 @@ int php_var_unserialize(pval **rval, const char **p, const char *max) ALLOC_INIT_ZVAL(key); ALLOC_INIT_ZVAL(data); - if (!php_var_unserialize(&key, p, max)) { + if (!php_var_unserialize(&key, p, max, NULL)) { zval_dtor(key); FREE_ZVAL(key); FREE_ZVAL(data); return 0; } - if (!php_var_unserialize(&data, p, max)) { + if (!php_var_unserialize(&data, p, max, var_hash)) { zval_dtor(key); FREE_ZVAL(key); zval_dtor(data); @@ -558,6 +613,7 @@ int php_var_unserialize(pval **rval, const char **p, const char *max) PHP_FUNCTION(serialize) { pval **struc; + php_serialize_data_t var_hash; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &struc) == FAILURE) { WRONG_PARAM_COUNT; @@ -565,7 +621,10 @@ PHP_FUNCTION(serialize) return_value->type = IS_STRING; return_value->value.str.val = NULL; return_value->value.str.len = 0; - php_var_serialize(return_value, struc); + + PHP_VAR_SERIALIZE_INIT(var_hash); + php_var_serialize(return_value, struc, &var_hash); + PHP_VAR_SERIALIZE_DESTROY(var_hash); } /* }}} */ @@ -576,6 +635,7 @@ PHP_FUNCTION(serialize) PHP_FUNCTION(unserialize) { pval **buf; + php_serialize_data_t var_hash; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &buf) == FAILURE) { WRONG_PARAM_COUNT; @@ -588,11 +648,14 @@ PHP_FUNCTION(unserialize) RETURN_FALSE; } - if (!php_var_unserialize(&return_value, &p, p + (*buf)->value.str.len)) { + PHP_VAR_UNSERIALIZE_INIT(var_hash); + if (!php_var_unserialize(&return_value, &p, p + (*buf)->value.str.len, &var_hash)) { + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); zval_dtor(return_value); php_error(E_NOTICE, "unserialize() failed at offset %d of %d bytes",p-(*buf)->value.str.val,(*buf)->value.str.len); RETURN_FALSE; } + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); } else { php_error(E_NOTICE, "argument passed to unserialize() is not an string"); RETURN_FALSE; diff --git a/ext/sysvshm/sysvshm.c b/ext/sysvshm/sysvshm.c index b31a53d899..6986a29295 100644 --- a/ext/sysvshm/sysvshm.c +++ b/ext/sysvshm/sysvshm.c @@ -233,7 +233,7 @@ PHP_FUNCTION(shm_put_var) shm_var.type=IS_STRING; shm_var.value.str.len=0; shm_var.value.str.val=0; - php_var_serialize(&shm_var,arg_var); + php_var_serialize(&shm_var,arg_var,NULL); /* insert serialized variable into shared memory */ ret=php_put_shm_data(shm_list_ptr->ptr,key,shm_var.value.str.val,shm_var.value.str.len); -- 2.50.1