1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2017 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 "zend_smart_str.h"
32 #include "basic_functions.h"
33 #include "php_incomplete_class.h"
34
35 #define COMMON (is_ref ? "&" : "")
36 /* }}} */
37
php_array_element_dump(zval * zv,zend_ulong index,zend_string * key,int level)38 static void php_array_element_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
39 {
40 if (key == NULL) { /* numeric key */
41 php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
42 } else { /* string key */
43 php_printf("%*c[\"", level + 1, ' ');
44 PHPWRITE(ZSTR_VAL(key), ZSTR_LEN(key));
45 php_printf("\"]=>\n");
46 }
47 php_var_dump(zv, level + 2);
48 }
49 /* }}} */
50
php_object_property_dump(zval * zv,zend_ulong index,zend_string * key,int level)51 static void php_object_property_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
52 {
53 const char *prop_name, *class_name;
54
55 if (key == NULL) { /* numeric key */
56 php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
57 } else { /* string key */
58 int unmangle = zend_unmangle_property_name(key, &class_name, &prop_name);
59 php_printf("%*c[", level + 1, ' ');
60
61 if (class_name && unmangle == SUCCESS) {
62 if (class_name[0] == '*') {
63 php_printf("\"%s\":protected", prop_name);
64 } else {
65 php_printf("\"%s\":\"%s\":private", prop_name, class_name);
66 }
67 } else {
68 php_printf("\"");
69 PHPWRITE(ZSTR_VAL(key), ZSTR_LEN(key));
70 php_printf("\"");
71 }
72 ZEND_PUTS("]=>\n");
73 }
74 php_var_dump(zv, level + 2);
75 }
76 /* }}} */
77
php_var_dump(zval * struc,int level)78 PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */
79 {
80 HashTable *myht;
81 zend_string *class_name;
82 int is_temp;
83 int is_ref = 0;
84 zend_ulong num;
85 zend_string *key;
86 zval *val;
87 uint32_t count;
88
89 if (level > 1) {
90 php_printf("%*c", level - 1, ' ');
91 }
92
93 again:
94 switch (Z_TYPE_P(struc)) {
95 case IS_FALSE:
96 php_printf("%sbool(false)\n", COMMON);
97 break;
98 case IS_TRUE:
99 php_printf("%sbool(true)\n", COMMON);
100 break;
101 case IS_NULL:
102 php_printf("%sNULL\n", COMMON);
103 break;
104 case IS_LONG:
105 php_printf("%sint(" ZEND_LONG_FMT ")\n", COMMON, Z_LVAL_P(struc));
106 break;
107 case IS_DOUBLE:
108 php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc));
109 break;
110 case IS_STRING:
111 php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc));
112 PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc));
113 PUTS("\"\n");
114 break;
115 case IS_ARRAY:
116 myht = Z_ARRVAL_P(struc);
117 if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht) && ++myht->u.v.nApplyCount > 1) {
118 PUTS("*RECURSION*\n");
119 --myht->u.v.nApplyCount;
120 return;
121 }
122 count = zend_array_count(myht);
123 php_printf("%sarray(%d) {\n", COMMON, count);
124 is_temp = 0;
125
126 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
127 php_array_element_dump(val, num, key, level);
128 } ZEND_HASH_FOREACH_END();
129 if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht)) {
130 --myht->u.v.nApplyCount;
131 }
132 if (is_temp) {
133 zend_hash_destroy(myht);
134 efree(myht);
135 }
136 if (level > 1) {
137 php_printf("%*c", level-1, ' ');
138 }
139 PUTS("}\n");
140 break;
141 case IS_OBJECT:
142 if (Z_OBJ_APPLY_COUNT_P(struc) > 0) {
143 PUTS("*RECURSION*\n");
144 return;
145 }
146 Z_OBJ_INC_APPLY_COUNT_P(struc);
147
148 myht = Z_OBJDEBUG_P(struc, is_temp);
149 class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
150 php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0);
151 zend_string_release(class_name);
152
153 if (myht) {
154 zend_ulong num;
155 zend_string *key;
156 zval *val;
157
158 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
159 php_object_property_dump(val, num, key, level);
160 } ZEND_HASH_FOREACH_END();
161 if (is_temp) {
162 zend_hash_destroy(myht);
163 efree(myht);
164 }
165 }
166 if (level > 1) {
167 php_printf("%*c", level-1, ' ');
168 }
169 PUTS("}\n");
170 Z_OBJ_DEC_APPLY_COUNT_P(struc);
171 break;
172 case IS_RESOURCE: {
173 const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
174 php_printf("%sresource(%pd) of type (%s)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown");
175 break;
176 }
177 case IS_REFERENCE:
178 //??? hide references with refcount==1 (for compatibility)
179 if (Z_REFCOUNT_P(struc) > 1) {
180 is_ref = 1;
181 }
182 struc = Z_REFVAL_P(struc);
183 goto again;
184 break;
185 default:
186 php_printf("%sUNKNOWN:0\n", COMMON);
187 break;
188 }
189 }
190 /* }}} */
191
192 /* {{{ proto void var_dump(mixed var)
193 Dumps a string representation of variable to output */
PHP_FUNCTION(var_dump)194 PHP_FUNCTION(var_dump)
195 {
196 zval *args;
197 int argc;
198 int i;
199
200 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
201 return;
202 }
203
204 for (i = 0; i < argc; i++) {
205 php_var_dump(&args[i], 1);
206 }
207 }
208 /* }}} */
209
zval_array_element_dump(zval * zv,zend_ulong index,zend_string * key,int level)210 static void zval_array_element_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
211 {
212 if (key == NULL) { /* numeric key */
213 php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
214 } else { /* string key */
215 php_printf("%*c[\"", level + 1, ' ');
216 PHPWRITE(ZSTR_VAL(key), ZSTR_LEN(key));
217 php_printf("\"]=>\n");
218 }
219 php_debug_zval_dump(zv, level + 2);
220 }
221 /* }}} */
222
zval_object_property_dump(zval * zv,zend_ulong index,zend_string * key,int level)223 static void zval_object_property_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
224 {
225 const char *prop_name, *class_name;
226
227 if (key == NULL) { /* numeric key */
228 php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
229 } else { /* string key */
230 zend_unmangle_property_name(key, &class_name, &prop_name);
231 php_printf("%*c[", level + 1, ' ');
232
233 if (class_name) {
234 if (class_name[0] == '*') {
235 php_printf("\"%s\":protected", prop_name);
236 } else {
237 php_printf("\"%s\":\"%s\":private", prop_name, class_name);
238 }
239 } else {
240 php_printf("\"%s\"", prop_name);
241 }
242 ZEND_PUTS("]=>\n");
243 }
244 php_debug_zval_dump(zv, level + 2);
245 }
246 /* }}} */
247
php_debug_zval_dump(zval * struc,int level)248 PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
249 {
250 HashTable *myht = NULL;
251 zend_string *class_name;
252 int is_temp = 0;
253 int is_ref = 0;
254 zend_ulong index;
255 zend_string *key;
256 zval *val;
257 uint32_t count;
258
259 if (level > 1) {
260 php_printf("%*c", level - 1, ' ');
261 }
262
263 again:
264 switch (Z_TYPE_P(struc)) {
265 case IS_FALSE:
266 php_printf("%sbool(false)\n", COMMON);
267 break;
268 case IS_TRUE:
269 php_printf("%sbool(true)\n", COMMON);
270 break;
271 case IS_NULL:
272 php_printf("%sNULL\n", COMMON);
273 break;
274 case IS_LONG:
275 php_printf("%sint(" ZEND_LONG_FMT ")\n", COMMON, Z_LVAL_P(struc));
276 break;
277 case IS_DOUBLE:
278 php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc));
279 break;
280 case IS_STRING:
281 php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc));
282 PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc));
283 php_printf("\" refcount(%u)\n", Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1);
284 break;
285 case IS_ARRAY:
286 myht = Z_ARRVAL_P(struc);
287 if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 1) {
288 myht->u.v.nApplyCount--;
289 PUTS("*RECURSION*\n");
290 return;
291 }
292 count = zend_array_count(myht);
293 php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1);
294 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
295 zval_array_element_dump(val, index, key, level);
296 } ZEND_HASH_FOREACH_END();
297 if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht)) {
298 myht->u.v.nApplyCount--;
299 }
300 if (is_temp) {
301 zend_hash_destroy(myht);
302 efree(myht);
303 }
304 if (level > 1) {
305 php_printf("%*c", level - 1, ' ');
306 }
307 PUTS("}\n");
308 break;
309 case IS_OBJECT:
310 myht = Z_OBJDEBUG_P(struc, is_temp);
311 if (myht) {
312 if (myht->u.v.nApplyCount > 1) {
313 PUTS("*RECURSION*\n");
314 return;
315 } else {
316 myht->u.v.nApplyCount++;
317 }
318 }
319 class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
320 php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc));
321 zend_string_release(class_name);
322 if (myht) {
323 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
324 zval_object_property_dump(val, index, key, level);
325 } ZEND_HASH_FOREACH_END();
326 myht->u.v.nApplyCount--;
327 if (is_temp) {
328 zend_hash_destroy(myht);
329 efree(myht);
330 }
331 }
332 if (level > 1) {
333 php_printf("%*c", level - 1, ' ');
334 }
335 PUTS("}\n");
336 break;
337 case IS_RESOURCE: {
338 const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
339 php_printf("%sresource(%d) of type (%s) refcount(%u)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
340 break;
341 }
342 case IS_REFERENCE:
343 //??? hide references with refcount==1 (for compatibility)
344 if (Z_REFCOUNT_P(struc) > 1) {
345 is_ref = 1;
346 }
347 struc = Z_REFVAL_P(struc);
348 goto again;
349 default:
350 php_printf("%sUNKNOWN:0\n", COMMON);
351 break;
352 }
353 }
354 /* }}} */
355
356 /* {{{ proto void debug_zval_dump(mixed var)
357 Dumps a string representation of an internal zend value to output. */
PHP_FUNCTION(debug_zval_dump)358 PHP_FUNCTION(debug_zval_dump)
359 {
360 zval *args;
361 int argc;
362 int i;
363
364 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
365 return;
366 }
367
368 for (i = 0; i < argc; i++) {
369 php_debug_zval_dump(&args[i], 1);
370 }
371 }
372 /* }}} */
373
374 #define buffer_append_spaces(buf, num_spaces) \
375 do { \
376 char *tmp_spaces; \
377 size_t tmp_spaces_len; \
378 tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \
379 smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \
380 efree(tmp_spaces); \
381 } while(0);
382
php_array_element_export(zval * zv,zend_ulong index,zend_string * key,int level,smart_str * buf)383 static void php_array_element_export(zval *zv, zend_ulong index, zend_string *key, int level, smart_str *buf) /* {{{ */
384 {
385 if (key == NULL) { /* numeric key */
386 buffer_append_spaces(buf, level+1);
387 smart_str_append_long(buf, (zend_long) index);
388 smart_str_appendl(buf, " => ", 4);
389
390 } else { /* string key */
391 zend_string *tmp_str;
392 zend_string *ckey = php_addcslashes(key, 0, "'\\", 2);
393 tmp_str = php_str_to_str(ZSTR_VAL(ckey), ZSTR_LEN(ckey), "\0", 1, "' . \"\\0\" . '", 12);
394
395 buffer_append_spaces(buf, level + 1);
396
397 smart_str_appendc(buf, '\'');
398 smart_str_append(buf, tmp_str);
399 smart_str_appendl(buf, "' => ", 5);
400
401 zend_string_free(ckey);
402 zend_string_free(tmp_str);
403 }
404 php_var_export_ex(zv, level + 2, buf);
405
406 smart_str_appendc(buf, ',');
407 smart_str_appendc(buf, '\n');
408 }
409 /* }}} */
410
php_object_element_export(zval * zv,zend_ulong index,zend_string * key,int level,smart_str * buf)411 static void php_object_element_export(zval *zv, zend_ulong index, zend_string *key, int level, smart_str *buf) /* {{{ */
412 {
413 buffer_append_spaces(buf, level + 2);
414 if (key != NULL) {
415 const char *class_name, *prop_name;
416 size_t prop_name_len;
417 zend_string *pname_esc;
418
419 zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
420 pname_esc = php_addcslashes(zend_string_init(prop_name, prop_name_len, 0), 1, "'\\", 2);
421
422 smart_str_appendc(buf, '\'');
423 smart_str_append(buf, pname_esc);
424 smart_str_appendc(buf, '\'');
425 zend_string_release(pname_esc);
426 } else {
427 smart_str_append_long(buf, (zend_long) index);
428 }
429 smart_str_appendl(buf, " => ", 4);
430 php_var_export_ex(zv, level + 2, buf);
431 smart_str_appendc(buf, ',');
432 smart_str_appendc(buf, '\n');
433 }
434 /* }}} */
435
php_var_export_ex(zval * struc,int level,smart_str * buf)436 PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
437 {
438 HashTable *myht;
439 char *tmp_str;
440 size_t tmp_len;
441 zend_string *ztmp, *ztmp2;
442 zend_ulong index;
443 zend_string *key;
444 zval *val;
445
446 again:
447 switch (Z_TYPE_P(struc)) {
448 case IS_FALSE:
449 smart_str_appendl(buf, "false", 5);
450 break;
451 case IS_TRUE:
452 smart_str_appendl(buf, "true", 4);
453 break;
454 case IS_NULL:
455 smart_str_appendl(buf, "NULL", 4);
456 break;
457 case IS_LONG:
458 smart_str_append_long(buf, Z_LVAL_P(struc));
459 break;
460 case IS_DOUBLE:
461 tmp_len = spprintf(&tmp_str, 0,"%.*H", PG(serialize_precision), Z_DVAL_P(struc));
462 smart_str_appendl(buf, tmp_str, tmp_len);
463 /* Without a decimal point, PHP treats a number literal as an int.
464 * This check even works for scientific notation, because the
465 * mantissa always contains a decimal point.
466 * We need to check for finiteness, because INF, -INF and NAN
467 * must not have a decimal point added.
468 */
469 if (zend_finite(Z_DVAL_P(struc)) && NULL == strchr(tmp_str, '.')) {
470 smart_str_appendl(buf, ".0", 2);
471 }
472 efree(tmp_str);
473 break;
474 case IS_STRING:
475 ztmp = php_addcslashes(Z_STR_P(struc), 0, "'\\", 2);
476 ztmp2 = php_str_to_str(ZSTR_VAL(ztmp), ZSTR_LEN(ztmp), "\0", 1, "' . \"\\0\" . '", 12);
477
478 smart_str_appendc(buf, '\'');
479 smart_str_append(buf, ztmp2);
480 smart_str_appendc(buf, '\'');
481
482 zend_string_free(ztmp);
483 zend_string_free(ztmp2);
484 break;
485 case IS_ARRAY:
486 myht = Z_ARRVAL_P(struc);
487 if (ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 0) {
488 myht->u.v.nApplyCount--;
489 smart_str_appendl(buf, "NULL", 4);
490 zend_error(E_WARNING, "var_export does not handle circular references");
491 return;
492 }
493 if (level > 1) {
494 smart_str_appendc(buf, '\n');
495 buffer_append_spaces(buf, level - 1);
496 }
497 smart_str_appendl(buf, "array (\n", 8);
498 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
499 php_array_element_export(val, index, key, level, buf);
500 } ZEND_HASH_FOREACH_END();
501 if (ZEND_HASH_APPLY_PROTECTION(myht)) {
502 myht->u.v.nApplyCount--;
503 }
504 if (level > 1) {
505 buffer_append_spaces(buf, level - 1);
506 }
507 smart_str_appendc(buf, ')');
508
509 break;
510
511 case IS_OBJECT:
512 myht = Z_OBJPROP_P(struc);
513 if (myht) {
514 if (myht->u.v.nApplyCount > 0) {
515 smart_str_appendl(buf, "NULL", 4);
516 zend_error(E_WARNING, "var_export does not handle circular references");
517 return;
518 } else {
519 myht->u.v.nApplyCount++;
520 }
521 }
522 if (level > 1) {
523 smart_str_appendc(buf, '\n');
524 buffer_append_spaces(buf, level - 1);
525 }
526
527 smart_str_append(buf, Z_OBJCE_P(struc)->name);
528 smart_str_appendl(buf, "::__set_state(array(\n", 21);
529
530 if (myht) {
531 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
532 php_object_element_export(val, index, key, level, buf);
533 } ZEND_HASH_FOREACH_END();
534 myht->u.v.nApplyCount--;
535 }
536 if (level > 1) {
537 buffer_append_spaces(buf, level - 1);
538 }
539 smart_str_appendl(buf, "))", 2);
540
541 break;
542 case IS_REFERENCE:
543 struc = Z_REFVAL_P(struc);
544 goto again;
545 break;
546 default:
547 smart_str_appendl(buf, "NULL", 4);
548 break;
549 }
550 }
551 /* }}} */
552
553 /* FOR BC reasons, this will always perform and then print */
php_var_export(zval * struc,int level)554 PHPAPI void php_var_export(zval *struc, int level) /* {{{ */
555 {
556 smart_str buf = {0};
557 php_var_export_ex(struc, level, &buf);
558 smart_str_0(&buf);
559 PHPWRITE(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
560 smart_str_free(&buf);
561 }
562 /* }}} */
563
564 /* {{{ proto mixed var_export(mixed var [, bool return])
565 Outputs or returns a string representation of a variable */
PHP_FUNCTION(var_export)566 PHP_FUNCTION(var_export)
567 {
568 zval *var;
569 zend_bool return_output = 0;
570 smart_str buf = {0};
571
572 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &var, &return_output) == FAILURE) {
573 return;
574 }
575
576 php_var_export_ex(var, 1, &buf);
577 smart_str_0 (&buf);
578
579 if (return_output) {
580 RETURN_NEW_STR(buf.s);
581 } else {
582 PHPWRITE(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
583 smart_str_free(&buf);
584 }
585 }
586 /* }}} */
587
588 static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash);
589
php_add_var_hash(php_serialize_data_t data,zval * var)590 static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var) /* {{{ */
591 {
592 zval *zv;
593 zend_ulong key;
594 zend_bool is_ref = Z_ISREF_P(var);
595
596 data->n += 1;
597
598 if (!is_ref && Z_TYPE_P(var) != IS_OBJECT) {
599 return 0;
600 }
601
602 /* References to objects are treated as if the reference didn't exist */
603 if (is_ref && Z_TYPE_P(Z_REFVAL_P(var)) == IS_OBJECT) {
604 var = Z_REFVAL_P(var);
605 }
606
607 /* Index for the variable is stored using the numeric value of the pointer to
608 * the zend_refcounted struct */
609 key = (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(var);
610 zv = zend_hash_index_find(&data->ht, key);
611
612 if (zv) {
613 /* References are only counted once, undo the data->n increment above */
614 if (is_ref) {
615 data->n -= 1;
616 }
617
618 return Z_LVAL_P(zv);
619 } else {
620 zval zv_n;
621 ZVAL_LONG(&zv_n, data->n);
622 zend_hash_index_add_new(&data->ht, key, &zv_n);
623
624 /* Additionally to the index, we also store the variable, to ensure that it is
625 * not destroyed during serialization and its pointer reused. The variable is
626 * stored at the numeric value of the pointer + 1, which cannot be the location
627 * of another zend_refcounted structure. */
628 zend_hash_index_add_new(&data->ht, key + 1, var);
629 Z_ADDREF_P(var);
630
631 return 0;
632 }
633 }
634 /* }}} */
635
php_var_serialize_long(smart_str * buf,zend_long val)636 static inline void php_var_serialize_long(smart_str *buf, zend_long val) /* {{{ */
637 {
638 smart_str_appendl(buf, "i:", 2);
639 smart_str_append_long(buf, val);
640 smart_str_appendc(buf, ';');
641 }
642 /* }}} */
643
php_var_serialize_string(smart_str * buf,char * str,size_t len)644 static inline void php_var_serialize_string(smart_str *buf, char *str, size_t len) /* {{{ */
645 {
646 smart_str_appendl(buf, "s:", 2);
647 smart_str_append_unsigned(buf, len);
648 smart_str_appendl(buf, ":\"", 2);
649 smart_str_appendl(buf, str, len);
650 smart_str_appendl(buf, "\";", 2);
651 }
652 /* }}} */
653
php_var_serialize_class_name(smart_str * buf,zval * struc)654 static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc) /* {{{ */
655 {
656 PHP_CLASS_ATTRIBUTES;
657
658 PHP_SET_CLASS_ATTRIBUTES(struc);
659 smart_str_appendl(buf, "O:", 2);
660 smart_str_append_unsigned(buf, ZSTR_LEN(class_name));
661 smart_str_appendl(buf, ":\"", 2);
662 smart_str_append(buf, class_name);
663 smart_str_appendl(buf, "\":", 2);
664 PHP_CLEANUP_CLASS_ATTRIBUTES();
665 return incomplete_class;
666 }
667 /* }}} */
668
php_var_serialize_collect_names(HashTable * src,uint32_t count,zend_bool incomplete)669 static HashTable *php_var_serialize_collect_names(HashTable *src, uint32_t count, zend_bool incomplete) /* {{{ */ {
670 zval *val;
671 HashTable *ht;
672 zend_string *key, *name;
673
674 ALLOC_HASHTABLE(ht);
675 zend_hash_init(ht, count, NULL, NULL, 0);
676 ZEND_HASH_FOREACH_STR_KEY_VAL(src, key, val) {
677 if (incomplete && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) {
678 continue;
679 }
680 if (Z_TYPE_P(val) != IS_STRING) {
681 php_error_docref(NULL, E_NOTICE,
682 "__sleep should return an array only containing the names of instance-variables to serialize.");
683 }
684 name = zval_get_string(val);
685 if (zend_hash_exists(ht, name)) {
686 php_error_docref(NULL, E_NOTICE,
687 "\"%s\" is returned from __sleep multiple times", ZSTR_VAL(name));
688 zend_string_release(name);
689 continue;
690 }
691 zend_hash_add_empty_element(ht, name);
692 zend_string_release(name);
693 } ZEND_HASH_FOREACH_END();
694
695 return ht;
696 }
697 /* }}} */
698
php_var_serialize_class(smart_str * buf,zval * struc,zval * retval_ptr,php_serialize_data_t var_hash)699 static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */
700 {
701 uint32_t count;
702 zend_bool incomplete_class;
703 HashTable *ht;
704
705 incomplete_class = php_var_serialize_class_name(buf, struc);
706 /* count after serializing name, since php_var_serialize_class_name
707 * changes the count if the variable is incomplete class */
708 if (Z_TYPE_P(retval_ptr) == IS_ARRAY) {
709 ht = Z_ARRVAL_P(retval_ptr);
710 count = zend_array_count(ht);
711 } else if (Z_TYPE_P(retval_ptr) == IS_OBJECT) {
712 ht = Z_OBJPROP_P(retval_ptr);
713 count = zend_array_count(ht);
714 if (incomplete_class) {
715 --count;
716 }
717 } else {
718 count = 0;
719 ht = NULL;
720 }
721
722 if (count > 0) {
723 zval *d;
724 zval nval, *nvalp;
725 zend_string *name;
726 HashTable *names, *propers;
727
728 names = php_var_serialize_collect_names(ht, count, incomplete_class);
729
730 smart_str_append_unsigned(buf, zend_hash_num_elements(names));
731 smart_str_appendl(buf, ":{", 2);
732
733 ZVAL_NULL(&nval);
734 nvalp = &nval;
735 propers = Z_OBJPROP_P(struc);
736
737 ZEND_HASH_FOREACH_STR_KEY(names, name) {
738 if ((d = zend_hash_find(propers, name)) != NULL) {
739 if (Z_TYPE_P(d) == IS_INDIRECT) {
740 d = Z_INDIRECT_P(d);
741 if (Z_TYPE_P(d) == IS_UNDEF) {
742 continue;
743 }
744 }
745 php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
746 php_var_serialize_intern(buf, d, var_hash);
747 } else {
748 zend_class_entry *ce = Z_OBJ_P(struc)->ce;
749 if (ce) {
750 zend_string *prot_name, *priv_name;
751
752 do {
753 priv_name = zend_mangle_property_name(
754 ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
755 if ((d = zend_hash_find(propers, priv_name)) != NULL) {
756 if (Z_TYPE_P(d) == IS_INDIRECT) {
757 d = Z_INDIRECT_P(d);
758 if (Z_ISUNDEF_P(d)) {
759 break;
760 }
761 }
762 php_var_serialize_string(buf, ZSTR_VAL(priv_name), ZSTR_LEN(priv_name));
763 zend_string_free(priv_name);
764 php_var_serialize_intern(buf, d, var_hash);
765 break;
766 }
767 zend_string_free(priv_name);
768 prot_name = zend_mangle_property_name(
769 "*", 1, ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
770 if ((d = zend_hash_find(propers, prot_name)) != NULL) {
771 if (Z_TYPE_P(d) == IS_INDIRECT) {
772 d = Z_INDIRECT_P(d);
773 if (Z_TYPE_P(d) == IS_UNDEF) {
774 zend_string_free(prot_name);
775 break;
776 }
777 }
778 php_var_serialize_string(buf, ZSTR_VAL(prot_name), ZSTR_LEN(prot_name));
779 zend_string_free(prot_name);
780 php_var_serialize_intern(buf, d, var_hash);
781 break;
782 }
783 zend_string_free(prot_name);
784 php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
785 php_var_serialize_intern(buf, nvalp, var_hash);
786 php_error_docref(NULL, E_NOTICE,
787 "\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(name));
788 } while (0);
789 } else {
790 php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
791 php_var_serialize_intern(buf, nvalp, var_hash);
792 }
793 }
794 } ZEND_HASH_FOREACH_END();
795 smart_str_appendc(buf, '}');
796
797 zend_hash_destroy(names);
798 FREE_HASHTABLE(names);
799 } else {
800 smart_str_appendl(buf, "0:{}", 4);
801 }
802 }
803 /* }}} */
804
php_var_serialize_intern(smart_str * buf,zval * struc,php_serialize_data_t var_hash)805 static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash) /* {{{ */
806 {
807 zend_long var_already;
808 HashTable *myht;
809
810 if (EG(exception)) {
811 return;
812 }
813
814 if (var_hash && (var_already = php_add_var_hash(var_hash, struc))) {
815 if (Z_ISREF_P(struc)) {
816 smart_str_appendl(buf, "R:", 2);
817 smart_str_append_long(buf, var_already);
818 smart_str_appendc(buf, ';');
819 return;
820 } else if (Z_TYPE_P(struc) == IS_OBJECT) {
821 smart_str_appendl(buf, "r:", 2);
822 smart_str_append_long(buf, var_already);
823 smart_str_appendc(buf, ';');
824 return;
825 }
826 }
827
828 again:
829 switch (Z_TYPE_P(struc)) {
830 case IS_FALSE:
831 smart_str_appendl(buf, "b:0;", 4);
832 return;
833
834 case IS_TRUE:
835 smart_str_appendl(buf, "b:1;", 4);
836 return;
837
838 case IS_NULL:
839 smart_str_appendl(buf, "N;", 2);
840 return;
841
842 case IS_LONG:
843 php_var_serialize_long(buf, Z_LVAL_P(struc));
844 return;
845
846 case IS_DOUBLE: {
847 char *s;
848
849 smart_str_appendl(buf, "d:", 2);
850 s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1);
851 php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', s);
852 smart_str_appends(buf, s);
853 smart_str_appendc(buf, ';');
854 efree(s);
855 return;
856 }
857
858 case IS_STRING:
859 php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc));
860 return;
861
862 case IS_OBJECT: {
863 zend_class_entry *ce = Z_OBJCE_P(struc);
864
865 if (ce->serialize != NULL) {
866 /* has custom handler */
867 unsigned char *serialized_data = NULL;
868 size_t serialized_length;
869
870 if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash) == SUCCESS) {
871 smart_str_appendl(buf, "C:", 2);
872 smart_str_append_unsigned(buf, ZSTR_LEN(Z_OBJCE_P(struc)->name));
873 smart_str_appendl(buf, ":\"", 2);
874 smart_str_append(buf, Z_OBJCE_P(struc)->name);
875 smart_str_appendl(buf, "\":", 2);
876
877 smart_str_append_unsigned(buf, serialized_length);
878 smart_str_appendl(buf, ":{", 2);
879 smart_str_appendl(buf, (char *) serialized_data, serialized_length);
880 smart_str_appendc(buf, '}');
881 } else {
882 smart_str_appendl(buf, "N;", 2);
883 }
884 if (serialized_data) {
885 efree(serialized_data);
886 }
887 return;
888 }
889
890 if (ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) {
891 zval fname, tmp, retval;
892 int res;
893
894 ZVAL_COPY(&tmp, struc);
895 ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1);
896 BG(serialize_lock)++;
897 res = call_user_function_ex(CG(function_table), &tmp, &fname, &retval, 0, 0, 1, NULL);
898 BG(serialize_lock)--;
899 zval_dtor(&fname);
900
901 if (EG(exception)) {
902 zval_ptr_dtor(&retval);
903 zval_ptr_dtor(&tmp);
904 return;
905 }
906
907 if (res == SUCCESS) {
908 if (Z_TYPE(retval) != IS_UNDEF) {
909 if (HASH_OF(&retval)) {
910 php_var_serialize_class(buf, &tmp, &retval, var_hash);
911 } else {
912 php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize");
913 /* we should still add element even if it's not OK,
914 * since we already wrote the length of the array before */
915 smart_str_appendl(buf,"N;", 2);
916 }
917 }
918 zval_ptr_dtor(&retval);
919 zval_ptr_dtor(&tmp);
920 return;
921 }
922 zval_ptr_dtor(&retval);
923 zval_ptr_dtor(&tmp);
924 }
925
926 /* fall-through */
927 }
928 case IS_ARRAY: {
929 uint32_t i;
930 zend_bool incomplete_class = 0;
931 if (Z_TYPE_P(struc) == IS_ARRAY) {
932 smart_str_appendl(buf, "a:", 2);
933 myht = Z_ARRVAL_P(struc);
934 i = zend_array_count(myht);
935 } else {
936 incomplete_class = php_var_serialize_class_name(buf, struc);
937 myht = Z_OBJPROP_P(struc);
938 /* count after serializing name, since php_var_serialize_class_name
939 * changes the count if the variable is incomplete class */
940 i = zend_array_count(myht);
941 if (i > 0 && incomplete_class) {
942 --i;
943 }
944 }
945 smart_str_append_unsigned(buf, i);
946 smart_str_appendl(buf, ":{", 2);
947 if (i > 0) {
948 zend_string *key;
949 zval *data;
950 zend_ulong index;
951
952 ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) {
953
954 if (incomplete_class && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) {
955 continue;
956 }
957
958 if (!key) {
959 php_var_serialize_long(buf, index);
960 } else {
961 php_var_serialize_string(buf, ZSTR_VAL(key), ZSTR_LEN(key));
962 }
963
964 if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
965 data = Z_REFVAL_P(data);
966 }
967
968 /* we should still add element even if it's not OK,
969 * since we already wrote the length of the array before */
970 if ((Z_TYPE_P(data) == IS_ARRAY && Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))
971 || (Z_TYPE_P(data) == IS_ARRAY && Z_ARRVAL_P(data)->u.v.nApplyCount > 1)
972 ) {
973 smart_str_appendl(buf, "N;", 2);
974 } else {
975 if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
976 Z_ARRVAL_P(data)->u.v.nApplyCount++;
977 }
978 php_var_serialize_intern(buf, data, var_hash);
979 if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
980 Z_ARRVAL_P(data)->u.v.nApplyCount--;
981 }
982 }
983 } ZEND_HASH_FOREACH_END();
984 }
985 smart_str_appendc(buf, '}');
986 return;
987 }
988 case IS_REFERENCE:
989 struc = Z_REFVAL_P(struc);
990 goto again;
991 default:
992 smart_str_appendl(buf, "i:0;", 4);
993 return;
994 }
995 }
996 /* }}} */
997
php_var_serialize(smart_str * buf,zval * struc,php_serialize_data_t * data)998 PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data) /* {{{ */
999 {
1000 php_var_serialize_intern(buf, struc, *data);
1001 smart_str_0(buf);
1002 }
1003 /* }}} */
1004
1005 /* {{{ proto string serialize(mixed variable)
1006 Returns a string representation of variable (which can later be unserialized) */
PHP_FUNCTION(serialize)1007 PHP_FUNCTION(serialize)
1008 {
1009 zval *struc;
1010 php_serialize_data_t var_hash;
1011 smart_str buf = {0};
1012
1013 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &struc) == FAILURE) {
1014 return;
1015 }
1016
1017 PHP_VAR_SERIALIZE_INIT(var_hash);
1018 php_var_serialize(&buf, struc, &var_hash);
1019 PHP_VAR_SERIALIZE_DESTROY(var_hash);
1020
1021 if (EG(exception)) {
1022 smart_str_free(&buf);
1023 RETURN_FALSE;
1024 }
1025
1026 if (buf.s) {
1027 RETURN_NEW_STR(buf.s);
1028 } else {
1029 RETURN_NULL();
1030 }
1031 }
1032 /* }}} */
1033
1034 /* {{{ proto mixed unserialize(string variable_representation[, array allowed_classes])
1035 Takes a string representation of variable and recreates it */
PHP_FUNCTION(unserialize)1036 PHP_FUNCTION(unserialize)
1037 {
1038 char *buf = NULL;
1039 size_t buf_len;
1040 const unsigned char *p;
1041 php_unserialize_data_t var_hash;
1042 zval *options = NULL, *classes = NULL;
1043 zval *retval;
1044 HashTable *class_hash = NULL;
1045
1046 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &options) == FAILURE) {
1047 RETURN_FALSE;
1048 }
1049
1050 if (buf_len == 0) {
1051 RETURN_FALSE;
1052 }
1053
1054 p = (const unsigned char*) buf;
1055 PHP_VAR_UNSERIALIZE_INIT(var_hash);
1056 if(options != NULL) {
1057 classes = zend_hash_str_find(Z_ARRVAL_P(options), "allowed_classes", sizeof("allowed_classes")-1);
1058 if(classes && (Z_TYPE_P(classes) == IS_ARRAY || !zend_is_true(classes))) {
1059 ALLOC_HASHTABLE(class_hash);
1060 zend_hash_init(class_hash, (Z_TYPE_P(classes) == IS_ARRAY)?zend_hash_num_elements(Z_ARRVAL_P(classes)):0, NULL, NULL, 0);
1061 }
1062 if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) {
1063 zval *entry;
1064 zend_string *lcname;
1065
1066 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) {
1067 convert_to_string_ex(entry);
1068 lcname = zend_string_tolower(Z_STR_P(entry));
1069 zend_hash_add_empty_element(class_hash, lcname);
1070 zend_string_release(lcname);
1071 } ZEND_HASH_FOREACH_END();
1072 }
1073 }
1074
1075 retval = var_tmp_var(&var_hash);
1076 if (!php_var_unserialize_ex(retval, &p, p + buf_len, &var_hash, class_hash)) {
1077 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1078 if (class_hash) {
1079 zend_hash_destroy(class_hash);
1080 FREE_HASHTABLE(class_hash);
1081 }
1082 if (!EG(exception)) {
1083 php_error_docref(NULL, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %zd bytes",
1084 (zend_long)((char*)p - buf), buf_len);
1085 }
1086 RETURN_FALSE;
1087 }
1088
1089 ZVAL_COPY(return_value, retval);
1090
1091 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1092 if (class_hash) {
1093 zend_hash_destroy(class_hash);
1094 FREE_HASHTABLE(class_hash);
1095 }
1096 }
1097 /* }}} */
1098
1099 /* {{{ proto int memory_get_usage([bool real_usage])
1100 Returns the allocated by PHP memory */
PHP_FUNCTION(memory_get_usage)1101 PHP_FUNCTION(memory_get_usage) {
1102 zend_bool real_usage = 0;
1103
1104 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &real_usage) == FAILURE) {
1105 RETURN_FALSE;
1106 }
1107
1108 RETURN_LONG(zend_memory_usage(real_usage));
1109 }
1110 /* }}} */
1111
1112 /* {{{ proto int memory_get_peak_usage([bool real_usage])
1113 Returns the peak allocated by PHP memory */
PHP_FUNCTION(memory_get_peak_usage)1114 PHP_FUNCTION(memory_get_peak_usage) {
1115 zend_bool real_usage = 0;
1116
1117 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &real_usage) == FAILURE) {
1118 RETURN_FALSE;
1119 }
1120
1121 RETURN_LONG(zend_memory_peak_usage(real_usage));
1122 }
1123 /* }}} */
1124
1125 /*
1126 * Local variables:
1127 * tab-width: 4
1128 * c-basic-offset: 4
1129 * End:
1130 * vim600: sw=4 ts=4 fdm=marker
1131 * vim<600: sw=4 ts=4
1132 */
1133