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