1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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 34static PHP_MINFO_FUNCTION(json); 35static PHP_FUNCTION(json_encode); 36static PHP_FUNCTION(json_decode); 37static PHP_FUNCTION(json_last_error); 38static PHP_FUNCTION(json_last_error_msg); 39 40static const char digits[] = "0123456789abcdef"; 41 42zend_class_entry *php_json_serializable_ce; 43 44ZEND_DECLARE_MODULE_GLOBALS(json) 45 46/* {{{ arginfo */ 47ZEND_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) 51ZEND_END_ARG_INFO() 52 53ZEND_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) 58ZEND_END_ARG_INFO() 59 60ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0) 61ZEND_END_ARG_INFO() 62 63ZEND_BEGIN_ARG_INFO(arginfo_json_last_error_msg, 0) 64ZEND_END_ARG_INFO() 65/* }}} */ 66 67/* {{{ json_functions[] */ 68static 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 */ 78ZEND_BEGIN_ARG_INFO(json_serialize_arginfo, 0) 79 /* No arguments */ 80ZEND_END_ARG_INFO(); 81 82static 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 */ 89static 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*/ 126static 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 */ 137zend_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 156ZEND_GET_MODULE(json) 157#endif 158 159/* {{{ PHP_MINFO_FUNCTION 160 */ 161static 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 170static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC); 171 172static 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_EXISTANT) { 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 209static 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 217static 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 231static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */ 232{ 233 int i, r; 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_pretty_print_char(buf, options, '\n' TSRMLS_CC); 257 ++JSON_G(encoder_depth); 258 259 i = myht ? zend_hash_num_elements(myht) : 0; 260 261 if (i > 0) 262 { 263 char *key; 264 zval **data; 265 ulong index; 266 uint key_len; 267 HashPosition pos; 268 HashTable *tmp_ht; 269 int need_comma = 0; 270 271 zend_hash_internal_pointer_reset_ex(myht, &pos); 272 for (;; zend_hash_move_forward_ex(myht, &pos)) { 273 i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); 274 if (i == HASH_KEY_NON_EXISTANT) 275 break; 276 277 if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) { 278 tmp_ht = HASH_OF(*data); 279 if (tmp_ht) { 280 tmp_ht->nApplyCount++; 281 } 282 283 if (r == PHP_JSON_OUTPUT_ARRAY) { 284 if (need_comma) { 285 smart_str_appendc(buf, ','); 286 json_pretty_print_char(buf, options, '\n' TSRMLS_CC); 287 } else { 288 need_comma = 1; 289 } 290 291 json_pretty_print_indent(buf, options TSRMLS_CC); 292 php_json_encode(buf, *data, options TSRMLS_CC); 293 } else if (r == PHP_JSON_OUTPUT_OBJECT) { 294 if (i == HASH_KEY_IS_STRING) { 295 if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) { 296 /* Skip protected and private members. */ 297 if (tmp_ht) { 298 tmp_ht->nApplyCount--; 299 } 300 continue; 301 } 302 303 if (need_comma) { 304 smart_str_appendc(buf, ','); 305 json_pretty_print_char(buf, options, '\n' TSRMLS_CC); 306 } else { 307 need_comma = 1; 308 } 309 310 json_pretty_print_indent(buf, options TSRMLS_CC); 311 312 json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC); 313 smart_str_appendc(buf, ':'); 314 315 json_pretty_print_char(buf, options, ' ' TSRMLS_CC); 316 317 php_json_encode(buf, *data, options TSRMLS_CC); 318 } else { 319 if (need_comma) { 320 smart_str_appendc(buf, ','); 321 json_pretty_print_char(buf, options, '\n' TSRMLS_CC); 322 } else { 323 need_comma = 1; 324 } 325 326 json_pretty_print_indent(buf, options TSRMLS_CC); 327 328 smart_str_appendc(buf, '"'); 329 smart_str_append_long(buf, (long) index); 330 smart_str_appendc(buf, '"'); 331 smart_str_appendc(buf, ':'); 332 333 json_pretty_print_char(buf, options, ' ' TSRMLS_CC); 334 335 php_json_encode(buf, *data, options TSRMLS_CC); 336 } 337 } 338 339 if (tmp_ht) { 340 tmp_ht->nApplyCount--; 341 } 342 } 343 } 344 } 345 346 if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) { 347 JSON_G(error_code) = PHP_JSON_ERROR_DEPTH; 348 } 349 --JSON_G(encoder_depth); 350 json_pretty_print_char(buf, options, '\n' TSRMLS_CC); 351 json_pretty_print_indent(buf, options TSRMLS_CC); 352 353 if (r == PHP_JSON_OUTPUT_ARRAY) { 354 smart_str_appendc(buf, ']'); 355 } else { 356 smart_str_appendc(buf, '}'); 357 } 358} 359/* }}} */ 360 361static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{{ */ 362{ 363 size_t pos = 0, us; 364 int j, status; 365 366 if (utf16) { 367 /* really convert the utf8 string */ 368 for (j=0 ; pos < len ; j++) { 369 us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status); 370 if (status != SUCCESS) { 371 return -1; 372 } 373 /* From http://en.wikipedia.org/wiki/UTF16 */ 374 if (us >= 0x10000) { 375 us -= 0x10000; 376 utf16[j++] = (unsigned short)((us >> 10) | 0xd800); 377 utf16[j] = (unsigned short)((us & 0x3ff) | 0xdc00); 378 } else { 379 utf16[j] = (unsigned short)us; 380 } 381 } 382 } else { 383 /* Only check if utf8 string is valid, and compute utf16 lenght */ 384 for (j=0 ; pos < len ; j++) { 385 us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status); 386 if (status != SUCCESS) { 387 return -1; 388 } 389 if (us >= 0x10000) { 390 j++; 391 } 392 } 393 } 394 return j; 395} 396/* }}} */ 397 398 399static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */ 400{ 401 int pos = 0, ulen = 0; 402 unsigned short us; 403 unsigned short *utf16; 404 size_t newlen; 405 406 if (len == 0) { 407 smart_str_appendl(buf, "\"\"", 2); 408 return; 409 } 410 411 if (options & PHP_JSON_NUMERIC_CHECK) { 412 double d; 413 int type; 414 long p; 415 416 if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { 417 if (type == IS_LONG) { 418 smart_str_append_long(buf, p); 419 } else if (type == IS_DOUBLE) { 420 if (!zend_isinf(d) && !zend_isnan(d)) { 421 char *tmp; 422 int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d); 423 smart_str_appendl(buf, tmp, l); 424 efree(tmp); 425 } else { 426 JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; 427 smart_str_appendc(buf, '0'); 428 } 429 } 430 return; 431 } 432 433 } 434 435 utf16 = (options & PHP_JSON_UNESCAPED_UNICODE) ? NULL : (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0); 436 ulen = json_utf8_to_utf16(utf16, s, len); 437 if (ulen <= 0) { 438 if (utf16) { 439 efree(utf16); 440 } 441 if (ulen < 0) { 442 JSON_G(error_code) = PHP_JSON_ERROR_UTF8; 443 smart_str_appendl(buf, "null", 4); 444 } else { 445 smart_str_appendl(buf, "\"\"", 2); 446 } 447 return; 448 } 449 if (!(options & PHP_JSON_UNESCAPED_UNICODE)) { 450 len = ulen; 451 } 452 453 /* pre-allocate for string length plus 2 quotes */ 454 smart_str_alloc(buf, len+2, 0); 455 smart_str_appendc(buf, '"'); 456 457 while (pos < len) 458 { 459 us = (options & PHP_JSON_UNESCAPED_UNICODE) ? s[pos++] : utf16[pos++]; 460 461 switch (us) 462 { 463 case '"': 464 if (options & PHP_JSON_HEX_QUOT) { 465 smart_str_appendl(buf, "\\u0022", 6); 466 } else { 467 smart_str_appendl(buf, "\\\"", 2); 468 } 469 break; 470 471 case '\\': 472 smart_str_appendl(buf, "\\\\", 2); 473 break; 474 475 case '/': 476 if (options & PHP_JSON_UNESCAPED_SLASHES) { 477 smart_str_appendc(buf, '/'); 478 } else { 479 smart_str_appendl(buf, "\\/", 2); 480 } 481 break; 482 483 case '\b': 484 smart_str_appendl(buf, "\\b", 2); 485 break; 486 487 case '\f': 488 smart_str_appendl(buf, "\\f", 2); 489 break; 490 491 case '\n': 492 smart_str_appendl(buf, "\\n", 2); 493 break; 494 495 case '\r': 496 smart_str_appendl(buf, "\\r", 2); 497 break; 498 499 case '\t': 500 smart_str_appendl(buf, "\\t", 2); 501 break; 502 503 case '<': 504 if (options & PHP_JSON_HEX_TAG) { 505 smart_str_appendl(buf, "\\u003C", 6); 506 } else { 507 smart_str_appendc(buf, '<'); 508 } 509 break; 510 511 case '>': 512 if (options & PHP_JSON_HEX_TAG) { 513 smart_str_appendl(buf, "\\u003E", 6); 514 } else { 515 smart_str_appendc(buf, '>'); 516 } 517 break; 518 519 case '&': 520 if (options & PHP_JSON_HEX_AMP) { 521 smart_str_appendl(buf, "\\u0026", 6); 522 } else { 523 smart_str_appendc(buf, '&'); 524 } 525 break; 526 527 case '\'': 528 if (options & PHP_JSON_HEX_APOS) { 529 smart_str_appendl(buf, "\\u0027", 6); 530 } else { 531 smart_str_appendc(buf, '\''); 532 } 533 break; 534 535 default: 536 if (us >= ' ' && ((options & PHP_JSON_UNESCAPED_UNICODE) || (us & 127) == us)) { 537 smart_str_appendc(buf, (unsigned char) us); 538 } else { 539 smart_str_appendl(buf, "\\u", 2); 540 smart_str_appendc(buf, digits[(us & 0xf000) >> 12]); 541 smart_str_appendc(buf, digits[(us & 0xf00) >> 8]); 542 smart_str_appendc(buf, digits[(us & 0xf0) >> 4]); 543 smart_str_appendc(buf, digits[(us & 0xf)]); 544 } 545 break; 546 } 547 } 548 549 smart_str_appendc(buf, '"'); 550 if (utf16) { 551 efree(utf16); 552 } 553} 554/* }}} */ 555 556 557static void json_encode_serializable_object(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ 558{ 559 zend_class_entry *ce = Z_OBJCE_P(val); 560 zval *retval = NULL, fname; 561 HashTable* myht; 562 563 if (Z_TYPE_P(val) == IS_ARRAY) { 564 myht = HASH_OF(val); 565 } else { 566 myht = Z_OBJPROP_P(val); 567 } 568 569 if (myht && myht->nApplyCount > 1) { 570 JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; 571 smart_str_appendl(buf, "null", 4); 572 return; 573 } 574 575 ZVAL_STRING(&fname, "jsonSerialize", 0); 576 577 if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) { 578 zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name); 579 smart_str_appendl(buf, "null", sizeof("null") - 1); 580 return; 581 } 582 583 if (EG(exception)) { 584 /* Error already raised */ 585 zval_ptr_dtor(&retval); 586 smart_str_appendl(buf, "null", sizeof("null") - 1); 587 return; 588 } 589 590 if ((Z_TYPE_P(retval) == IS_OBJECT) && 591 (Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) { 592 /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */ 593 json_encode_array(buf, &retval, options TSRMLS_CC); 594 } else { 595 /* All other types, encode as normal */ 596 php_json_encode(buf, retval, options TSRMLS_CC); 597 } 598 599 zval_ptr_dtor(&retval); 600} 601/* }}} */ 602 603PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ 604{ 605 switch (Z_TYPE_P(val)) 606 { 607 case IS_NULL: 608 smart_str_appendl(buf, "null", 4); 609 break; 610 611 case IS_BOOL: 612 if (Z_BVAL_P(val)) { 613 smart_str_appendl(buf, "true", 4); 614 } else { 615 smart_str_appendl(buf, "false", 5); 616 } 617 break; 618 619 case IS_LONG: 620 smart_str_append_long(buf, Z_LVAL_P(val)); 621 break; 622 623 case IS_DOUBLE: 624 { 625 char *d = NULL; 626 int len; 627 double dbl = Z_DVAL_P(val); 628 629 if (!zend_isinf(dbl) && !zend_isnan(dbl)) { 630 len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl); 631 smart_str_appendl(buf, d, len); 632 efree(d); 633 } else { 634 JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; 635 smart_str_appendc(buf, '0'); 636 } 637 } 638 break; 639 640 case IS_STRING: 641 json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC); 642 break; 643 644 case IS_OBJECT: 645 if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce TSRMLS_CC)) { 646 json_encode_serializable_object(buf, val, options TSRMLS_CC); 647 break; 648 } 649 /* fallthrough -- Non-serializable object */ 650 case IS_ARRAY: 651 json_encode_array(buf, &val, options TSRMLS_CC); 652 break; 653 654 default: 655 JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE; 656 smart_str_appendl(buf, "null", 4); 657 break; 658 } 659 660 return; 661} 662/* }}} */ 663 664PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */ 665{ 666 int utf16_len; 667 zval *z; 668 unsigned short *utf16; 669 JSON_parser jp; 670 671 utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 1); 672 673 utf16_len = json_utf8_to_utf16(utf16, str, str_len); 674 if (utf16_len <= 0) { 675 if (utf16) { 676 efree(utf16); 677 } 678 JSON_G(error_code) = PHP_JSON_ERROR_UTF8; 679 RETURN_NULL(); 680 } 681 682 if (depth <= 0) { 683 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be greater than zero"); 684 efree(utf16); 685 RETURN_NULL(); 686 } 687 688 ALLOC_INIT_ZVAL(z); 689 jp = new_JSON_parser(depth); 690 if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) { 691 *return_value = *z; 692 } 693 else 694 { 695 double d; 696 int type, overflow_info; 697 long p; 698 699 RETVAL_NULL(); 700 if (str_len == 4) { 701 if (!strcasecmp(str, "null")) { 702 /* We need to explicitly clear the error because its an actual NULL and not an error */ 703 jp->error_code = PHP_JSON_ERROR_NONE; 704 RETVAL_NULL(); 705 } else if (!strcasecmp(str, "true")) { 706 RETVAL_BOOL(1); 707 } 708 } else if (str_len == 5 && !strcasecmp(str, "false")) { 709 RETVAL_BOOL(0); 710 } 711 712 if ((type = is_numeric_string_ex(str, str_len, &p, &d, 0, &overflow_info)) != 0) { 713 if (type == IS_LONG) { 714 RETVAL_LONG(p); 715 } else if (type == IS_DOUBLE) { 716 if (options & PHP_JSON_BIGINT_AS_STRING && overflow_info) { 717 /* Within an object or array, a numeric literal is assumed 718 * to be an integer if and only if it's entirely made up of 719 * digits (exponent notation will result in the number 720 * being treated as a double). We'll match that behaviour 721 * here. */ 722 int i; 723 zend_bool is_float = 0; 724 725 for (i = (str[0] == '-' ? 1 : 0); i < str_len; i++) { 726 /* Not using isdigit() because it's locale specific, 727 * but we expect JSON input to always be UTF-8. */ 728 if (str[i] < '0' || str[i] > '9') { 729 is_float = 1; 730 break; 731 } 732 } 733 734 if (is_float) { 735 RETVAL_DOUBLE(d); 736 } else { 737 RETVAL_STRINGL(str, str_len, 1); 738 } 739 } else { 740 RETVAL_DOUBLE(d); 741 } 742 } 743 } 744 745 if (Z_TYPE_P(return_value) != IS_NULL) { 746 jp->error_code = PHP_JSON_ERROR_NONE; 747 } 748 749 zval_dtor(z); 750 } 751 FREE_ZVAL(z); 752 efree(utf16); 753 JSON_G(error_code) = jp->error_code; 754 free_JSON_parser(jp); 755} 756/* }}} */ 757 758 759/* {{{ proto string json_encode(mixed data [, int options[, int depth]]) 760 Returns the JSON representation of a value */ 761static PHP_FUNCTION(json_encode) 762{ 763 zval *parameter; 764 smart_str buf = {0}; 765 long options = 0; 766 long depth = JSON_PARSER_DEFAULT_DEPTH; 767 768 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", ¶meter, &options, &depth) == FAILURE) { 769 return; 770 } 771 772 JSON_G(error_code) = PHP_JSON_ERROR_NONE; 773 774 JSON_G(encode_max_depth) = depth; 775 776 php_json_encode(&buf, parameter, options TSRMLS_CC); 777 778 if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { 779 ZVAL_FALSE(return_value); 780 } else { 781 ZVAL_STRINGL(return_value, buf.c, buf.len, 1); 782 } 783 784 smart_str_free(&buf); 785} 786/* }}} */ 787 788/* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]]) 789 Decodes the JSON representation into a PHP value */ 790static PHP_FUNCTION(json_decode) 791{ 792 char *str; 793 int str_len; 794 zend_bool assoc = 0; /* return JS objects as PHP objects by default */ 795 long depth = JSON_PARSER_DEFAULT_DEPTH; 796 long options = 0; 797 798 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) { 799 return; 800 } 801 802 JSON_G(error_code) = 0; 803 804 if (!str_len) { 805 RETURN_NULL(); 806 } 807 808 /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */ 809 if (assoc) { 810 options |= PHP_JSON_OBJECT_AS_ARRAY; 811 } else { 812 options &= ~PHP_JSON_OBJECT_AS_ARRAY; 813 } 814 815 php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC); 816} 817/* }}} */ 818 819/* {{{ proto int json_last_error() 820 Returns the error code of the last json_encode() or json_decode() call. */ 821static PHP_FUNCTION(json_last_error) 822{ 823 if (zend_parse_parameters_none() == FAILURE) { 824 return; 825 } 826 827 RETURN_LONG(JSON_G(error_code)); 828} 829/* }}} */ 830 831/* {{{ proto string json_last_error_msg() 832 Returns the error string of the last json_encode() or json_decode() call. */ 833static PHP_FUNCTION(json_last_error_msg) 834{ 835 if (zend_parse_parameters_none() == FAILURE) { 836 return; 837 } 838 839 switch(JSON_G(error_code)) { 840 case PHP_JSON_ERROR_NONE: 841 RETURN_STRING("No error", 1); 842 case PHP_JSON_ERROR_DEPTH: 843 RETURN_STRING("Maximum stack depth exceeded", 1); 844 case PHP_JSON_ERROR_STATE_MISMATCH: 845 RETURN_STRING("State mismatch (invalid or malformed JSON)", 1); 846 case PHP_JSON_ERROR_CTRL_CHAR: 847 RETURN_STRING("Control character error, possibly incorrectly encoded", 1); 848 case PHP_JSON_ERROR_SYNTAX: 849 RETURN_STRING("Syntax error", 1); 850 case PHP_JSON_ERROR_UTF8: 851 RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded", 1); 852 case PHP_JSON_ERROR_RECURSION: 853 RETURN_STRING("Recursion detected", 1); 854 case PHP_JSON_ERROR_INF_OR_NAN: 855 RETURN_STRING("Inf and NaN cannot be JSON encoded", 1); 856 case PHP_JSON_ERROR_UNSUPPORTED_TYPE: 857 RETURN_STRING("Type is not supported", 1); 858 default: 859 RETURN_STRING("Unknown error", 1); 860 } 861 862} 863/* }}} */ 864 865/* 866 * Local variables: 867 * tab-width: 4 868 * c-basic-offset: 4 869 * End: 870 * vim600: noet sw=4 ts=4 fdm=marker 871 * vim<600: noet sw=4 ts=4 872 */ 873