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", ¶meter, &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