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