Back to index

php5  5.3.10
var.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Jani Lehtimäki <jkl@njet.net>                               |
00016    |          Thies C. Arntzen <thies@thieso.net>                         |
00017    |          Sascha Schumann <sascha@schumann.cx>                        |
00018    +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: var.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 /* {{{ includes
00024 */
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include "php.h"
00029 #include "php_string.h"
00030 #include "php_var.h"
00031 #include "php_smart_str.h"
00032 #include "basic_functions.h"
00033 #include "php_incomplete_class.h"
00034 
00035 #define COMMON (Z_ISREF_PP(struc) ? "&" : "")
00036 /* }}} */
00037 
00038 static int php_array_element_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
00039 {
00040        int level;
00041 
00042        level = va_arg(args, int);
00043 
00044        if (hash_key->nKeyLength == 0) { /* numeric key */
00045               php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h);
00046        } else { /* string key */
00047               php_printf("%*c[\"", level + 1, ' ');
00048               PHPWRITE(hash_key->arKey, hash_key->nKeyLength - 1);
00049               php_printf("\"]=>\n");
00050        }
00051        php_var_dump(zv, level + 2 TSRMLS_CC);
00052        return 0;
00053 }
00054 /* }}} */
00055 
00056 static int php_object_property_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
00057 {
00058        int level;
00059        char *prop_name, *class_name;
00060 
00061        level = va_arg(args, int);
00062 
00063        if (hash_key->nKeyLength == 0) { /* numeric key */
00064               php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h);
00065        } else { /* string key */
00066               int unmangle = zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name);
00067               php_printf("%*c[", level + 1, ' ');
00068 
00069               if (class_name && unmangle == SUCCESS) {
00070                      if (class_name[0] == '*') {
00071                             php_printf("\"%s\":protected", prop_name);
00072                      } else {
00073                             php_printf("\"%s\":\"%s\":private", prop_name, class_name);
00074                      }
00075               } else {
00076                      php_printf("\"");
00077                      PHPWRITE(hash_key->arKey, hash_key->nKeyLength - 1);
00078                      php_printf("\"");
00079               }
00080               ZEND_PUTS("]=>\n");
00081        }
00082        php_var_dump(zv, level + 2 TSRMLS_CC);
00083        return 0;
00084 }
00085 /* }}} */
00086 
00087 PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC) /* {{{ */
00088 {
00089        HashTable *myht;
00090        char *class_name;
00091        zend_uint class_name_len;
00092        int (*php_element_dump_func)(zval** TSRMLS_DC, int, va_list, zend_hash_key*);
00093        int is_temp;
00094 
00095        if (level > 1) {
00096               php_printf("%*c", level - 1, ' ');
00097        }
00098 
00099        switch (Z_TYPE_PP(struc)) {
00100        case IS_BOOL:
00101               php_printf("%sbool(%s)\n", COMMON, Z_LVAL_PP(struc) ? "true" : "false");
00102               break;
00103        case IS_NULL:
00104               php_printf("%sNULL\n", COMMON);
00105               break;
00106        case IS_LONG:
00107               php_printf("%sint(%ld)\n", COMMON, Z_LVAL_PP(struc));
00108               break;
00109        case IS_DOUBLE:
00110               php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_PP(struc));
00111               break;
00112        case IS_STRING:
00113               php_printf("%sstring(%d) \"", COMMON, Z_STRLEN_PP(struc));
00114               PHPWRITE(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc));
00115               PUTS("\"\n");
00116               break;
00117        case IS_ARRAY:
00118               myht = Z_ARRVAL_PP(struc);
00119               if (++myht->nApplyCount > 1) {
00120                      PUTS("*RECURSION*\n");
00121                      --myht->nApplyCount;
00122                      return;
00123               }
00124               php_printf("%sarray(%d) {\n", COMMON, zend_hash_num_elements(myht));
00125               php_element_dump_func = php_array_element_dump;
00126               is_temp = 0;
00127               goto head_done;
00128        case IS_OBJECT:
00129               myht = Z_OBJDEBUG_PP(struc, is_temp);
00130               if (myht && ++myht->nApplyCount > 1) {
00131                      PUTS("*RECURSION*\n");
00132                      --myht->nApplyCount;
00133                      return;
00134               }
00135 
00136               Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC);
00137               php_printf("%sobject(%s)#%d (%d) {\n", COMMON, class_name, Z_OBJ_HANDLE_PP(struc), myht ? zend_hash_num_elements(myht) : 0);
00138               efree(class_name);
00139               php_element_dump_func = php_object_property_dump;
00140 head_done:
00141               if (myht) {
00142                      zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_element_dump_func, 1, level);
00143                      --myht->nApplyCount;
00144                      if (is_temp) {
00145                             zend_hash_destroy(myht);
00146                             efree(myht);
00147                      }
00148               }
00149               if (level > 1) {
00150                      php_printf("%*c", level-1, ' ');
00151               }
00152               PUTS("}\n");
00153               break;
00154        case IS_RESOURCE: {
00155               char *type_name;
00156 
00157               type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(struc) TSRMLS_CC);
00158               php_printf("%sresource(%ld) of type (%s)\n", COMMON, Z_LVAL_PP(struc), type_name ? type_name : "Unknown");
00159               break;
00160        }
00161        default:
00162               php_printf("%sUNKNOWN:0\n", COMMON);
00163               break;
00164        }
00165 }
00166 /* }}} */
00167 
00168 /* {{{ proto void var_dump(mixed var)
00169    Dumps a string representation of variable to output */
00170 PHP_FUNCTION(var_dump)
00171 {
00172        zval ***args;
00173        int argc;
00174        int    i;
00175 
00176        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
00177               return;
00178        }
00179 
00180        for (i = 0; i < argc; i++) {
00181               php_var_dump(args[i], 1 TSRMLS_CC);
00182        }
00183        efree(args);
00184 }
00185 /* }}} */
00186 
00187 static int zval_array_element_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
00188 {
00189        int level;
00190 
00191        level = va_arg(args, int);
00192 
00193        if (hash_key->nKeyLength == 0) { /* numeric key */
00194               php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h);
00195        } else { /* string key */
00196               /* XXX: perphaps when we are inside the class we should permit access to
00197                * private & protected values
00198                */
00199               if (va_arg(args, int) && hash_key->arKey[0] == '\0') {
00200                      return 0;
00201               }
00202               php_printf("%*c[\"", level + 1, ' ');
00203               PHPWRITE(hash_key->arKey, hash_key->nKeyLength - 1);
00204               php_printf("\"]=>\n");
00205        }
00206        php_debug_zval_dump(zv, level + 2 TSRMLS_CC);
00207        return 0;
00208 }
00209 /* }}} */
00210 
00211 static int zval_object_property_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
00212 {
00213        int level;
00214        char *prop_name, *class_name;
00215 
00216        level = va_arg(args, int);
00217 
00218        if (hash_key->nKeyLength == 0) { /* numeric key */
00219               php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h);
00220        } else { /* string key */
00221               zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name);
00222               php_printf("%*c[", level + 1, ' ');
00223 
00224               if (class_name) {
00225                      if (class_name[0] == '*') {
00226                             php_printf("\"%s\":protected", prop_name);
00227                      } else {
00228                             php_printf("\"%s\":\"%s\":private", prop_name, class_name);
00229                      }
00230               } else {
00231                      php_printf("\"%s\"", prop_name);
00232               }
00233               ZEND_PUTS("]=>\n");
00234        }
00235        php_debug_zval_dump(zv, level + 2 TSRMLS_CC);
00236        return 0;
00237 }
00238 /* }}} */
00239 
00240 PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC) /* {{{ */
00241 {
00242        HashTable *myht = NULL;
00243        char *class_name;
00244        zend_uint class_name_len;
00245        int (*zval_element_dump_func)(zval** TSRMLS_DC, int, va_list, zend_hash_key*);
00246        int is_temp = 0;
00247 
00248        if (level > 1) {
00249               php_printf("%*c", level - 1, ' ');
00250        }
00251 
00252        switch (Z_TYPE_PP(struc)) {
00253        case IS_BOOL:
00254               php_printf("%sbool(%s) refcount(%u)\n", COMMON, Z_LVAL_PP(struc)?"true":"false", Z_REFCOUNT_PP(struc));
00255               break;
00256        case IS_NULL:
00257               php_printf("%sNULL refcount(%u)\n", COMMON, Z_REFCOUNT_PP(struc));
00258               break;
00259        case IS_LONG:
00260               php_printf("%slong(%ld) refcount(%u)\n", COMMON, Z_LVAL_PP(struc), Z_REFCOUNT_PP(struc));
00261               break;
00262        case IS_DOUBLE:
00263               php_printf("%sdouble(%.*G) refcount(%u)\n", COMMON, (int) EG(precision), Z_DVAL_PP(struc), Z_REFCOUNT_PP(struc));
00264               break;
00265        case IS_STRING:
00266               php_printf("%sstring(%d) \"", COMMON, Z_STRLEN_PP(struc));
00267               PHPWRITE(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc));
00268               php_printf("\" refcount(%u)\n", Z_REFCOUNT_PP(struc));
00269               break;
00270        case IS_ARRAY:
00271               myht = Z_ARRVAL_PP(struc);
00272               if (myht->nApplyCount > 1) {
00273                      PUTS("*RECURSION*\n");
00274                      return;
00275               }
00276               php_printf("%sarray(%d) refcount(%u){\n", COMMON, zend_hash_num_elements(myht), Z_REFCOUNT_PP(struc));
00277               zval_element_dump_func = zval_array_element_dump;
00278               goto head_done;
00279        case IS_OBJECT:
00280               myht = Z_OBJDEBUG_PP(struc, is_temp);
00281               if (myht && myht->nApplyCount > 1) {
00282                      PUTS("*RECURSION*\n");
00283                      return;
00284               }
00285               if (Z_OBJ_HANDLER_PP(struc, get_class_name)) {
00286                      Z_OBJ_HANDLER_PP(struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC);
00287                      php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, class_name, Z_OBJ_HANDLE_PP(struc), myht ? zend_hash_num_elements(myht) : 0, Z_REFCOUNT_PP(struc));
00288                      efree(class_name);
00289               } else {
00290                      php_printf("%sobject(unknown class)#%d (%d) refcount(%u){\n", COMMON, Z_OBJ_HANDLE_PP(struc), myht ? zend_hash_num_elements(myht) : 0, Z_REFCOUNT_PP(struc));
00291               }
00292               zval_element_dump_func = zval_object_property_dump;
00293 head_done:
00294               if (myht) {
00295                      zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) zval_element_dump_func, 1, level, (Z_TYPE_PP(struc) == IS_ARRAY ? 0 : 1));
00296                      if (is_temp) {
00297                             zend_hash_destroy(myht);
00298                             efree(myht);
00299                      }
00300               }
00301               if (level > 1) {
00302                      php_printf("%*c", level - 1, ' ');
00303               }
00304               PUTS("}\n");
00305               break;
00306        case IS_RESOURCE: {
00307               char *type_name;
00308 
00309               type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(struc) TSRMLS_CC);
00310               php_printf("%sresource(%ld) of type (%s) refcount(%u)\n", COMMON, Z_LVAL_PP(struc), type_name ? type_name : "Unknown", Z_REFCOUNT_PP(struc));
00311               break;
00312        }
00313        default:
00314               php_printf("%sUNKNOWN:0\n", COMMON);
00315               break;
00316        }
00317 }
00318 /* }}} */
00319 
00320 /* {{{ proto void debug_zval_dump(mixed var)
00321    Dumps a string representation of an internal zend value to output. */
00322 PHP_FUNCTION(debug_zval_dump)
00323 {
00324        zval ***args;
00325        int argc;
00326        int    i;
00327 
00328        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
00329               return;
00330        }
00331 
00332        for (i = 0; i < argc; i++) {
00333               php_debug_zval_dump(args[i], 1 TSRMLS_CC);
00334        }
00335        efree(args);
00336 }
00337 /* }}} */
00338 
00339 #define buffer_append_spaces(buf, num_spaces) \
00340        do { \
00341               char *tmp_spaces; \
00342               int tmp_spaces_len; \
00343               tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \
00344               smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \
00345               efree(tmp_spaces); \
00346        } while(0);
00347 
00348 static int php_array_element_export(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
00349 {
00350        int level;
00351        smart_str *buf;
00352 
00353        level = va_arg(args, int);
00354        buf = va_arg(args, smart_str *);
00355 
00356        if (hash_key->nKeyLength == 0) { /* numeric key */
00357               buffer_append_spaces(buf, level+1);
00358               smart_str_append_long(buf, (long) hash_key->h);
00359               smart_str_appendl(buf, " => ", 4);
00360        } else { /* string key */
00361               char *key, *tmp_str;
00362               int key_len, tmp_len;
00363               key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC);
00364               tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL);
00365 
00366               buffer_append_spaces(buf, level + 1);
00367 
00368               smart_str_appendc(buf, '\'');
00369               smart_str_appendl(buf, tmp_str, tmp_len);
00370               smart_str_appendl(buf, "' => ", 5);
00371 
00372               efree(key);
00373               efree(tmp_str);
00374        }
00375        php_var_export_ex(zv, level + 2, buf TSRMLS_CC);
00376 
00377        smart_str_appendc(buf, ',');
00378        smart_str_appendc(buf, '\n');
00379 
00380        return 0;
00381 }
00382 /* }}} */
00383 
00384 static int php_object_element_export(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
00385 {
00386        int level;
00387        smart_str *buf;
00388 
00389        level = va_arg(args, int);
00390        buf = va_arg(args, smart_str *);
00391 
00392        buffer_append_spaces(buf, level + 2);
00393        if (hash_key->nKeyLength != 0) {
00394               char *class_name, /* ignored, but must be passed to unmangle */
00395                       *pname,
00396                       *pname_esc;
00397               int  pname_esc_len;
00398               
00399               zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1,
00400                             &class_name, &pname);
00401               pname_esc = php_addcslashes(pname, strlen(pname), &pname_esc_len, 0,
00402                      "'\\", 2 TSRMLS_CC);
00403 
00404               smart_str_appendc(buf, '\'');
00405               smart_str_appendl(buf, pname_esc, pname_esc_len);
00406               smart_str_appendc(buf, '\'');
00407               efree(pname_esc);
00408        } else {
00409               smart_str_append_long(buf, hash_key->h);
00410        }
00411 
00412        smart_str_appendl(buf, " => ", 4);
00413        php_var_export_ex(zv, level + 2, buf TSRMLS_CC);
00414        smart_str_appendc(buf, ',');
00415        smart_str_appendc(buf, '\n');
00416 
00417        return 0;
00418 }
00419 /* }}} */
00420 
00421 PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) /* {{{ */
00422 {
00423        HashTable *myht;
00424        char *tmp_str, *tmp_str2;
00425        int tmp_len, tmp_len2;
00426        char *class_name;
00427        zend_uint class_name_len;
00428 
00429        switch (Z_TYPE_PP(struc)) {
00430        case IS_BOOL:
00431        if (Z_LVAL_PP(struc)) {
00432               smart_str_appendl(buf, "true", 4);
00433        } else {
00434               smart_str_appendl(buf, "false", 5);
00435        }
00436               break;
00437        case IS_NULL:
00438               smart_str_appendl(buf, "NULL", 4);
00439               break;
00440        case IS_LONG:
00441               smart_str_append_long(buf, Z_LVAL_PP(struc));
00442               break;
00443        case IS_DOUBLE:
00444               tmp_len = spprintf(&tmp_str, 0,"%.*H", (int) EG(precision), Z_DVAL_PP(struc));
00445               smart_str_appendl(buf, tmp_str, tmp_len);
00446               efree(tmp_str);
00447               break;
00448        case IS_STRING:
00449               tmp_str = php_addcslashes(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc), &tmp_len, 0, "'\\", 2 TSRMLS_CC);
00450               tmp_str2 = php_str_to_str_ex(tmp_str, tmp_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len2, 0, NULL);
00451 
00452               smart_str_appendc(buf, '\'');
00453               smart_str_appendl(buf, tmp_str2, tmp_len2);
00454               smart_str_appendc(buf, '\'');
00455 
00456               efree(tmp_str2);
00457               efree(tmp_str);
00458               break;
00459        case IS_ARRAY:
00460               myht = Z_ARRVAL_PP(struc);
00461               if (level > 1) {
00462                      smart_str_appendc(buf, '\n');
00463                      buffer_append_spaces(buf, level - 1);
00464               }
00465               smart_str_appendl(buf, "array (\n", 8);
00466               zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_array_element_export, 2, level, buf);
00467 
00468               if (level > 1) {
00469                      buffer_append_spaces(buf, level - 1);
00470               }
00471               smart_str_appendc(buf, ')');
00472 
00473               break;
00474        case IS_OBJECT:
00475               myht = Z_OBJPROP_PP(struc);
00476               if (level > 1) {
00477                      smart_str_appendc(buf, '\n');
00478                      buffer_append_spaces(buf, level - 1);
00479               }
00480               Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC);
00481 
00482               smart_str_appendl(buf, class_name, class_name_len);
00483               smart_str_appendl(buf, "::__set_state(array(\n", 21);
00484 
00485               efree(class_name);
00486               if (myht) {
00487                      zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_object_element_export, 2, level, buf);
00488               }
00489               if (level > 1) {
00490                      buffer_append_spaces(buf, level - 1);
00491               }
00492               smart_str_appendl(buf, "))", 2);
00493 
00494               break;
00495        default:
00496               smart_str_appendl(buf, "NULL", 4);
00497               break;
00498        }
00499 }
00500 /* }}} */
00501 
00502 /* FOR BC reasons, this will always perform and then print */
00503 PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) /* {{{ */
00504 {
00505        smart_str buf = {0};
00506        php_var_export_ex(struc, level, &buf TSRMLS_CC);
00507        smart_str_0 (&buf);
00508        PHPWRITE(buf.c, buf.len);
00509        smart_str_free(&buf);
00510 }
00511 /* }}} */
00512 
00513 /* {{{ proto mixed var_export(mixed var [, bool return])
00514    Outputs or returns a string representation of a variable */
00515 PHP_FUNCTION(var_export)
00516 {
00517        zval *var;
00518        zend_bool return_output = 0;
00519        smart_str buf = {0};
00520 
00521        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &var, &return_output) == FAILURE) {
00522               return;
00523        }
00524 
00525        php_var_export_ex(&var, 1, &buf TSRMLS_CC);
00526        smart_str_0 (&buf);
00527 
00528        if (return_output) {
00529               RETVAL_STRINGL(buf.c, buf.len, 1);
00530        } else {
00531               PHPWRITE(buf.c, buf.len);
00532        }
00533        smart_str_free(&buf);
00534 }
00535 /* }}} */
00536 
00537 static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC);
00538 
00539 static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old TSRMLS_DC) /* {{{ */
00540 {
00541        ulong var_no;
00542        char id[32], *p;
00543        register int len;
00544 
00545        /* relies on "(long)" being a perfect hash function for data pointers,
00546         * however the actual identity of an object has had to be determined
00547         * by its object handle and the class entry since 5.0. */
00548        if ((Z_TYPE_P(var) == IS_OBJECT) && Z_OBJ_HT_P(var)->get_class_entry) {
00549               p = smart_str_print_long(id + sizeof(id) - 1,
00550                             (((size_t)Z_OBJCE_P(var) << 5)
00551                             | ((size_t)Z_OBJCE_P(var) >> (sizeof(long) * 8 - 5)))
00552                             + (long) Z_OBJ_HANDLE_P(var));
00553               *(--p) = 'O';
00554               len = id + sizeof(id) - 1 - p;
00555        } else {
00556               p = smart_str_print_long(id + sizeof(id) - 1, (long) var);
00557               len = id + sizeof(id) - 1 - p;
00558        }
00559 
00560        if (var_old && zend_hash_find(var_hash, p, len, var_old) == SUCCESS) {
00561               if (!Z_ISREF_P(var)) {
00562                      /* we still need to bump up the counter, since non-refs will
00563                       * be counted separately by unserializer */
00564                      var_no = -1;
00565                      zend_hash_next_index_insert(var_hash, &var_no, sizeof(var_no), NULL);
00566               }
00567               return FAILURE;
00568        }
00569 
00570        /* +1 because otherwise hash will think we are trying to store NULL pointer */
00571        var_no = zend_hash_num_elements(var_hash) + 1;
00572        zend_hash_add(var_hash, p, len, &var_no, sizeof(var_no), NULL);
00573        return SUCCESS;
00574 }
00575 /* }}} */
00576 
00577 static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */
00578 {
00579        smart_str_appendl(buf, "i:", 2);
00580        smart_str_append_long(buf, val);
00581        smart_str_appendc(buf, ';');
00582 }
00583 /* }}} */
00584 
00585 static inline void php_var_serialize_string(smart_str *buf, char *str, int len) /* {{{ */
00586 {
00587        smart_str_appendl(buf, "s:", 2);
00588        smart_str_append_long(buf, len);
00589        smart_str_appendl(buf, ":\"", 2);
00590        smart_str_appendl(buf, str, len);
00591        smart_str_appendl(buf, "\";", 2);
00592 }
00593 /* }}} */
00594 
00595 static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc TSRMLS_DC) /* {{{ */
00596 {
00597        PHP_CLASS_ATTRIBUTES;
00598 
00599        PHP_SET_CLASS_ATTRIBUTES(struc);
00600        smart_str_appendl(buf, "O:", 2);
00601        smart_str_append_long(buf, (int)name_len);
00602        smart_str_appendl(buf, ":\"", 2);
00603        smart_str_appendl(buf, class_name, name_len);
00604        smart_str_appendl(buf, "\":", 2);
00605        PHP_CLEANUP_CLASS_ATTRIBUTES();
00606        return incomplete_class;
00607 }
00608 /* }}} */
00609 
00610 static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, HashTable *var_hash TSRMLS_DC) /* {{{ */
00611 {
00612        int count;
00613        zend_bool incomplete_class;
00614 
00615        incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC);
00616        /* count after serializing name, since php_var_serialize_class_name
00617         * changes the count if the variable is incomplete class */
00618        count = zend_hash_num_elements(HASH_OF(retval_ptr));
00619        if (incomplete_class) {
00620               --count;
00621        }
00622        smart_str_append_long(buf, count);
00623        smart_str_appendl(buf, ":{", 2);
00624 
00625        if (count > 0) {
00626               char *key;
00627               zval **d, **name;
00628               ulong index;
00629               HashPosition pos;
00630               int i;
00631               zval nval, *nvalp;
00632 
00633               ZVAL_NULL(&nval);
00634               nvalp = &nval;
00635 
00636               zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos);
00637 
00638               for (;; zend_hash_move_forward_ex(HASH_OF(retval_ptr), &pos)) {
00639                      i = zend_hash_get_current_key_ex(HASH_OF(retval_ptr), &key, NULL, &index, 0, &pos);
00640 
00641                      if (i == HASH_KEY_NON_EXISTANT) {
00642                             break;
00643                      }
00644 
00645                      if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
00646                             continue;
00647                      }
00648                      zend_hash_get_current_data_ex(HASH_OF(retval_ptr), (void **) &name, &pos);
00649 
00650                      if (Z_TYPE_PP(name) != IS_STRING) {
00651                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
00652                             /* we should still add element even if it's not OK,
00653                              * since we already wrote the length of the array before */
00654                             smart_str_appendl(buf,"N;", 2);
00655                             continue;
00656                      }
00657                      if (zend_hash_find(Z_OBJPROP_P(struc), Z_STRVAL_PP(name), Z_STRLEN_PP(name) + 1, (void *) &d) == SUCCESS) {
00658                             php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
00659                             php_var_serialize_intern(buf, *d, var_hash TSRMLS_CC);
00660                      } else {
00661                             zend_class_entry *ce;
00662                             ce = zend_get_class_entry(struc TSRMLS_CC);
00663                             if (ce) {
00664                                    char *prot_name, *priv_name;
00665                                    int prop_name_length;
00666 
00667                                    do {
00668                                           zend_mangle_property_name(&priv_name, &prop_name_length, ce->name, ce->name_length, Z_STRVAL_PP(name), Z_STRLEN_PP(name), ce->type & ZEND_INTERNAL_CLASS);
00669                                           if (zend_hash_find(Z_OBJPROP_P(struc), priv_name, prop_name_length + 1, (void *) &d) == SUCCESS) {
00670                                                  php_var_serialize_string(buf, priv_name, prop_name_length);
00671                                                  pefree(priv_name, ce->type & ZEND_INTERNAL_CLASS);
00672                                                  php_var_serialize_intern(buf, *d, var_hash TSRMLS_CC);
00673                                                  break;
00674                                           }
00675                                           pefree(priv_name, ce->type & ZEND_INTERNAL_CLASS);
00676                                           zend_mangle_property_name(&prot_name, &prop_name_length, "*", 1, Z_STRVAL_PP(name), Z_STRLEN_PP(name), ce->type & ZEND_INTERNAL_CLASS);
00677                                           if (zend_hash_find(Z_OBJPROP_P(struc), prot_name, prop_name_length + 1, (void *) &d) == SUCCESS) {
00678                                                  php_var_serialize_string(buf, prot_name, prop_name_length);
00679                                                  pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS);
00680                                                  php_var_serialize_intern(buf, *d, var_hash TSRMLS_CC);
00681                                                  break;
00682                                           }
00683                                           pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS);
00684                                           php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
00685                                           php_var_serialize_intern(buf, nvalp, var_hash TSRMLS_CC);
00686                                           php_error_docref(NULL TSRMLS_CC, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", Z_STRVAL_PP(name));
00687                                    } while (0);
00688                             } else {
00689                                    php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
00690                                    php_var_serialize_intern(buf, nvalp, var_hash TSRMLS_CC);
00691                             }
00692                      }
00693               }
00694        }
00695        smart_str_appendc(buf, '}');
00696 }
00697 /* }}} */
00698 
00699 static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC) /* {{{ */
00700 {
00701        int i;
00702        ulong *var_already;
00703        HashTable *myht;
00704 
00705        if (var_hash && php_add_var_hash(var_hash, struc, (void *) &var_already TSRMLS_CC) == FAILURE) {
00706               if (Z_ISREF_P(struc)) {
00707                      smart_str_appendl(buf, "R:", 2);
00708                      smart_str_append_long(buf, (long)*var_already);
00709                      smart_str_appendc(buf, ';');
00710                      return;
00711               } else if (Z_TYPE_P(struc) == IS_OBJECT) {
00712                      smart_str_appendl(buf, "r:", 2);
00713                      smart_str_append_long(buf, (long)*var_already);
00714                      smart_str_appendc(buf, ';');
00715                      return;
00716               }
00717        }
00718 
00719        switch (Z_TYPE_P(struc)) {
00720               case IS_BOOL:
00721                      smart_str_appendl(buf, "b:", 2);
00722                      smart_str_append_long(buf, Z_LVAL_P(struc));
00723                      smart_str_appendc(buf, ';');
00724                      return;
00725 
00726               case IS_NULL:
00727                      smart_str_appendl(buf, "N;", 2);
00728                      return;
00729 
00730               case IS_LONG:
00731                      php_var_serialize_long(buf, Z_LVAL_P(struc));
00732                      return;
00733 
00734               case IS_DOUBLE: {
00735                             char *s;
00736 
00737                             smart_str_appendl(buf, "d:", 2);
00738                             s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1);
00739                             php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s);
00740                             smart_str_appends(buf, s);
00741                             smart_str_appendc(buf, ';');
00742                             efree(s);
00743                             return;
00744                      }
00745 
00746               case IS_STRING:
00747                      php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc));
00748                      return;
00749 
00750               case IS_OBJECT: {
00751                             zval *retval_ptr = NULL;
00752                             zval fname;
00753                             int res;
00754                             zend_class_entry *ce = NULL;
00755 
00756                             if (Z_OBJ_HT_P(struc)->get_class_entry) {
00757                                    ce = Z_OBJCE_P(struc);
00758                             }
00759 
00760                             if (ce && ce->serialize != NULL) {
00761                                    /* has custom handler */
00762                                    unsigned char *serialized_data = NULL;
00763                                    zend_uint serialized_length;
00764 
00765                                    if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC) == SUCCESS) {
00766                                           smart_str_appendl(buf, "C:", 2);
00767                                           smart_str_append_long(buf, (int)Z_OBJCE_P(struc)->name_length);
00768                                           smart_str_appendl(buf, ":\"", 2);
00769                                           smart_str_appendl(buf, Z_OBJCE_P(struc)->name, Z_OBJCE_P(struc)->name_length);
00770                                           smart_str_appendl(buf, "\":", 2);
00771 
00772                                           smart_str_append_long(buf, (int)serialized_length);
00773                                           smart_str_appendl(buf, ":{", 2);
00774                                           smart_str_appendl(buf, serialized_data, serialized_length);
00775                                           smart_str_appendc(buf, '}');
00776                                    } else {
00777                                           smart_str_appendl(buf, "N;", 2);
00778                                    }
00779                                    if (serialized_data) {
00780                                           efree(serialized_data);
00781                                    }
00782                                    return;
00783                             }
00784 
00785                             if (ce && ce != PHP_IC_ENTRY && zend_hash_exists(&ce->function_table, "__sleep", sizeof("__sleep"))) {
00786                                    INIT_PZVAL(&fname);
00787                                    ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1, 0);
00788                                    res = call_user_function_ex(CG(function_table), &struc, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
00789 
00790                                    if (res == SUCCESS && !EG(exception)) {
00791                                           if (retval_ptr) {
00792                                                  if (HASH_OF(retval_ptr)) {
00793                                                         php_var_serialize_class(buf, struc, retval_ptr, var_hash TSRMLS_CC);
00794                                                  } else {
00795                                                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize");
00796                                                         /* we should still add element even if it's not OK,
00797                                                          * since we already wrote the length of the array before */
00798                                                         smart_str_appendl(buf,"N;", 2);
00799                                                  }
00800                                                  zval_ptr_dtor(&retval_ptr);
00801                                           }
00802                                           return;
00803                                    }
00804                             }
00805 
00806                             if (retval_ptr) {
00807                                    zval_ptr_dtor(&retval_ptr);
00808                             }
00809                             /* fall-through */
00810                      }
00811               case IS_ARRAY: {
00812                      zend_bool incomplete_class = 0;
00813                      if (Z_TYPE_P(struc) == IS_ARRAY) {
00814                             smart_str_appendl(buf, "a:", 2);
00815                             myht = HASH_OF(struc);
00816                      } else {
00817                             incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC);
00818                             myht = Z_OBJPROP_P(struc);
00819                      }
00820                      /* count after serializing name, since php_var_serialize_class_name
00821                       * changes the count if the variable is incomplete class */
00822                      i = myht ? zend_hash_num_elements(myht) : 0;
00823                      if (i > 0 && incomplete_class) {
00824                             --i;
00825                      }
00826                      smart_str_append_long(buf, i);
00827                      smart_str_appendl(buf, ":{", 2);
00828                      if (i > 0) {
00829                             char *key;
00830                             zval **data;
00831                             ulong index;
00832                             uint key_len;
00833                             HashPosition pos;
00834 
00835                             zend_hash_internal_pointer_reset_ex(myht, &pos);
00836                             for (;; zend_hash_move_forward_ex(myht, &pos)) {
00837                                    i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
00838                                    if (i == HASH_KEY_NON_EXISTANT) {
00839                                           break;
00840                                    }
00841                                    if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
00842                                           continue;
00843                                    }
00844 
00845                                    switch (i) {
00846                                           case HASH_KEY_IS_LONG:
00847                                                  php_var_serialize_long(buf, index);
00848                                                  break;
00849                                           case HASH_KEY_IS_STRING:
00850                                                  php_var_serialize_string(buf, key, key_len - 1);
00851                                                  break;
00852                                    }
00853 
00854                                    /* we should still add element even if it's not OK,
00855                                     * since we already wrote the length of the array before */
00856                                    if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS
00857                                           || !data
00858                                           || data == &struc
00859                                           || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1)
00860                                    ) {
00861                                           smart_str_appendl(buf, "N;", 2);
00862                                    } else {
00863                                           if (Z_TYPE_PP(data) == IS_ARRAY) {
00864                                                  Z_ARRVAL_PP(data)->nApplyCount++;
00865                                           }
00866                                           php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC);
00867                                           if (Z_TYPE_PP(data) == IS_ARRAY) {
00868                                                  Z_ARRVAL_PP(data)->nApplyCount--;
00869                                           }
00870                                    }
00871                             }
00872                      }
00873                      smart_str_appendc(buf, '}');
00874                      return;
00875               }
00876               default:
00877                      smart_str_appendl(buf, "i:0;", 4);
00878                      return;
00879        }
00880 }
00881 /* }}} */
00882 
00883 PHPAPI void php_var_serialize(smart_str *buf, zval **struc, HashTable *var_hash TSRMLS_DC) /* {{{ */
00884 {
00885        php_var_serialize_intern(buf, *struc, var_hash TSRMLS_CC);
00886        smart_str_0(buf);
00887 }
00888 /* }}} */
00889 
00890 /* {{{ proto string serialize(mixed variable)
00891    Returns a string representation of variable (which can later be unserialized) */
00892 PHP_FUNCTION(serialize)
00893 {
00894        zval **struc;
00895        php_serialize_data_t var_hash;
00896        smart_str buf = {0};
00897 
00898        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &struc) == FAILURE) {
00899               return;
00900        }
00901 
00902        Z_TYPE_P(return_value) = IS_STRING;
00903        Z_STRVAL_P(return_value) = NULL;
00904        Z_STRLEN_P(return_value) = 0;
00905 
00906        PHP_VAR_SERIALIZE_INIT(var_hash);
00907        php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
00908        PHP_VAR_SERIALIZE_DESTROY(var_hash);
00909 
00910        if (buf.c) {
00911               RETURN_STRINGL(buf.c, buf.len, 0);
00912        } else {
00913               RETURN_NULL();
00914        }
00915 }
00916 /* }}} */
00917 
00918 /* {{{ proto mixed unserialize(string variable_representation)
00919    Takes a string representation of variable and recreates it */
00920 PHP_FUNCTION(unserialize)
00921 {
00922        char *buf = NULL;
00923        int buf_len;
00924        const unsigned char *p;
00925        php_unserialize_data_t var_hash;
00926 
00927        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
00928               RETURN_FALSE;
00929        }
00930 
00931        if (buf_len == 0) {
00932               RETURN_FALSE;
00933        }
00934 
00935        p = (const unsigned char*) buf;
00936        PHP_VAR_UNSERIALIZE_INIT(var_hash);
00937        if (!php_var_unserialize(&return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) {
00938               PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
00939               zval_dtor(return_value);
00940               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
00941               RETURN_FALSE;
00942        }
00943        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
00944 }
00945 /* }}} */
00946 
00947 /* {{{ proto int memory_get_usage([real_usage])
00948    Returns the allocated by PHP memory */
00949 PHP_FUNCTION(memory_get_usage) {
00950        zend_bool real_usage = 0;
00951 
00952        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &real_usage) == FAILURE) {
00953               RETURN_FALSE;
00954        }
00955 
00956        RETURN_LONG(zend_memory_usage(real_usage TSRMLS_CC));
00957 }
00958 /* }}} */
00959 
00960 /* {{{ proto int memory_get_peak_usage([real_usage])
00961    Returns the peak allocated by PHP memory */
00962 PHP_FUNCTION(memory_get_peak_usage) {
00963        zend_bool real_usage = 0;
00964 
00965        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &real_usage) == FAILURE) {
00966               RETURN_FALSE;
00967        }
00968 
00969        RETURN_LONG(zend_memory_peak_usage(real_usage TSRMLS_CC));
00970 }
00971 /* }}} */
00972 
00973 /*
00974  * Local variables:
00975  * tab-width: 4
00976  * c-basic-offset: 4
00977  * End:
00978  * vim600: sw=4 ts=4 fdm=marker
00979  * vim<600: sw=4 ts=4
00980  */