xref: /PHP-5.6/ext/json/json.c (revision 1ed4b13f)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2016 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   | Author: Omar Kilani <omar@php.net>                                   |
16   +----------------------------------------------------------------------+
17 */
18 
19 /* $Id$ */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "ext/standard/html.h"
29 #include "ext/standard/php_smart_str.h"
30 #include "JSON_parser.h"
31 #include "php_json.h"
32 #include <zend_exceptions.h>
33 
34 #include <float.h>
35 #if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
36 #define NUM_BUF_SIZE (3 + DBL_MANT_DIG - DBL_MIN_EXP)
37 #else
38 #define NUM_BUF_SIZE 1080
39 #endif
40 
41 
42 static PHP_MINFO_FUNCTION(json);
43 static PHP_FUNCTION(json_encode);
44 static PHP_FUNCTION(json_decode);
45 static PHP_FUNCTION(json_last_error);
46 static PHP_FUNCTION(json_last_error_msg);
47 
48 static const char digits[] = "0123456789abcdef";
49 
50 PHP_JSON_API zend_class_entry *php_json_serializable_ce;
51 
52 ZEND_DECLARE_MODULE_GLOBALS(json)
53 
54 /* {{{ arginfo */
55 ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
56 	ZEND_ARG_INFO(0, value)
57 	ZEND_ARG_INFO(0, options)
58 	ZEND_ARG_INFO(0, depth)
59 ZEND_END_ARG_INFO()
60 
61 ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
62 	ZEND_ARG_INFO(0, json)
63 	ZEND_ARG_INFO(0, assoc)
64 	ZEND_ARG_INFO(0, depth)
65 	ZEND_ARG_INFO(0, options)
66 ZEND_END_ARG_INFO()
67 
68 ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
69 ZEND_END_ARG_INFO()
70 
71 ZEND_BEGIN_ARG_INFO(arginfo_json_last_error_msg, 0)
72 ZEND_END_ARG_INFO()
73 /* }}} */
74 
75 /* {{{ json_functions[] */
76 static const zend_function_entry json_functions[] = {
77 	PHP_FE(json_encode, arginfo_json_encode)
78 	PHP_FE(json_decode, arginfo_json_decode)
79 	PHP_FE(json_last_error, arginfo_json_last_error)
80 	PHP_FE(json_last_error_msg, arginfo_json_last_error_msg)
81 	PHP_FE_END
82 };
83 /* }}} */
84 
85 /* {{{ JsonSerializable methods */
86 ZEND_BEGIN_ARG_INFO(json_serialize_arginfo, 0)
87 	/* No arguments */
88 ZEND_END_ARG_INFO();
89 
90 static const zend_function_entry json_serializable_interface[] = {
91 	PHP_ABSTRACT_ME(JsonSerializable, jsonSerialize, json_serialize_arginfo)
92 	PHP_FE_END
93 };
94 /* }}} */
95 
96 /* {{{ MINIT */
PHP_MINIT_FUNCTION(json)97 static PHP_MINIT_FUNCTION(json)
98 {
99 	zend_class_entry ce;
100 
101 	INIT_CLASS_ENTRY(ce, "JsonSerializable", json_serializable_interface);
102 	php_json_serializable_ce = zend_register_internal_interface(&ce TSRMLS_CC);
103 
104 	REGISTER_LONG_CONSTANT("JSON_HEX_TAG",  PHP_JSON_HEX_TAG,  CONST_CS | CONST_PERSISTENT);
105 	REGISTER_LONG_CONSTANT("JSON_HEX_AMP",  PHP_JSON_HEX_AMP,  CONST_CS | CONST_PERSISTENT);
106 	REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
107 	REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
108 	REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
109 	REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT);
110 	REGISTER_LONG_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES, CONST_CS | CONST_PERSISTENT);
111 	REGISTER_LONG_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT);
112 	REGISTER_LONG_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT);
113 	REGISTER_LONG_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT);
114 	REGISTER_LONG_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION, CONST_CS | CONST_PERSISTENT);
115 
116 	REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
117 	REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
118 	REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
119 	REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
120 	REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
121 	REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT);
122 	REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT);
123 	REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT);
124 	REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT);
125 
126 	REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY",		PHP_JSON_OBJECT_AS_ARRAY,		CONST_CS | CONST_PERSISTENT);
127 	REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING",		PHP_JSON_BIGINT_AS_STRING,		CONST_CS | CONST_PERSISTENT);
128 
129 	return SUCCESS;
130 }
131 /* }}} */
132 
133 /* {{{ PHP_GINIT_FUNCTION
134 */
PHP_GINIT_FUNCTION(json)135 static PHP_GINIT_FUNCTION(json)
136 {
137 	json_globals->encoder_depth = 0;
138 	json_globals->error_code = 0;
139 	json_globals->encode_max_depth = 0;
140 }
141 /* }}} */
142 
143 
144 /* {{{ json_module_entry
145  */
146 zend_module_entry json_module_entry = {
147 	STANDARD_MODULE_HEADER,
148 	"json",
149 	json_functions,
150 	PHP_MINIT(json),
151 	NULL,
152 	NULL,
153 	NULL,
154 	PHP_MINFO(json),
155 	PHP_JSON_VERSION,
156 	PHP_MODULE_GLOBALS(json),
157 	PHP_GINIT(json),
158 	NULL,
159 	NULL,
160 	STANDARD_MODULE_PROPERTIES_EX
161 };
162 /* }}} */
163 
164 #ifdef COMPILE_DL_JSON
165 ZEND_GET_MODULE(json)
166 #endif
167 
168 /* {{{ PHP_MINFO_FUNCTION
169  */
PHP_MINFO_FUNCTION(json)170 static PHP_MINFO_FUNCTION(json)
171 {
172 	php_info_print_table_start();
173 	php_info_print_table_row(2, "json support", "enabled");
174 	php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
175 	php_info_print_table_end();
176 }
177 /* }}} */
178 
179 static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC);
180 
json_determine_array_type(zval ** val TSRMLS_DC)181 static int json_determine_array_type(zval **val TSRMLS_DC) /* {{{ */
182 {
183 	int i;
184 	HashTable *myht = HASH_OF(*val);
185 
186 	i = myht ? zend_hash_num_elements(myht) : 0;
187 	if (i > 0) {
188 		char *key;
189 		ulong index, idx;
190 		uint key_len;
191 		HashPosition pos;
192 
193 		zend_hash_internal_pointer_reset_ex(myht, &pos);
194 		idx = 0;
195 		for (;; zend_hash_move_forward_ex(myht, &pos)) {
196 			i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
197 			if (i == HASH_KEY_NON_EXISTENT) {
198 				break;
199 			}
200 
201 			if (i == HASH_KEY_IS_STRING) {
202 				return 1;
203 			} else {
204 				if (index != idx) {
205 					return 1;
206 				}
207 			}
208 			idx++;
209 		}
210 	}
211 
212 	return PHP_JSON_OUTPUT_ARRAY;
213 }
214 /* }}} */
215 
216 /* {{{ Pretty printing support functions */
217 
json_pretty_print_char(smart_str * buf,int options,char c TSRMLS_DC)218 static inline void json_pretty_print_char(smart_str *buf, int options, char c TSRMLS_DC) /* {{{ */
219 {
220 	if (options & PHP_JSON_PRETTY_PRINT) {
221 		smart_str_appendc(buf, c);
222 	}
223 }
224 /* }}} */
225 
json_pretty_print_indent(smart_str * buf,int options TSRMLS_DC)226 static inline void json_pretty_print_indent(smart_str *buf, int options TSRMLS_DC) /* {{{ */
227 {
228 	int i;
229 
230 	if (options & PHP_JSON_PRETTY_PRINT) {
231 		for (i = 0; i < JSON_G(encoder_depth); ++i) {
232 			smart_str_appendl(buf, "    ", 4);
233 		}
234 	}
235 }
236 /* }}} */
237 
238 /* }}} */
239 
json_encode_array(smart_str * buf,zval ** val,int options TSRMLS_DC)240 static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */
241 {
242 	int i, r, need_comma = 0;
243 	HashTable *myht;
244 
245 	if (Z_TYPE_PP(val) == IS_ARRAY) {
246 		myht = HASH_OF(*val);
247 		r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC);
248 	} else {
249 		myht = Z_OBJPROP_PP(val);
250 		r = PHP_JSON_OUTPUT_OBJECT;
251 	}
252 
253 	if (myht && myht->nApplyCount > 1) {
254 		JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
255 		smart_str_appendl(buf, "null", 4);
256 		return;
257 	}
258 
259 	if (r == PHP_JSON_OUTPUT_ARRAY) {
260 		smart_str_appendc(buf, '[');
261 	} else {
262 		smart_str_appendc(buf, '{');
263 	}
264 
265 	++JSON_G(encoder_depth);
266 
267 	i = myht ? zend_hash_num_elements(myht) : 0;
268 
269 	if (i > 0)
270 	{
271 		char *key;
272 		zval **data;
273 		ulong index;
274 		uint key_len;
275 		HashPosition pos;
276 		HashTable *tmp_ht;
277 
278 		zend_hash_internal_pointer_reset_ex(myht, &pos);
279 		for (;; zend_hash_move_forward_ex(myht, &pos)) {
280 			i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
281 			if (i == HASH_KEY_NON_EXISTENT)
282 				break;
283 
284 			if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
285 				tmp_ht = HASH_OF(*data);
286 				if (tmp_ht) {
287 					tmp_ht->nApplyCount++;
288 				}
289 
290 				if (r == PHP_JSON_OUTPUT_ARRAY) {
291 					if (need_comma) {
292 						smart_str_appendc(buf, ',');
293 					} else {
294 						need_comma = 1;
295 					}
296 
297 					json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
298 					json_pretty_print_indent(buf, options TSRMLS_CC);
299 					php_json_encode(buf, *data, options TSRMLS_CC);
300 				} else if (r == PHP_JSON_OUTPUT_OBJECT) {
301 					if (i == HASH_KEY_IS_STRING) {
302 						if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) {
303 							/* Skip protected and private members. */
304 							if (tmp_ht) {
305 								tmp_ht->nApplyCount--;
306 							}
307 							continue;
308 						}
309 
310 						if (need_comma) {
311 							smart_str_appendc(buf, ',');
312 						} else {
313 							need_comma = 1;
314 						}
315 
316 						json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
317 						json_pretty_print_indent(buf, options TSRMLS_CC);
318 
319 						json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC);
320 						smart_str_appendc(buf, ':');
321 
322 						json_pretty_print_char(buf, options, ' ' TSRMLS_CC);
323 
324 						php_json_encode(buf, *data, options TSRMLS_CC);
325 					} else {
326 						if (need_comma) {
327 							smart_str_appendc(buf, ',');
328 						} else {
329 							need_comma = 1;
330 						}
331 
332 						json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
333 						json_pretty_print_indent(buf, options TSRMLS_CC);
334 
335 						smart_str_appendc(buf, '"');
336 						smart_str_append_long(buf, (long) index);
337 						smart_str_appendc(buf, '"');
338 						smart_str_appendc(buf, ':');
339 
340 						json_pretty_print_char(buf, options, ' ' TSRMLS_CC);
341 
342 						php_json_encode(buf, *data, options TSRMLS_CC);
343 					}
344 				}
345 
346 				if (tmp_ht) {
347 					tmp_ht->nApplyCount--;
348 				}
349 			}
350 		}
351 	}
352 
353 	if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) {
354 		JSON_G(error_code) = PHP_JSON_ERROR_DEPTH;
355 	}
356 	--JSON_G(encoder_depth);
357 
358 	/* Only keep closing bracket on same line for empty arrays/objects */
359 	if (need_comma) {
360 		json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
361 		json_pretty_print_indent(buf, options TSRMLS_CC);
362 	}
363 
364 	if (r == PHP_JSON_OUTPUT_ARRAY) {
365 		smart_str_appendc(buf, ']');
366 	} else {
367 		smart_str_appendc(buf, '}');
368 	}
369 }
370 /* }}} */
371 
json_utf8_to_utf16(unsigned short * utf16,char utf8[],int len)372 static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{{ */
373 {
374 	size_t pos = 0, us;
375 	int j, status;
376 
377 	if (utf16) {
378 		/* really convert the utf8 string */
379 		for (j=0 ; pos < len ; j++) {
380 			us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status);
381 			if (status != SUCCESS) {
382 				return -1;
383 			}
384 			/* From http://en.wikipedia.org/wiki/UTF16 */
385 			if (us >= 0x10000) {
386 				us -= 0x10000;
387 				utf16[j++] = (unsigned short)((us >> 10) | 0xd800);
388 				utf16[j] = (unsigned short)((us & 0x3ff) | 0xdc00);
389 			} else {
390 				utf16[j] = (unsigned short)us;
391 			}
392 		}
393 	} else {
394 		/* Only check if utf8 string is valid, and compute utf16 length */
395 		for (j=0 ; pos < len ; j++) {
396 			us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status);
397 			if (status != SUCCESS) {
398 				return -1;
399 			}
400 			if (us >= 0x10000) {
401 				j++;
402 			}
403 		}
404 	}
405 	return j;
406 }
407 /* }}} */
408 
409 
json_escape_string(smart_str * buf,char * s,int len,int options TSRMLS_DC)410 static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */
411 {
412 	int pos = 0, ulen = 0;
413 	unsigned short us;
414 	unsigned short *utf16;
415 	size_t newlen;
416 
417 	if (len == 0) {
418 		smart_str_appendl(buf, "\"\"", 2);
419 		return;
420 	}
421 
422 	if (options & PHP_JSON_NUMERIC_CHECK) {
423 		double d;
424 		int type;
425 		long p;
426 
427 		if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
428 			if (type == IS_LONG) {
429 				smart_str_append_long(buf, p);
430 				return;
431 			} else if (type == IS_DOUBLE && !zend_isinf(d) && !zend_isnan(d)) {
432 				char num[NUM_BUF_SIZE];
433 				int l;
434 
435 				php_gcvt(d, EG(precision), '.', 'e', (char *)num);
436 				l = strlen(num);
437 				if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && l < NUM_BUF_SIZE - 2) {
438 					num[l++] = '.';
439 					num[l++] = '0';
440 					num[l] = '\0';
441 				}
442 				smart_str_appendl(buf, num, l);
443 				return;
444 			}
445 		}
446 
447 	}
448 
449 	utf16 = (options & PHP_JSON_UNESCAPED_UNICODE) ? NULL : (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
450 	ulen = json_utf8_to_utf16(utf16, s, len);
451 	if (ulen <= 0) {
452 		if (utf16) {
453 			efree(utf16);
454 		}
455 		if (ulen < 0) {
456 			JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
457 			smart_str_appendl(buf, "null", 4);
458 		} else {
459 			smart_str_appendl(buf, "\"\"", 2);
460 		}
461 		return;
462 	}
463 	if (!(options & PHP_JSON_UNESCAPED_UNICODE)) {
464 		len = ulen;
465 	}
466 
467 	/* pre-allocate for string length plus 2 quotes */
468 	smart_str_alloc(buf, len+2, 0);
469 	smart_str_appendc(buf, '"');
470 
471 	while (pos < len)
472 	{
473 		us = (options & PHP_JSON_UNESCAPED_UNICODE) ? s[pos++] : utf16[pos++];
474 
475 		switch (us)
476 		{
477 			case '"':
478 				if (options & PHP_JSON_HEX_QUOT) {
479 					smart_str_appendl(buf, "\\u0022", 6);
480 				} else {
481 					smart_str_appendl(buf, "\\\"", 2);
482 				}
483 				break;
484 
485 			case '\\':
486 				smart_str_appendl(buf, "\\\\", 2);
487 				break;
488 
489 			case '/':
490 				if (options & PHP_JSON_UNESCAPED_SLASHES) {
491 					smart_str_appendc(buf, '/');
492 				} else {
493 					smart_str_appendl(buf, "\\/", 2);
494 				}
495 				break;
496 
497 			case '\b':
498 				smart_str_appendl(buf, "\\b", 2);
499 				break;
500 
501 			case '\f':
502 				smart_str_appendl(buf, "\\f", 2);
503 				break;
504 
505 			case '\n':
506 				smart_str_appendl(buf, "\\n", 2);
507 				break;
508 
509 			case '\r':
510 				smart_str_appendl(buf, "\\r", 2);
511 				break;
512 
513 			case '\t':
514 				smart_str_appendl(buf, "\\t", 2);
515 				break;
516 
517 			case '<':
518 				if (options & PHP_JSON_HEX_TAG) {
519 					smart_str_appendl(buf, "\\u003C", 6);
520 				} else {
521 					smart_str_appendc(buf, '<');
522 				}
523 				break;
524 
525 			case '>':
526 				if (options & PHP_JSON_HEX_TAG) {
527 					smart_str_appendl(buf, "\\u003E", 6);
528 				} else {
529 					smart_str_appendc(buf, '>');
530 				}
531 				break;
532 
533 			case '&':
534 				if (options & PHP_JSON_HEX_AMP) {
535 					smart_str_appendl(buf, "\\u0026", 6);
536 				} else {
537 					smart_str_appendc(buf, '&');
538 				}
539 				break;
540 
541 			case '\'':
542 				if (options & PHP_JSON_HEX_APOS) {
543 					smart_str_appendl(buf, "\\u0027", 6);
544 				} else {
545 					smart_str_appendc(buf, '\'');
546 				}
547 				break;
548 
549 			default:
550 				if (us >= ' ' && ((options & PHP_JSON_UNESCAPED_UNICODE) || (us & 127) == us)) {
551 					smart_str_appendc(buf, (unsigned char) us);
552 				} else {
553 					smart_str_appendl(buf, "\\u", 2);
554 					smart_str_appendc(buf, digits[(us & 0xf000) >> 12]);
555 					smart_str_appendc(buf, digits[(us & 0xf00)  >> 8]);
556 					smart_str_appendc(buf, digits[(us & 0xf0)   >> 4]);
557 					smart_str_appendc(buf, digits[(us & 0xf)]);
558 				}
559 				break;
560 		}
561 	}
562 
563 	smart_str_appendc(buf, '"');
564 	if (utf16) {
565 		efree(utf16);
566 	}
567 }
568 /* }}} */
569 
570 
json_encode_serializable_object(smart_str * buf,zval * val,int options TSRMLS_DC)571 static void json_encode_serializable_object(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
572 {
573 	zend_class_entry *ce = Z_OBJCE_P(val);
574 	zval *retval = NULL, fname;
575 	HashTable* myht;
576 
577 	if (Z_TYPE_P(val) == IS_ARRAY) {
578 		myht = HASH_OF(val);
579 	} else {
580 		myht = Z_OBJPROP_P(val);
581 	}
582 
583 	if (myht && myht->nApplyCount > 1) {
584 		JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
585 		smart_str_appendl(buf, "null", 4);
586 		return;
587 	}
588 
589 	ZVAL_STRING(&fname, "jsonSerialize", 0);
590 
591 	if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) {
592 		if (!EG(exception)) {
593 			zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name);
594 		}
595 		smart_str_appendl(buf, "null", sizeof("null") - 1);
596 		return;
597     }
598 
599 	if (EG(exception)) {
600 		/* Error already raised */
601 		zval_ptr_dtor(&retval);
602 		smart_str_appendl(buf, "null", sizeof("null") - 1);
603 		return;
604 	}
605 
606 	if ((Z_TYPE_P(retval) == IS_OBJECT) &&
607 		(Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) {
608 		/* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
609 		json_encode_array(buf, &retval, options TSRMLS_CC);
610 	} else {
611 		/* All other types, encode as normal */
612 		php_json_encode(buf, retval, options TSRMLS_CC);
613 	}
614 
615 	zval_ptr_dtor(&retval);
616 }
617 /* }}} */
618 
php_json_encode(smart_str * buf,zval * val,int options TSRMLS_DC)619 PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
620 {
621 	switch (Z_TYPE_P(val))
622 	{
623 		case IS_NULL:
624 			smart_str_appendl(buf, "null", 4);
625 			break;
626 
627 		case IS_BOOL:
628 			if (Z_BVAL_P(val)) {
629 				smart_str_appendl(buf, "true", 4);
630 			} else {
631 				smart_str_appendl(buf, "false", 5);
632 			}
633 			break;
634 
635 		case IS_LONG:
636 			smart_str_append_long(buf, Z_LVAL_P(val));
637 			break;
638 
639 		case IS_DOUBLE:
640 			{
641 				char num[NUM_BUF_SIZE];
642 				int len;
643 				double dbl = Z_DVAL_P(val);
644 
645 				if (!zend_isinf(dbl) && !zend_isnan(dbl)) {
646 					php_gcvt(dbl, EG(precision), '.', 'e', (char *)num);
647 					len = strlen(num);
648 					if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < NUM_BUF_SIZE - 2) {
649 						num[len++] = '.';
650 						num[len++] = '0';
651 						num[len] = '\0';
652 					}
653 					smart_str_appendl(buf, num, len);
654 				} else {
655 					JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
656 					smart_str_appendc(buf, '0');
657 				}
658 			}
659 			break;
660 
661 		case IS_STRING:
662 			json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC);
663 			break;
664 
665 		case IS_OBJECT:
666 			if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce TSRMLS_CC)) {
667 				json_encode_serializable_object(buf, val, options TSRMLS_CC);
668 				break;
669 			}
670 			/* fallthrough -- Non-serializable object */
671 		case IS_ARRAY:
672 			json_encode_array(buf, &val, options TSRMLS_CC);
673 			break;
674 
675 		default:
676 			JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE;
677 			smart_str_appendl(buf, "null", 4);
678 			break;
679 	}
680 
681 	return;
682 }
683 /* }}} */
684 
php_json_decode_ex(zval * return_value,char * str,int str_len,int options,long depth TSRMLS_DC)685 PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */
686 {
687 	int utf16_len;
688 	zval *z;
689 	unsigned short *utf16;
690 	JSON_parser jp;
691 
692 	utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 1);
693 
694 	utf16_len = json_utf8_to_utf16(utf16, str, str_len);
695 	if (utf16_len <= 0) {
696 		if (utf16) {
697 			efree(utf16);
698 		}
699 		JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
700 		RETURN_NULL();
701 	}
702 
703 	if (depth <= 0) {
704 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be greater than zero");
705 		efree(utf16);
706 		RETURN_NULL();
707 	}
708 
709 	if (depth > INT_MAX) {
710 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be lower than %d", INT_MAX);
711 		efree(utf16);
712 		RETURN_NULL();
713 	}
714 
715 	ALLOC_INIT_ZVAL(z);
716 	jp = new_JSON_parser(depth);
717 	if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {
718 		*return_value = *z;
719 	}
720 	else
721 	{
722 		double d;
723 		int type, overflow_info;
724 		long p;
725 		char *trim = str;
726 		int trim_len = str_len;
727 
728 		/* Increment trimmed string pointer to strip leading whitespace */
729 		/* JSON RFC says to consider as whitespace: space, tab, LF or CR */
730 		while (trim_len && (*trim == ' ' || *trim == '\t' || *trim == '\n' || *trim == '\r')) {
731 			trim++;
732 			trim_len--;
733 		}
734 
735 		/* Decrement trimmed string length to strip trailing whitespace */
736 		while (trim_len && (trim[trim_len - 1] == ' ' || trim[trim_len - 1] == '\t' || trim[trim_len - 1] == '\n' || trim[trim_len - 1] == '\r')) {
737 			trim_len--;
738 		}
739 
740 		RETVAL_NULL();
741 		if (trim_len == 4) {
742 			if (!strncmp(trim, "null", trim_len)) {
743 				/* We need to explicitly clear the error because its an actual NULL and not an error */
744 				jp->error_code = PHP_JSON_ERROR_NONE;
745 				RETVAL_NULL();
746 			} else if (!strncmp(trim, "true", trim_len)) {
747 				RETVAL_BOOL(1);
748 			}
749 		} else if (trim_len == 5 && !strncmp(trim, "false", trim_len)) {
750 			RETVAL_BOOL(0);
751 		}
752 
753 		if ((type = is_numeric_string_ex(trim, trim_len, &p, &d, 0, &overflow_info)) != 0) {
754 			if (type == IS_LONG) {
755 				RETVAL_LONG(p);
756 			} else if (type == IS_DOUBLE) {
757 				if (options & PHP_JSON_BIGINT_AS_STRING && overflow_info) {
758 					/* Within an object or array, a numeric literal is assumed
759 					 * to be an integer if and only if it's entirely made up of
760 					 * digits (exponent notation will result in the number
761 					 * being treated as a double). We'll match that behaviour
762 					 * here. */
763 					int i;
764 					zend_bool is_float = 0;
765 
766 					for (i = (trim[0] == '-' ? 1 : 0); i < trim_len; i++) {
767 						/* Not using isdigit() because it's locale specific,
768 						 * but we expect JSON input to always be UTF-8. */
769 						if (trim[i] < '0' || trim[i] > '9') {
770 							is_float = 1;
771 							break;
772 						}
773 					}
774 
775 					if (is_float) {
776 						RETVAL_DOUBLE(d);
777 					} else {
778 						RETVAL_STRINGL(trim, trim_len, 1);
779 					}
780 				} else {
781 					RETVAL_DOUBLE(d);
782 				}
783 			}
784 		}
785 
786 		if (Z_TYPE_P(return_value) != IS_NULL) {
787 			jp->error_code = PHP_JSON_ERROR_NONE;
788 		}
789 
790 		zval_dtor(z);
791 	}
792 	FREE_ZVAL(z);
793 	efree(utf16);
794 	JSON_G(error_code) = jp->error_code;
795 	free_JSON_parser(jp);
796 }
797 /* }}} */
798 
799 
800 /* {{{ proto string json_encode(mixed data [, int options[, int depth]])
801    Returns the JSON representation of a value */
PHP_FUNCTION(json_encode)802 static PHP_FUNCTION(json_encode)
803 {
804 	zval *parameter;
805 	smart_str buf = {0};
806 	long options = 0;
807     long depth = JSON_PARSER_DEFAULT_DEPTH;
808 
809 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &parameter, &options, &depth) == FAILURE) {
810 		return;
811 	}
812 
813 	JSON_G(error_code) = PHP_JSON_ERROR_NONE;
814 
815 	JSON_G(encode_max_depth) = depth;
816 
817 	php_json_encode(&buf, parameter, options TSRMLS_CC);
818 
819 	if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
820 		ZVAL_FALSE(return_value);
821 	} else {
822 		ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
823 	}
824 
825 	smart_str_free(&buf);
826 }
827 /* }}} */
828 
829 /* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]])
830    Decodes the JSON representation into a PHP value */
PHP_FUNCTION(json_decode)831 static PHP_FUNCTION(json_decode)
832 {
833 	char *str;
834 	int str_len;
835 	zend_bool assoc = 0; /* return JS objects as PHP objects by default */
836 	long depth = JSON_PARSER_DEFAULT_DEPTH;
837 	long options = 0;
838 
839 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
840 		return;
841 	}
842 
843 	JSON_G(error_code) = 0;
844 
845 	if (!str_len) {
846 		RETURN_NULL();
847 	}
848 
849 	/* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
850 	if (assoc) {
851 		options |=  PHP_JSON_OBJECT_AS_ARRAY;
852 	} else {
853 		options &= ~PHP_JSON_OBJECT_AS_ARRAY;
854 	}
855 
856 	php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC);
857 }
858 /* }}} */
859 
860 /* {{{ proto int json_last_error()
861    Returns the error code of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error)862 static PHP_FUNCTION(json_last_error)
863 {
864 	if (zend_parse_parameters_none() == FAILURE) {
865 		return;
866 	}
867 
868 	RETURN_LONG(JSON_G(error_code));
869 }
870 /* }}} */
871 
872 /* {{{ proto string json_last_error_msg()
873    Returns the error string of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error_msg)874 static PHP_FUNCTION(json_last_error_msg)
875 {
876 	if (zend_parse_parameters_none() == FAILURE) {
877 		return;
878 	}
879 
880 	switch(JSON_G(error_code)) {
881 		case PHP_JSON_ERROR_NONE:
882 			RETURN_STRING("No error", 1);
883 		case PHP_JSON_ERROR_DEPTH:
884 			RETURN_STRING("Maximum stack depth exceeded", 1);
885 		case PHP_JSON_ERROR_STATE_MISMATCH:
886 			RETURN_STRING("State mismatch (invalid or malformed JSON)", 1);
887 		case PHP_JSON_ERROR_CTRL_CHAR:
888 			RETURN_STRING("Control character error, possibly incorrectly encoded", 1);
889 		case PHP_JSON_ERROR_SYNTAX:
890 			RETURN_STRING("Syntax error", 1);
891 		case PHP_JSON_ERROR_UTF8:
892 			RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded", 1);
893 		case PHP_JSON_ERROR_RECURSION:
894 			RETURN_STRING("Recursion detected", 1);
895 		case PHP_JSON_ERROR_INF_OR_NAN:
896 			RETURN_STRING("Inf and NaN cannot be JSON encoded", 1);
897 		case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
898 			RETURN_STRING("Type is not supported", 1);
899 		default:
900 			RETURN_STRING("Unknown error", 1);
901 	}
902 
903 }
904 /* }}} */
905 
906 /*
907  * Local variables:
908  * tab-width: 4
909  * c-basic-offset: 4
910  * End:
911  * vim600: noet sw=4 ts=4 fdm=marker
912  * vim<600: noet sw=4 ts=4
913  */
914