xref: /PHP-7.2/ext/standard/var.c (revision 1fd32e9c)
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 	ZEND_PARSE_PARAMETERS_START(1, -1)
206 		Z_PARAM_VARIADIC('+', args, argc)
207 	ZEND_PARSE_PARAMETERS_END();
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 	ZEND_PARSE_PARAMETERS_START(1, -1)
370 		Z_PARAM_VARIADIC('+', args, argc)
371 	ZEND_PARSE_PARAMETERS_END();
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 			/* INT_MIN as a literal will be parsed as a float. Emit something like
463 			 * -9223372036854775807-1 to avoid this. */
464 			if (Z_LVAL_P(struc) == ZEND_LONG_MIN) {
465 				smart_str_append_long(buf, ZEND_LONG_MIN+1);
466 				smart_str_appends(buf, "-1");
467 				break;
468 			}
469 			smart_str_append_long(buf, Z_LVAL_P(struc));
470 			break;
471 		case IS_DOUBLE:
472 			php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
473 			smart_str_appends(buf, tmp_str);
474 			/* Without a decimal point, PHP treats a number literal as an int.
475 			 * This check even works for scientific notation, because the
476 			 * mantissa always contains a decimal point.
477 			 * We need to check for finiteness, because INF, -INF and NAN
478 			 * must not have a decimal point added.
479 			 */
480 			if (zend_finite(Z_DVAL_P(struc)) && NULL == strchr(tmp_str, '.')) {
481 				smart_str_appendl(buf, ".0", 2);
482 			}
483 			break;
484 		case IS_STRING:
485 			ztmp = php_addcslashes(Z_STR_P(struc), 0, "'\\", 2);
486 			ztmp2 = php_str_to_str(ZSTR_VAL(ztmp), ZSTR_LEN(ztmp), "\0", 1, "' . \"\\0\" . '", 12);
487 
488 			smart_str_appendc(buf, '\'');
489 			smart_str_append(buf, ztmp2);
490 			smart_str_appendc(buf, '\'');
491 
492 			zend_string_free(ztmp);
493 			zend_string_free(ztmp2);
494 			break;
495 		case IS_ARRAY:
496 			myht = Z_ARRVAL_P(struc);
497 			if (ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 0) {
498 				myht->u.v.nApplyCount--;
499 				smart_str_appendl(buf, "NULL", 4);
500 				zend_error(E_WARNING, "var_export does not handle circular references");
501 				return;
502 			}
503 			if (level > 1) {
504 				smart_str_appendc(buf, '\n');
505 				buffer_append_spaces(buf, level - 1);
506 			}
507 			smart_str_appendl(buf, "array (\n", 8);
508 			ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
509 				php_array_element_export(val, index, key, level, buf);
510 			} ZEND_HASH_FOREACH_END();
511 			if (ZEND_HASH_APPLY_PROTECTION(myht)) {
512 				myht->u.v.nApplyCount--;
513 			}
514 			if (level > 1) {
515 				buffer_append_spaces(buf, level - 1);
516 			}
517 			smart_str_appendc(buf, ')');
518 
519 			break;
520 
521 		case IS_OBJECT:
522 			myht = Z_OBJPROP_P(struc);
523 			if (myht) {
524 				if (myht->u.v.nApplyCount > 0) {
525 					smart_str_appendl(buf, "NULL", 4);
526 					zend_error(E_WARNING, "var_export does not handle circular references");
527 					return;
528 				} else {
529 					myht->u.v.nApplyCount++;
530 				}
531 			}
532 			if (level > 1) {
533 				smart_str_appendc(buf, '\n');
534 				buffer_append_spaces(buf, level - 1);
535 			}
536 
537 			smart_str_append(buf, Z_OBJCE_P(struc)->name);
538 			smart_str_appendl(buf, "::__set_state(array(\n", 21);
539 
540 			if (myht) {
541 				ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
542 					php_object_element_export(val, index, key, level, buf);
543 				} ZEND_HASH_FOREACH_END();
544 				myht->u.v.nApplyCount--;
545 			}
546 			if (level > 1) {
547 				buffer_append_spaces(buf, level - 1);
548 			}
549 			smart_str_appendl(buf, "))", 2);
550 
551 			break;
552 		case IS_REFERENCE:
553 			struc = Z_REFVAL_P(struc);
554 			goto again;
555 			break;
556 		default:
557 			smart_str_appendl(buf, "NULL", 4);
558 			break;
559 	}
560 }
561 /* }}} */
562 
563 /* FOR BC reasons, this will always perform and then print */
php_var_export(zval * struc,int level)564 PHPAPI void php_var_export(zval *struc, int level) /* {{{ */
565 {
566 	smart_str buf = {0};
567 	php_var_export_ex(struc, level, &buf);
568 	smart_str_0(&buf);
569 	PHPWRITE(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
570 	smart_str_free(&buf);
571 }
572 /* }}} */
573 
574 /* {{{ proto mixed var_export(mixed var [, bool return])
575    Outputs or returns a string representation of a variable */
PHP_FUNCTION(var_export)576 PHP_FUNCTION(var_export)
577 {
578 	zval *var;
579 	zend_bool return_output = 0;
580 	smart_str buf = {0};
581 
582 	ZEND_PARSE_PARAMETERS_START(1, 2)
583 		Z_PARAM_ZVAL(var)
584 		Z_PARAM_OPTIONAL
585 		Z_PARAM_BOOL(return_output)
586 	ZEND_PARSE_PARAMETERS_END();
587 
588 	php_var_export_ex(var, 1, &buf);
589 	smart_str_0 (&buf);
590 
591 	if (return_output) {
592 		RETURN_NEW_STR(buf.s);
593 	} else {
594 		PHPWRITE(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
595 		smart_str_free(&buf);
596 	}
597 }
598 /* }}} */
599 
600 static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash);
601 
php_add_var_hash(php_serialize_data_t data,zval * var)602 static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var) /* {{{ */
603 {
604 	zval *zv;
605 	zend_ulong key;
606 	zend_bool is_ref = Z_ISREF_P(var);
607 
608 	data->n += 1;
609 
610 	if (!is_ref && Z_TYPE_P(var) != IS_OBJECT) {
611 		return 0;
612 	}
613 
614 	/* References to objects are treated as if the reference didn't exist */
615 	if (is_ref && Z_TYPE_P(Z_REFVAL_P(var)) == IS_OBJECT) {
616 		var = Z_REFVAL_P(var);
617 	}
618 
619 	/* Index for the variable is stored using the numeric value of the pointer to
620 	 * the zend_refcounted struct */
621 	key = (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(var);
622 	zv = zend_hash_index_find(&data->ht, key);
623 
624 	if (zv) {
625 		/* References are only counted once, undo the data->n increment above */
626 		if (is_ref) {
627 			data->n -= 1;
628 		}
629 
630 		return Z_LVAL_P(zv);
631 	} else {
632 		zval zv_n;
633 		ZVAL_LONG(&zv_n, data->n);
634 		zend_hash_index_add_new(&data->ht, key, &zv_n);
635 
636 		/* Additionally to the index, we also store the variable, to ensure that it is
637 		 * not destroyed during serialization and its pointer reused. The variable is
638 		 * stored at the numeric value of the pointer + 1, which cannot be the location
639 		 * of another zend_refcounted structure. */
640 		zend_hash_index_add_new(&data->ht, key + 1, var);
641 		Z_ADDREF_P(var);
642 
643 		return 0;
644 	}
645 }
646 /* }}} */
647 
php_var_serialize_long(smart_str * buf,zend_long val)648 static inline void php_var_serialize_long(smart_str *buf, zend_long val) /* {{{ */
649 {
650 	smart_str_appendl(buf, "i:", 2);
651 	smart_str_append_long(buf, val);
652 	smart_str_appendc(buf, ';');
653 }
654 /* }}} */
655 
php_var_serialize_string(smart_str * buf,char * str,size_t len)656 static inline void php_var_serialize_string(smart_str *buf, char *str, size_t len) /* {{{ */
657 {
658 	smart_str_appendl(buf, "s:", 2);
659 	smart_str_append_unsigned(buf, len);
660 	smart_str_appendl(buf, ":\"", 2);
661 	smart_str_appendl(buf, str, len);
662 	smart_str_appendl(buf, "\";", 2);
663 }
664 /* }}} */
665 
php_var_serialize_class_name(smart_str * buf,zval * struc)666 static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc) /* {{{ */
667 {
668 	PHP_CLASS_ATTRIBUTES;
669 
670 	PHP_SET_CLASS_ATTRIBUTES(struc);
671 	smart_str_appendl(buf, "O:", 2);
672 	smart_str_append_unsigned(buf, ZSTR_LEN(class_name));
673 	smart_str_appendl(buf, ":\"", 2);
674 	smart_str_append(buf, class_name);
675 	smart_str_appendl(buf, "\":", 2);
676 	PHP_CLEANUP_CLASS_ATTRIBUTES();
677 	return incomplete_class;
678 }
679 /* }}} */
680 
php_var_serialize_call_sleep(zval * retval,zval * struc)681 static int php_var_serialize_call_sleep(zval *retval, zval *struc) /* {{{ */
682 {
683 	zval fname;
684 	int res;
685 
686 	ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1);
687 	BG(serialize_lock)++;
688 	res = call_user_function_ex(CG(function_table), struc, &fname, retval, 0, 0, 1, NULL);
689 	BG(serialize_lock)--;
690 	zval_dtor(&fname);
691 
692 	if (res == FAILURE || Z_ISUNDEF_P(retval)) {
693 		zval_ptr_dtor(retval);
694 		return FAILURE;
695 	}
696 
697 	if (!HASH_OF(retval)) {
698 		zval_ptr_dtor(retval);
699 		php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize");
700 		return FAILURE;
701 	}
702 
703 	return SUCCESS;
704 }
705 /* }}} */
706 
php_var_serialize_collect_names(HashTable * ht,HashTable * src)707 static void php_var_serialize_collect_names(HashTable *ht, HashTable *src) /* {{{ */
708 {
709 	zval *val;
710 	zend_string *name;
711 
712 	zend_hash_init(ht, zend_hash_num_elements(src), NULL, NULL, 0);
713 	ZEND_HASH_FOREACH_VAL(src, val) {
714 		if (Z_TYPE_P(val) != IS_STRING) {
715 			php_error_docref(NULL, E_NOTICE,
716 					"__sleep should return an array only containing the names of instance-variables to serialize.");
717 		}
718 
719 		name = zval_get_string(val);
720 		if (zend_hash_exists(ht, name)) {
721 			php_error_docref(NULL, E_NOTICE,
722 					"\"%s\" is returned from __sleep multiple times", ZSTR_VAL(name));
723 			zend_string_release(name);
724 			continue;
725 		}
726 		zend_hash_add_empty_element(ht, name);
727 		zend_string_release(name);
728 	} ZEND_HASH_FOREACH_END();
729 }
730 /* }}} */
731 
php_var_serialize_class(smart_str * buf,zval * struc,zval * retval_ptr,php_serialize_data_t var_hash)732 static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */
733 {
734 	zend_class_entry *ce = Z_OBJCE_P(struc);
735 	HashTable names, *propers;
736 	zval nval;
737 	zend_string *name;
738 
739 	php_var_serialize_class_name(buf, struc);
740 	php_var_serialize_collect_names(&names, HASH_OF(retval_ptr));
741 
742 	smart_str_append_unsigned(buf, zend_hash_num_elements(&names));
743 	smart_str_appendl(buf, ":{", 2);
744 
745 	ZVAL_NULL(&nval);
746 	propers = Z_OBJPROP_P(struc);
747 
748 	ZEND_HASH_FOREACH_STR_KEY(&names, name) {
749 		zend_string *prot_name, *priv_name;
750 
751 		zval *val = zend_hash_find(propers, name);
752 		if (val != NULL) {
753 			if (Z_TYPE_P(val) == IS_INDIRECT) {
754 				val = Z_INDIRECT_P(val);
755 				if (Z_TYPE_P(val) == IS_UNDEF) {
756 					goto undef_prop;
757 				}
758 			}
759 
760 			php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
761 			php_var_serialize_intern(buf, val, var_hash);
762 			continue;
763 		}
764 
765 		priv_name = zend_mangle_property_name(
766 				ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
767 		val = zend_hash_find(propers, priv_name);
768 		if (val != NULL) {
769 			if (Z_TYPE_P(val) == IS_INDIRECT) {
770 				val = Z_INDIRECT_P(val);
771 				if (Z_ISUNDEF_P(val)) {
772 					zend_string_free(priv_name);
773 					goto undef_prop;
774 				}
775 			}
776 
777 			php_var_serialize_string(buf, ZSTR_VAL(priv_name), ZSTR_LEN(priv_name));
778 			zend_string_free(priv_name);
779 			php_var_serialize_intern(buf, val, var_hash);
780 			continue;
781 		}
782 		zend_string_free(priv_name);
783 
784 		prot_name = zend_mangle_property_name(
785 				"*", 1, ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
786 		val = zend_hash_find(propers, prot_name);
787 		if (val != NULL) {
788 			if (Z_TYPE_P(val) == IS_INDIRECT) {
789 				val = Z_INDIRECT_P(val);
790 				if (Z_TYPE_P(val) == IS_UNDEF) {
791 					zend_string_free(prot_name);
792 					goto undef_prop;
793 				}
794 			}
795 
796 			php_var_serialize_string(buf, ZSTR_VAL(prot_name), ZSTR_LEN(prot_name));
797 			zend_string_free(prot_name);
798 			php_var_serialize_intern(buf, val, var_hash);
799 			continue;
800 		}
801 		zend_string_free(prot_name);
802 
803 undef_prop:
804 		php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
805 		php_var_serialize_intern(buf, &nval, var_hash);
806 		php_error_docref(NULL, E_NOTICE,
807 				"\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(name));
808 	} ZEND_HASH_FOREACH_END();
809 	smart_str_appendc(buf, '}');
810 
811 	zend_hash_destroy(&names);
812 }
813 /* }}} */
814 
php_var_serialize_intern(smart_str * buf,zval * struc,php_serialize_data_t var_hash)815 static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash) /* {{{ */
816 {
817 	zend_long var_already;
818 	HashTable *myht;
819 
820 	if (EG(exception)) {
821 		return;
822 	}
823 
824 	if (var_hash && (var_already = php_add_var_hash(var_hash, struc))) {
825 		if (Z_ISREF_P(struc)) {
826 			smart_str_appendl(buf, "R:", 2);
827 			smart_str_append_long(buf, var_already);
828 			smart_str_appendc(buf, ';');
829 			return;
830 		} else if (Z_TYPE_P(struc) == IS_OBJECT) {
831 			smart_str_appendl(buf, "r:", 2);
832 			smart_str_append_long(buf, var_already);
833 			smart_str_appendc(buf, ';');
834 			return;
835 		}
836 	}
837 
838 again:
839 	switch (Z_TYPE_P(struc)) {
840 		case IS_FALSE:
841 			smart_str_appendl(buf, "b:0;", 4);
842 			return;
843 
844 		case IS_TRUE:
845 			smart_str_appendl(buf, "b:1;", 4);
846 			return;
847 
848 		case IS_NULL:
849 			smart_str_appendl(buf, "N;", 2);
850 			return;
851 
852 		case IS_LONG:
853 			php_var_serialize_long(buf, Z_LVAL_P(struc));
854 			return;
855 
856 		case IS_DOUBLE: {
857 			char tmp_str[PHP_DOUBLE_MAX_LENGTH];
858 			smart_str_appendl(buf, "d:", 2);
859 			php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
860 			smart_str_appends(buf, tmp_str);
861 			smart_str_appendc(buf, ';');
862 			return;
863 		}
864 
865 		case IS_STRING:
866 			php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc));
867 			return;
868 
869 		case IS_OBJECT: {
870 				zend_class_entry *ce = Z_OBJCE_P(struc);
871 
872 				if (ce->serialize != NULL) {
873 					/* has custom handler */
874 					unsigned char *serialized_data = NULL;
875 					size_t serialized_length;
876 
877 					if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash) == SUCCESS) {
878 						smart_str_appendl(buf, "C:", 2);
879 						smart_str_append_unsigned(buf, ZSTR_LEN(Z_OBJCE_P(struc)->name));
880 						smart_str_appendl(buf, ":\"", 2);
881 						smart_str_append(buf, Z_OBJCE_P(struc)->name);
882 						smart_str_appendl(buf, "\":", 2);
883 
884 						smart_str_append_unsigned(buf, serialized_length);
885 						smart_str_appendl(buf, ":{", 2);
886 						smart_str_appendl(buf, (char *) serialized_data, serialized_length);
887 						smart_str_appendc(buf, '}');
888 					} else {
889 						smart_str_appendl(buf, "N;", 2);
890 					}
891 					if (serialized_data) {
892 						efree(serialized_data);
893 					}
894 					return;
895 				}
896 
897 				if (ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) {
898 					zval retval, tmp;
899 					ZVAL_COPY(&tmp, struc);
900 
901 					if (php_var_serialize_call_sleep(&retval, &tmp) == FAILURE) {
902 						if (!EG(exception)) {
903 							/* we should still add element even if it's not OK,
904 							 * since we already wrote the length of the array before */
905 							smart_str_appendl(buf, "N;", 2);
906 						}
907 						zval_ptr_dtor(&tmp);
908 						return;
909 					}
910 
911 					php_var_serialize_class(buf, &tmp, &retval, var_hash);
912 					zval_ptr_dtor(&retval);
913 					zval_ptr_dtor(&tmp);
914 					return;
915 				}
916 
917 				/* fall-through */
918 			}
919 		case IS_ARRAY: {
920 			uint32_t i;
921 			zend_bool incomplete_class = 0;
922 			if (Z_TYPE_P(struc) == IS_ARRAY) {
923 				smart_str_appendl(buf, "a:", 2);
924 				myht = Z_ARRVAL_P(struc);
925 				i = zend_array_count(myht);
926 			} else {
927 				incomplete_class = php_var_serialize_class_name(buf, struc);
928 				myht = Z_OBJPROP_P(struc);
929 				/* count after serializing name, since php_var_serialize_class_name
930 				 * changes the count if the variable is incomplete class */
931 				i = zend_array_count(myht);
932 				if (i > 0 && incomplete_class) {
933 					--i;
934 				}
935 			}
936 			smart_str_append_unsigned(buf, i);
937 			smart_str_appendl(buf, ":{", 2);
938 			if (i > 0) {
939 				zend_string *key;
940 				zval *data;
941 				zend_ulong index;
942 
943 				ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) {
944 
945 					if (incomplete_class && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) {
946 						continue;
947 					}
948 
949 					if (!key) {
950 						php_var_serialize_long(buf, index);
951 					} else {
952 						php_var_serialize_string(buf, ZSTR_VAL(key), ZSTR_LEN(key));
953 					}
954 
955 					if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
956 						data = Z_REFVAL_P(data);
957 					}
958 
959 					/* we should still add element even if it's not OK,
960 					 * since we already wrote the length of the array before */
961 					if ((Z_TYPE_P(data) == IS_ARRAY && Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))
962 						|| (Z_TYPE_P(data) == IS_ARRAY && Z_ARRVAL_P(data)->u.v.nApplyCount > 1)
963 					) {
964 						smart_str_appendl(buf, "N;", 2);
965 					} else {
966 						if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
967 							Z_ARRVAL_P(data)->u.v.nApplyCount++;
968 						}
969 						php_var_serialize_intern(buf, data, var_hash);
970 						if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
971 							Z_ARRVAL_P(data)->u.v.nApplyCount--;
972 						}
973 					}
974 				} ZEND_HASH_FOREACH_END();
975 			}
976 			smart_str_appendc(buf, '}');
977 			return;
978 		}
979 		case IS_REFERENCE:
980 			struc = Z_REFVAL_P(struc);
981 			goto again;
982 		default:
983 			smart_str_appendl(buf, "i:0;", 4);
984 			return;
985 	}
986 }
987 /* }}} */
988 
php_var_serialize(smart_str * buf,zval * struc,php_serialize_data_t * data)989 PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data) /* {{{ */
990 {
991 	php_var_serialize_intern(buf, struc, *data);
992 	smart_str_0(buf);
993 }
994 /* }}} */
995 
php_var_serialize_init()996 PHPAPI php_serialize_data_t php_var_serialize_init() {
997 	struct php_serialize_data *d;
998 	/* fprintf(stderr, "SERIALIZE_INIT      == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */
999 	if (BG(serialize_lock) || !BG(serialize).level) {
1000 		d = emalloc(sizeof(struct php_serialize_data));
1001 		zend_hash_init(&d->ht, 16, NULL, ZVAL_PTR_DTOR, 0);
1002 		d->n = 0;
1003 		if (!BG(serialize_lock)) {
1004 			BG(serialize).data = d;
1005 			BG(serialize).level = 1;
1006 		}
1007 	} else {
1008 		d = BG(serialize).data;
1009 		++BG(serialize).level;
1010 	}
1011 	return d;
1012 }
1013 
php_var_serialize_destroy(php_serialize_data_t d)1014 PHPAPI void php_var_serialize_destroy(php_serialize_data_t d) {
1015 	/* fprintf(stderr, "SERIALIZE_DESTROY   == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */
1016 	if (BG(serialize_lock) || BG(serialize).level == 1) {
1017 		zend_hash_destroy(&d->ht);
1018 		efree(d);
1019 	}
1020 	if (!BG(serialize_lock) && !--BG(serialize).level) {
1021 		BG(serialize).data = NULL;
1022 	}
1023 }
1024 
1025 /* {{{ proto string serialize(mixed variable)
1026    Returns a string representation of variable (which can later be unserialized) */
PHP_FUNCTION(serialize)1027 PHP_FUNCTION(serialize)
1028 {
1029 	zval *struc;
1030 	php_serialize_data_t var_hash;
1031 	smart_str buf = {0};
1032 
1033 	ZEND_PARSE_PARAMETERS_START(1, 1)
1034 		Z_PARAM_ZVAL(struc)
1035 	ZEND_PARSE_PARAMETERS_END();
1036 
1037 	PHP_VAR_SERIALIZE_INIT(var_hash);
1038 	php_var_serialize(&buf, struc, &var_hash);
1039 	PHP_VAR_SERIALIZE_DESTROY(var_hash);
1040 
1041 	if (EG(exception)) {
1042 		smart_str_free(&buf);
1043 		RETURN_FALSE;
1044 	}
1045 
1046 	if (buf.s) {
1047 		RETURN_NEW_STR(buf.s);
1048 	} else {
1049 		RETURN_NULL();
1050 	}
1051 }
1052 /* }}} */
1053 
1054 /* {{{ proto mixed unserialize(string variable_representation[, array allowed_classes])
1055    Takes a string representation of variable and recreates it */
PHP_FUNCTION(unserialize)1056 PHP_FUNCTION(unserialize)
1057 {
1058 	char *buf = NULL;
1059 	size_t buf_len;
1060 	const unsigned char *p;
1061 	php_unserialize_data_t var_hash;
1062 	zval *options = NULL, *classes = NULL;
1063 	zval *retval;
1064 	HashTable *class_hash = NULL, *prev_class_hash;
1065 
1066 	ZEND_PARSE_PARAMETERS_START(1, 2)
1067 		Z_PARAM_STRING(buf, buf_len)
1068 		Z_PARAM_OPTIONAL
1069 		Z_PARAM_ARRAY(options)
1070 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1071 
1072 	if (buf_len == 0) {
1073 		RETURN_FALSE;
1074 	}
1075 
1076 	p = (const unsigned char*) buf;
1077 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
1078 
1079 	prev_class_hash = php_var_unserialize_get_allowed_classes(var_hash);
1080 	if (options != NULL) {
1081 		classes = zend_hash_str_find(Z_ARRVAL_P(options), "allowed_classes", sizeof("allowed_classes")-1);
1082 		if (classes && Z_TYPE_P(classes) != IS_ARRAY && Z_TYPE_P(classes) != IS_TRUE && Z_TYPE_P(classes) != IS_FALSE) {
1083 			php_error_docref(NULL, E_WARNING, "allowed_classes option should be array or boolean");
1084 			PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1085 			RETURN_FALSE;
1086 		}
1087 
1088 		if(classes && (Z_TYPE_P(classes) == IS_ARRAY || !zend_is_true(classes))) {
1089 			ALLOC_HASHTABLE(class_hash);
1090 			zend_hash_init(class_hash, (Z_TYPE_P(classes) == IS_ARRAY)?zend_hash_num_elements(Z_ARRVAL_P(classes)):0, NULL, NULL, 0);
1091 		}
1092 		if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) {
1093 			zval *entry;
1094 			zend_string *lcname;
1095 
1096 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) {
1097 				convert_to_string_ex(entry);
1098 				lcname = zend_string_tolower(Z_STR_P(entry));
1099 				zend_hash_add_empty_element(class_hash, lcname);
1100 		        zend_string_release(lcname);
1101 			} ZEND_HASH_FOREACH_END();
1102 		}
1103 		php_var_unserialize_set_allowed_classes(var_hash, class_hash);
1104 	}
1105 
1106 	retval = var_tmp_var(&var_hash);
1107 	if (!php_var_unserialize(retval, &p, p + buf_len, &var_hash)) {
1108 		if (!EG(exception)) {
1109 			php_error_docref(NULL, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %zd bytes",
1110 				(zend_long)((char*)p - buf), buf_len);
1111 		}
1112 		RETVAL_FALSE;
1113 	} else {
1114 		ZVAL_COPY(return_value, retval);
1115 	}
1116 
1117 	if (class_hash) {
1118 		zend_hash_destroy(class_hash);
1119 		FREE_HASHTABLE(class_hash);
1120 	}
1121 
1122 	/* Reset to previous allowed_classes in case this is a nested call */
1123 	php_var_unserialize_set_allowed_classes(var_hash, prev_class_hash);
1124 	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1125 
1126 	/* Per calling convention we must not return a reference here, so unwrap. We're doing this at
1127 	 * the very end, because __wakeup() calls performed during UNSERIALIZE_DESTROY might affect
1128 	 * the value we unwrap here. This is compatible with behavior in PHP <=7.0. */
1129 	if (Z_ISREF_P(return_value)) {
1130 		zend_unwrap_reference(return_value);
1131 	}
1132 }
1133 /* }}} */
1134 
1135 /* {{{ proto int memory_get_usage([bool real_usage])
1136    Returns the allocated by PHP memory */
PHP_FUNCTION(memory_get_usage)1137 PHP_FUNCTION(memory_get_usage) {
1138 	zend_bool real_usage = 0;
1139 
1140 	ZEND_PARSE_PARAMETERS_START(0, 1)
1141 		Z_PARAM_OPTIONAL
1142 		Z_PARAM_BOOL(real_usage)
1143 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1144 
1145 	RETURN_LONG(zend_memory_usage(real_usage));
1146 }
1147 /* }}} */
1148 
1149 /* {{{ proto int memory_get_peak_usage([bool real_usage])
1150    Returns the peak allocated by PHP memory */
PHP_FUNCTION(memory_get_peak_usage)1151 PHP_FUNCTION(memory_get_peak_usage) {
1152 	zend_bool real_usage = 0;
1153 
1154 	ZEND_PARSE_PARAMETERS_START(0, 1)
1155 		Z_PARAM_OPTIONAL
1156 		Z_PARAM_BOOL(real_usage)
1157 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1158 
1159 	RETURN_LONG(zend_memory_peak_usage(real_usage));
1160 }
1161 /* }}} */
1162 
1163 /*
1164  * Local variables:
1165  * tab-width: 4
1166  * c-basic-offset: 4
1167  * End:
1168  * vim600: sw=4 ts=4 fdm=marker
1169  * vim<600: sw=4 ts=4
1170  */
1171