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