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