1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Jani Lehtimäki <jkl@njet.net> | 16 | Thies C. Arntzen <thies@thieso.net> | 17 | Sascha Schumann <sascha@schumann.cx> | 18 +----------------------------------------------------------------------+ 19*/ 20 21/* $Id$ */ 22 23/* {{{ includes 24*/ 25#include <stdio.h> 26#include <stdlib.h> 27#include <errno.h> 28#include "php.h" 29#include "php_string.h" 30#include "php_var.h" 31#include "php_smart_str.h" 32#include "basic_functions.h" 33#include "php_incomplete_class.h" 34 35#define COMMON (Z_ISREF_PP(struc) ? "&" : "") 36/* }}} */ 37 38static int php_array_element_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 39{ 40 int level; 41 42 level = va_arg(args, int); 43 44 if (hash_key->nKeyLength == 0) { /* numeric key */ 45 php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h); 46 } else { /* string key */ 47 php_printf("%*c[\"", level + 1, ' '); 48 PHPWRITE(hash_key->arKey, hash_key->nKeyLength - 1); 49 php_printf("\"]=>\n"); 50 } 51 php_var_dump(zv, level + 2 TSRMLS_CC); 52 return 0; 53} 54/* }}} */ 55 56static int php_object_property_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 57{ 58 int level; 59 const char *prop_name, *class_name; 60 61 level = va_arg(args, int); 62 63 if (hash_key->nKeyLength == 0) { /* numeric key */ 64 php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h); 65 } else { /* string key */ 66 int unmangle = zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name); 67 php_printf("%*c[", level + 1, ' '); 68 69 if (class_name && unmangle == SUCCESS) { 70 if (class_name[0] == '*') { 71 php_printf("\"%s\":protected", prop_name); 72 } else { 73 php_printf("\"%s\":\"%s\":private", prop_name, class_name); 74 } 75 } else { 76 php_printf("\""); 77 PHPWRITE(hash_key->arKey, hash_key->nKeyLength - 1); 78 php_printf("\""); 79 } 80 ZEND_PUTS("]=>\n"); 81 } 82 php_var_dump(zv, level + 2 TSRMLS_CC); 83 return 0; 84} 85/* }}} */ 86 87PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC) /* {{{ */ 88{ 89 HashTable *myht; 90 const char *class_name; 91 zend_uint class_name_len; 92 int (*php_element_dump_func)(zval** TSRMLS_DC, int, va_list, zend_hash_key*); 93 int is_temp; 94 95 if (level > 1) { 96 php_printf("%*c", level - 1, ' '); 97 } 98 99 switch (Z_TYPE_PP(struc)) { 100 case IS_BOOL: 101 php_printf("%sbool(%s)\n", COMMON, Z_LVAL_PP(struc) ? "true" : "false"); 102 break; 103 case IS_NULL: 104 php_printf("%sNULL\n", COMMON); 105 break; 106 case IS_LONG: 107 php_printf("%sint(%ld)\n", COMMON, Z_LVAL_PP(struc)); 108 break; 109 case IS_DOUBLE: 110 php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_PP(struc)); 111 break; 112 case IS_STRING: 113 php_printf("%sstring(%d) \"", COMMON, Z_STRLEN_PP(struc)); 114 PHPWRITE(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc)); 115 PUTS("\"\n"); 116 break; 117 case IS_ARRAY: 118 myht = Z_ARRVAL_PP(struc); 119 if (++myht->nApplyCount > 1) { 120 PUTS("*RECURSION*\n"); 121 --myht->nApplyCount; 122 return; 123 } 124 php_printf("%sarray(%d) {\n", COMMON, zend_hash_num_elements(myht)); 125 php_element_dump_func = php_array_element_dump; 126 is_temp = 0; 127 goto head_done; 128 case IS_OBJECT: 129 myht = Z_OBJDEBUG_PP(struc, is_temp); 130 if (myht && ++myht->nApplyCount > 1) { 131 PUTS("*RECURSION*\n"); 132 --myht->nApplyCount; 133 return; 134 } 135 136 if (Z_OBJ_HANDLER(**struc, get_class_name)) { 137 Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC); 138 php_printf("%sobject(%s)#%d (%d) {\n", COMMON, class_name, Z_OBJ_HANDLE_PP(struc), myht ? zend_hash_num_elements(myht) : 0); 139 efree((char*)class_name); 140 } else { 141 php_printf("%sobject(unknown class)#%d (%d) {\n", COMMON, Z_OBJ_HANDLE_PP(struc), myht ? zend_hash_num_elements(myht) : 0); 142 } 143 php_element_dump_func = php_object_property_dump; 144head_done: 145 if (myht) { 146 zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_element_dump_func, 1, level); 147 --myht->nApplyCount; 148 if (is_temp) { 149 zend_hash_destroy(myht); 150 efree(myht); 151 } 152 } 153 if (level > 1) { 154 php_printf("%*c", level-1, ' '); 155 } 156 PUTS("}\n"); 157 break; 158 case IS_RESOURCE: { 159 const char *type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(struc) TSRMLS_CC); 160 php_printf("%sresource(%ld) of type (%s)\n", COMMON, Z_LVAL_PP(struc), type_name ? type_name : "Unknown"); 161 break; 162 } 163 default: 164 php_printf("%sUNKNOWN:0\n", COMMON); 165 break; 166 } 167} 168/* }}} */ 169 170/* {{{ proto void var_dump(mixed var) 171 Dumps a string representation of variable to output */ 172PHP_FUNCTION(var_dump) 173{ 174 zval ***args; 175 int argc; 176 int i; 177 178 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) { 179 return; 180 } 181 182 for (i = 0; i < argc; i++) { 183 php_var_dump(args[i], 1 TSRMLS_CC); 184 } 185 efree(args); 186} 187/* }}} */ 188 189static int zval_array_element_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 190{ 191 int level; 192 193 level = va_arg(args, int); 194 195 if (hash_key->nKeyLength == 0) { /* numeric key */ 196 php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h); 197 } else { /* string key */ 198 /* XXX: perphaps when we are inside the class we should permit access to 199 * private & protected values 200 */ 201 if (va_arg(args, int) && hash_key->arKey[0] == '\0') { 202 return 0; 203 } 204 php_printf("%*c[\"", level + 1, ' '); 205 PHPWRITE(hash_key->arKey, hash_key->nKeyLength - 1); 206 php_printf("\"]=>\n"); 207 } 208 php_debug_zval_dump(zv, level + 2 TSRMLS_CC); 209 return 0; 210} 211/* }}} */ 212 213static int zval_object_property_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 214{ 215 int level; 216 const char *prop_name, *class_name; 217 218 level = va_arg(args, int); 219 220 if (hash_key->nKeyLength == 0) { /* numeric key */ 221 php_printf("%*c[%ld]=>\n", level + 1, ' ', hash_key->h); 222 } else { /* string key */ 223 zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name); 224 php_printf("%*c[", level + 1, ' '); 225 226 if (class_name) { 227 if (class_name[0] == '*') { 228 php_printf("\"%s\":protected", prop_name); 229 } else { 230 php_printf("\"%s\":\"%s\":private", prop_name, class_name); 231 } 232 } else { 233 php_printf("\"%s\"", prop_name); 234 } 235 ZEND_PUTS("]=>\n"); 236 } 237 php_debug_zval_dump(zv, level + 2 TSRMLS_CC); 238 return 0; 239} 240/* }}} */ 241 242PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC) /* {{{ */ 243{ 244 HashTable *myht = NULL; 245 const char *class_name; 246 zend_uint class_name_len; 247 int (*zval_element_dump_func)(zval** TSRMLS_DC, int, va_list, zend_hash_key*); 248 int is_temp = 0; 249 250 if (level > 1) { 251 php_printf("%*c", level - 1, ' '); 252 } 253 254 switch (Z_TYPE_PP(struc)) { 255 case IS_BOOL: 256 php_printf("%sbool(%s) refcount(%u)\n", COMMON, Z_LVAL_PP(struc)?"true":"false", Z_REFCOUNT_PP(struc)); 257 break; 258 case IS_NULL: 259 php_printf("%sNULL refcount(%u)\n", COMMON, Z_REFCOUNT_PP(struc)); 260 break; 261 case IS_LONG: 262 php_printf("%slong(%ld) refcount(%u)\n", COMMON, Z_LVAL_PP(struc), Z_REFCOUNT_PP(struc)); 263 break; 264 case IS_DOUBLE: 265 php_printf("%sdouble(%.*G) refcount(%u)\n", COMMON, (int) EG(precision), Z_DVAL_PP(struc), Z_REFCOUNT_PP(struc)); 266 break; 267 case IS_STRING: 268 php_printf("%sstring(%d) \"", COMMON, Z_STRLEN_PP(struc)); 269 PHPWRITE(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc)); 270 php_printf("\" refcount(%u)\n", Z_REFCOUNT_PP(struc)); 271 break; 272 case IS_ARRAY: 273 myht = Z_ARRVAL_PP(struc); 274 if (myht->nApplyCount > 1) { 275 PUTS("*RECURSION*\n"); 276 return; 277 } 278 php_printf("%sarray(%d) refcount(%u){\n", COMMON, zend_hash_num_elements(myht), Z_REFCOUNT_PP(struc)); 279 zval_element_dump_func = zval_array_element_dump; 280 goto head_done; 281 case IS_OBJECT: 282 myht = Z_OBJDEBUG_PP(struc, is_temp); 283 if (myht && myht->nApplyCount > 1) { 284 PUTS("*RECURSION*\n"); 285 return; 286 } 287 Z_OBJ_HANDLER_PP(struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC); 288 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)); 289 efree((char*)class_name); 290 zval_element_dump_func = zval_object_property_dump; 291head_done: 292 if (myht) { 293 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)); 294 if (is_temp) { 295 zend_hash_destroy(myht); 296 efree(myht); 297 } 298 } 299 if (level > 1) { 300 php_printf("%*c", level - 1, ' '); 301 } 302 PUTS("}\n"); 303 break; 304 case IS_RESOURCE: { 305 const char *type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(struc) TSRMLS_CC); 306 php_printf("%sresource(%ld) of type (%s) refcount(%u)\n", COMMON, Z_LVAL_PP(struc), type_name ? type_name : "Unknown", Z_REFCOUNT_PP(struc)); 307 break; 308 } 309 default: 310 php_printf("%sUNKNOWN:0\n", COMMON); 311 break; 312 } 313} 314/* }}} */ 315 316/* {{{ proto void debug_zval_dump(mixed var) 317 Dumps a string representation of an internal zend value to output. */ 318PHP_FUNCTION(debug_zval_dump) 319{ 320 zval ***args; 321 int argc; 322 int i; 323 324 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) { 325 return; 326 } 327 328 for (i = 0; i < argc; i++) { 329 php_debug_zval_dump(args[i], 1 TSRMLS_CC); 330 } 331 efree(args); 332} 333/* }}} */ 334 335#define buffer_append_spaces(buf, num_spaces) \ 336 do { \ 337 char *tmp_spaces; \ 338 int tmp_spaces_len; \ 339 tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \ 340 smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \ 341 efree(tmp_spaces); \ 342 } while(0); 343 344static int php_array_element_export(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 345{ 346 int level; 347 smart_str *buf; 348 349 level = va_arg(args, int); 350 buf = va_arg(args, smart_str *); 351 352 if (hash_key->nKeyLength == 0) { /* numeric key */ 353 buffer_append_spaces(buf, level+1); 354 smart_str_append_long(buf, (long) hash_key->h); 355 smart_str_appendl(buf, " => ", 4); 356 357 } else { /* string key */ 358 char *key, *tmp_str; 359 int key_len, tmp_len; 360 key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); 361 tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL); 362 363 buffer_append_spaces(buf, level + 1); 364 365 smart_str_appendc(buf, '\''); 366 smart_str_appendl(buf, tmp_str, tmp_len); 367 smart_str_appendl(buf, "' => ", 5); 368 369 efree(key); 370 efree(tmp_str); 371 } 372 php_var_export_ex(zv, level + 2, buf TSRMLS_CC); 373 374 smart_str_appendc(buf, ','); 375 smart_str_appendc(buf, '\n'); 376 377 return 0; 378} 379/* }}} */ 380 381static int php_object_element_export(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 382{ 383 int level; 384 smart_str *buf; 385 386 level = va_arg(args, int); 387 buf = va_arg(args, smart_str *); 388 389 buffer_append_spaces(buf, level + 2); 390 if (hash_key->nKeyLength != 0) { 391 const char *class_name; /* ignored, but must be passed to unmangle */ 392 const char *pname; 393 char *pname_esc; 394 int pname_esc_len; 395 396 zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, 397 &class_name, &pname); 398 pname_esc = php_addcslashes(pname, strlen(pname), &pname_esc_len, 0, 399 "'\\", 2 TSRMLS_CC); 400 401 smart_str_appendc(buf, '\''); 402 smart_str_appendl(buf, pname_esc, pname_esc_len); 403 smart_str_appendc(buf, '\''); 404 efree(pname_esc); 405 } else { 406 smart_str_append_long(buf, (long) hash_key->h); 407 } 408 smart_str_appendl(buf, " => ", 4); 409 php_var_export_ex(zv, level + 2, buf TSRMLS_CC); 410 smart_str_appendc(buf, ','); 411 smart_str_appendc(buf, '\n'); 412 return 0; 413} 414/* }}} */ 415 416PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) /* {{{ */ 417{ 418 HashTable *myht; 419 char *tmp_str, *tmp_str2; 420 int tmp_len, tmp_len2; 421 const char *class_name; 422 zend_uint class_name_len; 423 424 switch (Z_TYPE_PP(struc)) { 425 case IS_BOOL: 426 if (Z_LVAL_PP(struc)) { 427 smart_str_appendl(buf, "true", 4); 428 } else { 429 smart_str_appendl(buf, "false", 5); 430 } 431 break; 432 case IS_NULL: 433 smart_str_appendl(buf, "NULL", 4); 434 break; 435 case IS_LONG: 436 smart_str_append_long(buf, Z_LVAL_PP(struc)); 437 break; 438 case IS_DOUBLE: 439 tmp_len = spprintf(&tmp_str, 0,"%.*H", (int) EG(precision), Z_DVAL_PP(struc)); 440 smart_str_appendl(buf, tmp_str, tmp_len); 441 efree(tmp_str); 442 break; 443 case IS_STRING: 444 tmp_str = php_addcslashes(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc), &tmp_len, 0, "'\\", 2 TSRMLS_CC); 445 tmp_str2 = php_str_to_str_ex(tmp_str, tmp_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len2, 0, NULL); 446 447 smart_str_appendc(buf, '\''); 448 smart_str_appendl(buf, tmp_str2, tmp_len2); 449 smart_str_appendc(buf, '\''); 450 451 efree(tmp_str2); 452 efree(tmp_str); 453 break; 454 case IS_ARRAY: 455 myht = Z_ARRVAL_PP(struc); 456 if(myht && myht->nApplyCount > 0){ 457 smart_str_appendl(buf, "NULL", 4); 458 zend_error(E_WARNING, "var_export does not handle circular references"); 459 return; 460 } 461 if (level > 1) { 462 smart_str_appendc(buf, '\n'); 463 buffer_append_spaces(buf, level - 1); 464 } 465 smart_str_appendl(buf, "array (\n", 8); 466 zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_array_element_export, 2, level, buf); 467 468 if (level > 1) { 469 buffer_append_spaces(buf, level - 1); 470 } 471 smart_str_appendc(buf, ')'); 472 473 break; 474 475 case IS_OBJECT: 476 myht = Z_OBJPROP_PP(struc); 477 if(myht && myht->nApplyCount > 0){ 478 smart_str_appendl(buf, "NULL", 4); 479 zend_error(E_WARNING, "var_export does not handle circular references"); 480 return; 481 } 482 if (level > 1) { 483 smart_str_appendc(buf, '\n'); 484 buffer_append_spaces(buf, level - 1); 485 } 486 Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC); 487 488 smart_str_appendl(buf, class_name, class_name_len); 489 smart_str_appendl(buf, "::__set_state(array(\n", 21); 490 491 efree((char*)class_name); 492 if (myht) { 493 zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) php_object_element_export, 1, level, buf); 494 } 495 if (level > 1) { 496 buffer_append_spaces(buf, level - 1); 497 } 498 smart_str_appendl(buf, "))", 2); 499 500 break; 501 default: 502 smart_str_appendl(buf, "NULL", 4); 503 break; 504 } 505} 506/* }}} */ 507 508/* FOR BC reasons, this will always perform and then print */ 509PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) /* {{{ */ 510{ 511 smart_str buf = {0}; 512 php_var_export_ex(struc, level, &buf TSRMLS_CC); 513 smart_str_0 (&buf); 514 PHPWRITE(buf.c, buf.len); 515 smart_str_free(&buf); 516} 517/* }}} */ 518 519 520/* {{{ proto mixed var_export(mixed var [, bool return]) 521 Outputs or returns a string representation of a variable */ 522PHP_FUNCTION(var_export) 523{ 524 zval *var; 525 zend_bool return_output = 0; 526 smart_str buf = {0}; 527 528 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &var, &return_output) == FAILURE) { 529 return; 530 } 531 532 php_var_export_ex(&var, 1, &buf TSRMLS_CC); 533 smart_str_0 (&buf); 534 535 if (return_output) { 536 RETVAL_STRINGL(buf.c, buf.len, 1); 537 } else { 538 PHPWRITE(buf.c, buf.len); 539 } 540 smart_str_free(&buf); 541} 542/* }}} */ 543 544static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC); 545 546static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old TSRMLS_DC) /* {{{ */ 547{ 548 ulong var_no; 549 char id[32], *p; 550 register int len; 551 552 /* relies on "(long)" being a perfect hash function for data pointers, 553 * however the actual identity of an object has had to be determined 554 * by its object handle since 5.0. */ 555 if ((Z_TYPE_P(var) == IS_OBJECT) && Z_OBJ_HT_P(var)->get_class_entry) { 556 p = smart_str_print_long(id + sizeof(id) - 1, (long) Z_OBJ_HANDLE_P(var)); 557 *(--p) = 'O'; 558 len = id + sizeof(id) - 1 - p; 559 } else { 560 p = smart_str_print_long(id + sizeof(id) - 1, (long) var); 561 len = id + sizeof(id) - 1 - p; 562 } 563 564 if (var_old && zend_hash_find(var_hash, p, len, var_old) == SUCCESS) { 565 if (!Z_ISREF_P(var)) { 566 /* we still need to bump up the counter, since non-refs will 567 * be counted separately by unserializer */ 568 var_no = -1; 569 zend_hash_next_index_insert(var_hash, &var_no, sizeof(var_no), NULL); 570 } 571#if 0 572 fprintf(stderr, "- had var (%d): %lu\n", Z_TYPE_P(var), **(ulong**)var_old); 573#endif 574 return FAILURE; 575 } 576 577 /* +1 because otherwise hash will think we are trying to store NULL pointer */ 578 var_no = zend_hash_num_elements(var_hash) + 1; 579 zend_hash_add(var_hash, p, len, &var_no, sizeof(var_no), NULL); 580#if 0 581 fprintf(stderr, "+ add var (%d): %lu\n", Z_TYPE_P(var), var_no); 582#endif 583 return SUCCESS; 584} 585/* }}} */ 586 587static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ 588{ 589 smart_str_appendl(buf, "i:", 2); 590 smart_str_append_long(buf, val); 591 smart_str_appendc(buf, ';'); 592} 593/* }}} */ 594 595static inline void php_var_serialize_string(smart_str *buf, char *str, int len) /* {{{ */ 596{ 597 smart_str_appendl(buf, "s:", 2); 598 smart_str_append_long(buf, len); 599 smart_str_appendl(buf, ":\"", 2); 600 smart_str_appendl(buf, str, len); 601 smart_str_appendl(buf, "\";", 2); 602} 603/* }}} */ 604 605static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc TSRMLS_DC) /* {{{ */ 606{ 607 PHP_CLASS_ATTRIBUTES; 608 609 PHP_SET_CLASS_ATTRIBUTES(struc); 610 smart_str_appendl(buf, "O:", 2); 611 smart_str_append_long(buf, (int)name_len); 612 smart_str_appendl(buf, ":\"", 2); 613 smart_str_appendl(buf, class_name, name_len); 614 smart_str_appendl(buf, "\":", 2); 615 PHP_CLEANUP_CLASS_ATTRIBUTES(); 616 return incomplete_class; 617} 618/* }}} */ 619 620static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, HashTable *var_hash TSRMLS_DC) /* {{{ */ 621{ 622 int count; 623 zend_bool incomplete_class; 624 625 incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC); 626 /* count after serializing name, since php_var_serialize_class_name 627 * changes the count if the variable is incomplete class */ 628 count = zend_hash_num_elements(HASH_OF(retval_ptr)); 629 if (incomplete_class) { 630 --count; 631 } 632 smart_str_append_long(buf, count); 633 smart_str_appendl(buf, ":{", 2); 634 635 if (count > 0) { 636 char *key; 637 zval **d, **name; 638 ulong index; 639 HashPosition pos; 640 int i; 641 zval nval, *nvalp; 642 HashTable *propers; 643 644 ZVAL_NULL(&nval); 645 nvalp = &nval; 646 647 zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos); 648 649 for (;; zend_hash_move_forward_ex(HASH_OF(retval_ptr), &pos)) { 650 i = zend_hash_get_current_key_ex(HASH_OF(retval_ptr), &key, NULL, &index, 0, &pos); 651 652 if (i == HASH_KEY_NON_EXISTANT) { 653 break; 654 } 655 656 if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { 657 continue; 658 } 659 zend_hash_get_current_data_ex(HASH_OF(retval_ptr), (void **) &name, &pos); 660 661 if (Z_TYPE_PP(name) != IS_STRING) { 662 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize."); 663 /* we should still add element even if it's not OK, 664 * since we already wrote the length of the array before */ 665 smart_str_appendl(buf,"N;", 2); 666 continue; 667 } 668 propers = Z_OBJPROP_P(struc); 669 if (zend_hash_find(propers, Z_STRVAL_PP(name), Z_STRLEN_PP(name) + 1, (void *) &d) == SUCCESS) { 670 php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name)); 671 php_var_serialize_intern(buf, *d, var_hash TSRMLS_CC); 672 } else { 673 zend_class_entry *ce; 674 ce = zend_get_class_entry(struc TSRMLS_CC); 675 if (ce) { 676 char *prot_name, *priv_name; 677 int prop_name_length; 678 679 do { 680 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); 681 if (zend_hash_find(propers, priv_name, prop_name_length + 1, (void *) &d) == SUCCESS) { 682 php_var_serialize_string(buf, priv_name, prop_name_length); 683 pefree(priv_name, ce->type & ZEND_INTERNAL_CLASS); 684 php_var_serialize_intern(buf, *d, var_hash TSRMLS_CC); 685 break; 686 } 687 pefree(priv_name, ce->type & ZEND_INTERNAL_CLASS); 688 zend_mangle_property_name(&prot_name, &prop_name_length, "*", 1, Z_STRVAL_PP(name), Z_STRLEN_PP(name), ce->type & ZEND_INTERNAL_CLASS); 689 if (zend_hash_find(propers, prot_name, prop_name_length + 1, (void *) &d) == SUCCESS) { 690 php_var_serialize_string(buf, prot_name, prop_name_length); 691 pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); 692 php_var_serialize_intern(buf, *d, var_hash TSRMLS_CC); 693 break; 694 } 695 pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); 696 php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name)); 697 php_var_serialize_intern(buf, nvalp, var_hash TSRMLS_CC); 698 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", Z_STRVAL_PP(name)); 699 } while (0); 700 } else { 701 php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name)); 702 php_var_serialize_intern(buf, nvalp, var_hash TSRMLS_CC); 703 } 704 } 705 } 706 } 707 smart_str_appendc(buf, '}'); 708} 709/* }}} */ 710 711static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC) /* {{{ */ 712{ 713 int i; 714 ulong *var_already; 715 HashTable *myht; 716 717 if (EG(exception)) { 718 return; 719 } 720 721 if (var_hash && php_add_var_hash(var_hash, struc, (void *) &var_already TSRMLS_CC) == FAILURE) { 722 if (Z_ISREF_P(struc)) { 723 smart_str_appendl(buf, "R:", 2); 724 smart_str_append_long(buf, (long)*var_already); 725 smart_str_appendc(buf, ';'); 726 return; 727 } else if (Z_TYPE_P(struc) == IS_OBJECT) { 728 smart_str_appendl(buf, "r:", 2); 729 smart_str_append_long(buf, (long)*var_already); 730 smart_str_appendc(buf, ';'); 731 return; 732 } 733 } 734 735 switch (Z_TYPE_P(struc)) { 736 case IS_BOOL: 737 smart_str_appendl(buf, "b:", 2); 738 smart_str_append_long(buf, Z_LVAL_P(struc)); 739 smart_str_appendc(buf, ';'); 740 return; 741 742 case IS_NULL: 743 smart_str_appendl(buf, "N;", 2); 744 return; 745 746 case IS_LONG: 747 php_var_serialize_long(buf, Z_LVAL_P(struc)); 748 return; 749 750 case IS_DOUBLE: { 751 char *s; 752 753 smart_str_appendl(buf, "d:", 2); 754 s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); 755 php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s); 756 smart_str_appends(buf, s); 757 smart_str_appendc(buf, ';'); 758 efree(s); 759 return; 760 } 761 762 case IS_STRING: 763 php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc)); 764 return; 765 766 case IS_OBJECT: { 767 zval *retval_ptr = NULL; 768 zval fname; 769 int res; 770 zend_class_entry *ce = NULL; 771 772 if (Z_OBJ_HT_P(struc)->get_class_entry) { 773 ce = Z_OBJCE_P(struc); 774 } 775 776 if (ce && ce->serialize != NULL) { 777 /* has custom handler */ 778 unsigned char *serialized_data = NULL; 779 zend_uint serialized_length; 780 781 if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC) == SUCCESS) { 782 smart_str_appendl(buf, "C:", 2); 783 smart_str_append_long(buf, (int)Z_OBJCE_P(struc)->name_length); 784 smart_str_appendl(buf, ":\"", 2); 785 smart_str_appendl(buf, Z_OBJCE_P(struc)->name, Z_OBJCE_P(struc)->name_length); 786 smart_str_appendl(buf, "\":", 2); 787 788 smart_str_append_long(buf, (int)serialized_length); 789 smart_str_appendl(buf, ":{", 2); 790 smart_str_appendl(buf, serialized_data, serialized_length); 791 smart_str_appendc(buf, '}'); 792 } else { 793 smart_str_appendl(buf, "N;", 2); 794 } 795 if (serialized_data) { 796 efree(serialized_data); 797 } 798 return; 799 } 800 801 if (ce && ce != PHP_IC_ENTRY && zend_hash_exists(&ce->function_table, "__sleep", sizeof("__sleep"))) { 802 INIT_PZVAL(&fname); 803 ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1, 0); 804 BG(serialize_lock)++; 805 res = call_user_function_ex(CG(function_table), &struc, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); 806 BG(serialize_lock)--; 807 808 if (EG(exception)) { 809 if (retval_ptr) { 810 zval_ptr_dtor(&retval_ptr); 811 } 812 return; 813 } 814 815 if (res == SUCCESS) { 816 if (retval_ptr) { 817 if (HASH_OF(retval_ptr)) { 818 php_var_serialize_class(buf, struc, retval_ptr, var_hash TSRMLS_CC); 819 } else { 820 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize"); 821 /* we should still add element even if it's not OK, 822 * since we already wrote the length of the array before */ 823 smart_str_appendl(buf,"N;", 2); 824 } 825 zval_ptr_dtor(&retval_ptr); 826 } 827 return; 828 } 829 } 830 831 if (retval_ptr) { 832 zval_ptr_dtor(&retval_ptr); 833 } 834 /* fall-through */ 835 } 836 case IS_ARRAY: { 837 zend_bool incomplete_class = 0; 838 if (Z_TYPE_P(struc) == IS_ARRAY) { 839 smart_str_appendl(buf, "a:", 2); 840 myht = HASH_OF(struc); 841 } else { 842 incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC); 843 myht = Z_OBJPROP_P(struc); 844 } 845 /* count after serializing name, since php_var_serialize_class_name 846 * changes the count if the variable is incomplete class */ 847 i = myht ? zend_hash_num_elements(myht) : 0; 848 if (i > 0 && incomplete_class) { 849 --i; 850 } 851 smart_str_append_long(buf, i); 852 smart_str_appendl(buf, ":{", 2); 853 if (i > 0) { 854 char *key; 855 zval **data; 856 ulong index; 857 uint key_len; 858 HashPosition pos; 859 860 zend_hash_internal_pointer_reset_ex(myht, &pos); 861 for (;; zend_hash_move_forward_ex(myht, &pos)) { 862 i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); 863 if (i == HASH_KEY_NON_EXISTANT) { 864 break; 865 } 866 if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { 867 continue; 868 } 869 870 switch (i) { 871 case HASH_KEY_IS_LONG: 872 php_var_serialize_long(buf, index); 873 break; 874 case HASH_KEY_IS_STRING: 875 php_var_serialize_string(buf, key, key_len - 1); 876 break; 877 } 878 879 /* we should still add element even if it's not OK, 880 * since we already wrote the length of the array before */ 881 if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS 882 || !data 883 || data == &struc 884 || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) 885 ) { 886 smart_str_appendl(buf, "N;", 2); 887 } else { 888 if (Z_TYPE_PP(data) == IS_ARRAY) { 889 Z_ARRVAL_PP(data)->nApplyCount++; 890 } 891 php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); 892 if (Z_TYPE_PP(data) == IS_ARRAY) { 893 Z_ARRVAL_PP(data)->nApplyCount--; 894 } 895 } 896 } 897 } 898 smart_str_appendc(buf, '}'); 899 return; 900 } 901 default: 902 smart_str_appendl(buf, "i:0;", 4); 903 return; 904 } 905} 906/* }}} */ 907 908PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC) /* {{{ */ 909{ 910 php_var_serialize_intern(buf, *struc, *var_hash TSRMLS_CC); 911 smart_str_0(buf); 912} 913/* }}} */ 914 915/* {{{ proto string serialize(mixed variable) 916 Returns a string representation of variable (which can later be unserialized) */ 917PHP_FUNCTION(serialize) 918{ 919 zval **struc; 920 php_serialize_data_t var_hash; 921 smart_str buf = {0}; 922 923 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &struc) == FAILURE) { 924 return; 925 } 926 927 Z_TYPE_P(return_value) = IS_STRING; 928 Z_STRVAL_P(return_value) = NULL; 929 Z_STRLEN_P(return_value) = 0; 930 931 PHP_VAR_SERIALIZE_INIT(var_hash); 932 php_var_serialize(&buf, struc, &var_hash TSRMLS_CC); 933 PHP_VAR_SERIALIZE_DESTROY(var_hash); 934 935 if (EG(exception)) { 936 smart_str_free(&buf); 937 RETURN_FALSE; 938 } 939 940 if (buf.c) { 941 RETURN_STRINGL(buf.c, buf.len, 0); 942 } else { 943 RETURN_NULL(); 944 } 945} 946/* }}} */ 947 948/* {{{ proto mixed unserialize(string variable_representation) 949 Takes a string representation of variable and recreates it */ 950PHP_FUNCTION(unserialize) 951{ 952 char *buf = NULL; 953 int buf_len; 954 const unsigned char *p; 955 php_unserialize_data_t var_hash; 956 957 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { 958 RETURN_FALSE; 959 } 960 961 if (buf_len == 0) { 962 RETURN_FALSE; 963 } 964 965 p = (const unsigned char*) buf; 966 PHP_VAR_UNSERIALIZE_INIT(var_hash); 967 if (!php_var_unserialize(&return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) { 968 PHP_VAR_UNSERIALIZE_DESTROY(var_hash); 969 zval_dtor(return_value); 970 if (!EG(exception)) { 971 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len); 972 } 973 RETURN_FALSE; 974 } 975 PHP_VAR_UNSERIALIZE_DESTROY(var_hash); 976} 977/* }}} */ 978 979/* {{{ proto int memory_get_usage([real_usage]) 980 Returns the allocated by PHP memory */ 981PHP_FUNCTION(memory_get_usage) { 982 zend_bool real_usage = 0; 983 984 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &real_usage) == FAILURE) { 985 RETURN_FALSE; 986 } 987 988 RETURN_LONG(zend_memory_usage(real_usage TSRMLS_CC)); 989} 990/* }}} */ 991 992/* {{{ proto int memory_get_peak_usage([real_usage]) 993 Returns the peak allocated by PHP memory */ 994PHP_FUNCTION(memory_get_peak_usage) { 995 zend_bool real_usage = 0; 996 997 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &real_usage) == FAILURE) { 998 RETURN_FALSE; 999 } 1000 1001 RETURN_LONG(zend_memory_peak_usage(real_usage TSRMLS_CC)); 1002} 1003/* }}} */ 1004 1005/* 1006 * Local variables: 1007 * tab-width: 4 1008 * c-basic-offset: 4 1009 * End: 1010 * vim600: sw=4 ts=4 fdm=marker 1011 * vim<600: sw=4 ts=4 1012 */ 1013