[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 _deprecated_file( basename( __FILE__ ), '5.3.0', '', 'The PHP native JSON extension is now a requirement.' ); 3 4 if ( ! class_exists( 'Services_JSON' ) ) : 5 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 6 /** 7 * Converts to and from JSON format. 8 * 9 * JSON (JavaScript Object Notation) is a lightweight data-interchange 10 * format. It is easy for humans to read and write. It is easy for machines 11 * to parse and generate. It is based on a subset of the JavaScript 12 * Programming Language, Standard ECMA-262 3rd Edition - December 1999. 13 * This feature can also be found in Python. JSON is a text format that is 14 * completely language independent but uses conventions that are familiar 15 * to programmers of the C-family of languages, including C, C++, C#, Java, 16 * JavaScript, Perl, TCL, and many others. These properties make JSON an 17 * ideal data-interchange language. 18 * 19 * This package provides a simple encoder and decoder for JSON notation. It 20 * is intended for use with client-side JavaScript applications that make 21 * use of HTTPRequest to perform server communication functions - data can 22 * be encoded into JSON notation for use in a client-side javaScript, or 23 * decoded from incoming JavaScript requests. JSON format is native to 24 * JavaScript, and can be directly eval()'ed with no further parsing 25 * overhead 26 * 27 * All strings should be in ASCII or UTF-8 format! 28 * 29 * LICENSE: Redistribution and use in source and binary forms, with or 30 * without modification, are permitted provided that the following 31 * conditions are met: Redistributions of source code must retain the 32 * above copyright notice, this list of conditions and the following 33 * disclaimer. Redistributions in binary form must reproduce the above 34 * copyright notice, this list of conditions and the following disclaimer 35 * in the documentation and/or other materials provided with the 36 * distribution. 37 * 38 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 39 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 41 * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 43 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 44 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 47 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 48 * DAMAGE. 49 * 50 * @category 51 * @package Services_JSON 52 * @author Michal Migurski <mike-json@teczno.com> 53 * @author Matt Knapp <mdknapp[at]gmail[dot]com> 54 * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com> 55 * @copyright 2005 Michal Migurski 56 * @version CVS: $Id: JSON.php 305040 2010-11-02 23:19:03Z alan_k $ 57 * @license https://www.opensource.org/licenses/bsd-license.php 58 * @link https://pear.php.net/pepr/pepr-proposal-show.php?id=198 59 */ 60 61 /** 62 * Marker constant for Services_JSON::decode(), used to flag stack state 63 */ 64 define('SERVICES_JSON_SLICE', 1); 65 66 /** 67 * Marker constant for Services_JSON::decode(), used to flag stack state 68 */ 69 define('SERVICES_JSON_IN_STR', 2); 70 71 /** 72 * Marker constant for Services_JSON::decode(), used to flag stack state 73 */ 74 define('SERVICES_JSON_IN_ARR', 3); 75 76 /** 77 * Marker constant for Services_JSON::decode(), used to flag stack state 78 */ 79 define('SERVICES_JSON_IN_OBJ', 4); 80 81 /** 82 * Marker constant for Services_JSON::decode(), used to flag stack state 83 */ 84 define('SERVICES_JSON_IN_CMT', 5); 85 86 /** 87 * Behavior switch for Services_JSON::decode() 88 */ 89 define('SERVICES_JSON_LOOSE_TYPE', 16); 90 91 /** 92 * Behavior switch for Services_JSON::decode() 93 */ 94 define('SERVICES_JSON_SUPPRESS_ERRORS', 32); 95 96 /** 97 * Behavior switch for Services_JSON::decode() 98 */ 99 define('SERVICES_JSON_USE_TO_JSON', 64); 100 101 /** 102 * Converts to and from JSON format. 103 * 104 * Brief example of use: 105 * 106 * <code> 107 * // create a new instance of Services_JSON 108 * $json = new Services_JSON(); 109 * 110 * // convert a complex value to JSON notation, and send it to the browser 111 * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); 112 * $output = $json->encode($value); 113 * 114 * print($output); 115 * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] 116 * 117 * // accept incoming POST data, assumed to be in JSON notation 118 * $input = file_get_contents('php://input', 1000000); 119 * $value = $json->decode($input); 120 * </code> 121 */ 122 class Services_JSON 123 { 124 /** 125 * Object behavior flags. 126 * 127 * @var int 128 */ 129 public $use; 130 131 // private - cache the mbstring lookup results.. 132 var $_mb_strlen = false; 133 var $_mb_substr = false; 134 var $_mb_convert_encoding = false; 135 136 /** 137 * constructs a new JSON instance 138 * 139 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 140 * 141 * @param int $use object behavior flags; combine with boolean-OR 142 * 143 * possible values: 144 * - SERVICES_JSON_LOOSE_TYPE: loose typing. 145 * "{...}" syntax creates associative arrays 146 * instead of objects in decode(). 147 * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. 148 * Values which can't be encoded (e.g. resources) 149 * appear as NULL instead of throwing errors. 150 * By default, a deeply-nested resource will 151 * bubble up with an error, so all return values 152 * from encode() should be checked with isError() 153 * - SERVICES_JSON_USE_TO_JSON: call toJSON when serializing objects 154 * It serializes the return value from the toJSON call rather 155 * than the object itself, toJSON can return associative arrays, 156 * strings or numbers, if you return an object, make sure it does 157 * not have a toJSON method, otherwise an error will occur. 158 */ 159 function __construct( $use = 0 ) 160 { 161 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 162 163 $this->use = $use; 164 $this->_mb_strlen = function_exists('mb_strlen'); 165 $this->_mb_convert_encoding = function_exists('mb_convert_encoding'); 166 $this->_mb_substr = function_exists('mb_substr'); 167 } 168 169 /** 170 * PHP4 constructor. 171 * 172 * @deprecated 5.3.0 Use __construct() instead. 173 * 174 * @see Services_JSON::__construct() 175 */ 176 public function Services_JSON( $use = 0 ) { 177 _deprecated_constructor( 'Services_JSON', '5.3.0', get_class( $this ) ); 178 self::__construct( $use ); 179 } 180 181 /** 182 * convert a string from one UTF-16 char to one UTF-8 char 183 * 184 * Normally should be handled by mb_convert_encoding, but 185 * provides a slower PHP-only method for installations 186 * that lack the multibye string extension. 187 * 188 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 189 * 190 * @param string $utf16 UTF-16 character 191 * @return string UTF-8 character 192 * @access private 193 */ 194 function utf162utf8($utf16) 195 { 196 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 197 198 // oh please oh please oh please oh please oh please 199 if($this->_mb_convert_encoding) { 200 return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); 201 } 202 203 $bytes = (ord($utf16[0]) << 8) | ord($utf16[1]); 204 205 switch(true) { 206 case ((0x7F & $bytes) == $bytes): 207 // this case should never be reached, because we are in ASCII range 208 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 209 return chr(0x7F & $bytes); 210 211 case (0x07FF & $bytes) == $bytes: 212 // return a 2-byte UTF-8 character 213 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 214 return chr(0xC0 | (($bytes >> 6) & 0x1F)) 215 . chr(0x80 | ($bytes & 0x3F)); 216 217 case (0xFFFF & $bytes) == $bytes: 218 // return a 3-byte UTF-8 character 219 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 220 return chr(0xE0 | (($bytes >> 12) & 0x0F)) 221 . chr(0x80 | (($bytes >> 6) & 0x3F)) 222 . chr(0x80 | ($bytes & 0x3F)); 223 } 224 225 // ignoring UTF-32 for now, sorry 226 return ''; 227 } 228 229 /** 230 * convert a string from one UTF-8 char to one UTF-16 char 231 * 232 * Normally should be handled by mb_convert_encoding, but 233 * provides a slower PHP-only method for installations 234 * that lack the multibyte string extension. 235 * 236 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 237 * 238 * @param string $utf8 UTF-8 character 239 * @return string UTF-16 character 240 * @access private 241 */ 242 function utf82utf16($utf8) 243 { 244 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 245 246 // oh please oh please oh please oh please oh please 247 if($this->_mb_convert_encoding) { 248 return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); 249 } 250 251 switch($this->strlen8($utf8)) { 252 case 1: 253 // this case should never be reached, because we are in ASCII range 254 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 255 return $utf8; 256 257 case 2: 258 // return a UTF-16 character from a 2-byte UTF-8 char 259 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 260 return chr(0x07 & (ord($utf8[0]) >> 2)) 261 . chr((0xC0 & (ord($utf8[0]) << 6)) 262 | (0x3F & ord($utf8[1]))); 263 264 case 3: 265 // return a UTF-16 character from a 3-byte UTF-8 char 266 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 267 return chr((0xF0 & (ord($utf8[0]) << 4)) 268 | (0x0F & (ord($utf8[1]) >> 2))) 269 . chr((0xC0 & (ord($utf8[1]) << 6)) 270 | (0x7F & ord($utf8[2]))); 271 } 272 273 // ignoring UTF-32 for now, sorry 274 return ''; 275 } 276 277 /** 278 * encodes an arbitrary variable into JSON format (and sends JSON Header) 279 * 280 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 281 * 282 * @param mixed $var any number, boolean, string, array, or object to be encoded. 283 * see argument 1 to Services_JSON() above for array-parsing behavior. 284 * if var is a string, note that encode() always expects it 285 * to be in ASCII or UTF-8 format! 286 * 287 * @return mixed JSON string representation of input var or an error if a problem occurs 288 * @access public 289 */ 290 function encode($var) 291 { 292 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 293 294 header('Content-Type: application/json'); 295 return $this->encodeUnsafe($var); 296 } 297 /** 298 * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!) 299 * 300 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 301 * 302 * @param mixed $var any number, boolean, string, array, or object to be encoded. 303 * see argument 1 to Services_JSON() above for array-parsing behavior. 304 * if var is a string, note that encode() always expects it 305 * to be in ASCII or UTF-8 format! 306 * 307 * @return mixed JSON string representation of input var or an error if a problem occurs 308 * @access public 309 */ 310 function encodeUnsafe($var) 311 { 312 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 313 314 // see bug #16908 - regarding numeric locale printing 315 $lc = setlocale(LC_NUMERIC, 0); 316 setlocale(LC_NUMERIC, 'C'); 317 $ret = $this->_encode($var); 318 setlocale(LC_NUMERIC, $lc); 319 return $ret; 320 321 } 322 /** 323 * PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format 324 * 325 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 326 * 327 * @param mixed $var any number, boolean, string, array, or object to be encoded. 328 * see argument 1 to Services_JSON() above for array-parsing behavior. 329 * if var is a string, note that encode() always expects it 330 * to be in ASCII or UTF-8 format! 331 * 332 * @return mixed JSON string representation of input var or an error if a problem occurs 333 * @access public 334 */ 335 function _encode($var) 336 { 337 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 338 339 switch (gettype($var)) { 340 case 'boolean': 341 return $var ? 'true' : 'false'; 342 343 case 'NULL': 344 return 'null'; 345 346 case 'integer': 347 return (int) $var; 348 349 case 'double': 350 case 'float': 351 return (float) $var; 352 353 case 'string': 354 // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT 355 $ascii = ''; 356 $strlen_var = $this->strlen8($var); 357 358 /* 359 * Iterate over every character in the string, 360 * escaping with a slash or encoding to UTF-8 where necessary 361 */ 362 for ($c = 0; $c < $strlen_var; ++$c) { 363 364 $ord_var_c = ord($var[$c]); 365 366 switch (true) { 367 case $ord_var_c == 0x08: 368 $ascii .= '\b'; 369 break; 370 case $ord_var_c == 0x09: 371 $ascii .= '\t'; 372 break; 373 case $ord_var_c == 0x0A: 374 $ascii .= '\n'; 375 break; 376 case $ord_var_c == 0x0C: 377 $ascii .= '\f'; 378 break; 379 case $ord_var_c == 0x0D: 380 $ascii .= '\r'; 381 break; 382 383 case $ord_var_c == 0x22: 384 case $ord_var_c == 0x2F: 385 case $ord_var_c == 0x5C: 386 // double quote, slash, slosh 387 $ascii .= '\\'.$var[$c]; 388 break; 389 390 case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): 391 // characters U-00000000 - U-0000007F (same as ASCII) 392 $ascii .= $var[$c]; 393 break; 394 395 case (($ord_var_c & 0xE0) == 0xC0): 396 // characters U-00000080 - U-000007FF, mask 110XXXXX 397 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 398 if ($c+1 >= $strlen_var) { 399 $c += 1; 400 $ascii .= '?'; 401 break; 402 } 403 404 $char = pack('C*', $ord_var_c, ord($var[$c + 1])); 405 $c += 1; 406 $utf16 = $this->utf82utf16($char); 407 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 408 break; 409 410 case (($ord_var_c & 0xF0) == 0xE0): 411 if ($c+2 >= $strlen_var) { 412 $c += 2; 413 $ascii .= '?'; 414 break; 415 } 416 // characters U-00000800 - U-0000FFFF, mask 1110XXXX 417 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 418 $char = pack('C*', $ord_var_c, 419 @ord($var[$c + 1]), 420 @ord($var[$c + 2])); 421 $c += 2; 422 $utf16 = $this->utf82utf16($char); 423 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 424 break; 425 426 case (($ord_var_c & 0xF8) == 0xF0): 427 if ($c+3 >= $strlen_var) { 428 $c += 3; 429 $ascii .= '?'; 430 break; 431 } 432 // characters U-00010000 - U-001FFFFF, mask 11110XXX 433 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 434 $char = pack('C*', $ord_var_c, 435 ord($var[$c + 1]), 436 ord($var[$c + 2]), 437 ord($var[$c + 3])); 438 $c += 3; 439 $utf16 = $this->utf82utf16($char); 440 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 441 break; 442 443 case (($ord_var_c & 0xFC) == 0xF8): 444 // characters U-00200000 - U-03FFFFFF, mask 111110XX 445 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 446 if ($c+4 >= $strlen_var) { 447 $c += 4; 448 $ascii .= '?'; 449 break; 450 } 451 $char = pack('C*', $ord_var_c, 452 ord($var[$c + 1]), 453 ord($var[$c + 2]), 454 ord($var[$c + 3]), 455 ord($var[$c + 4])); 456 $c += 4; 457 $utf16 = $this->utf82utf16($char); 458 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 459 break; 460 461 case (($ord_var_c & 0xFE) == 0xFC): 462 if ($c+5 >= $strlen_var) { 463 $c += 5; 464 $ascii .= '?'; 465 break; 466 } 467 // characters U-04000000 - U-7FFFFFFF, mask 1111110X 468 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 469 $char = pack('C*', $ord_var_c, 470 ord($var[$c + 1]), 471 ord($var[$c + 2]), 472 ord($var[$c + 3]), 473 ord($var[$c + 4]), 474 ord($var[$c + 5])); 475 $c += 5; 476 $utf16 = $this->utf82utf16($char); 477 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 478 break; 479 } 480 } 481 return '"'.$ascii.'"'; 482 483 case 'array': 484 /* 485 * As per JSON spec if any array key is not an integer 486 * we must treat the whole array as an object. We 487 * also try to catch a sparsely populated associative 488 * array with numeric keys here because some JS engines 489 * will create an array with empty indexes up to 490 * max_index which can cause memory issues and because 491 * the keys, which may be relevant, will be remapped 492 * otherwise. 493 * 494 * As per the ECMA and JSON specification an object may 495 * have any string as a property. Unfortunately due to 496 * a hole in the ECMA specification if the key is a 497 * ECMA reserved word or starts with a digit the 498 * parameter is only accessible using ECMAScript's 499 * bracket notation. 500 */ 501 502 // treat as a JSON object 503 if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { 504 $properties = array_map(array($this, 'name_value'), 505 array_keys($var), 506 array_values($var)); 507 508 foreach($properties as $property) { 509 if(Services_JSON::isError($property)) { 510 return $property; 511 } 512 } 513 514 return '{' . join(',', $properties) . '}'; 515 } 516 517 // treat it like a regular array 518 $elements = array_map(array($this, '_encode'), $var); 519 520 foreach($elements as $element) { 521 if(Services_JSON::isError($element)) { 522 return $element; 523 } 524 } 525 526 return '[' . join(',', $elements) . ']'; 527 528 case 'object': 529 530 // support toJSON methods. 531 if (($this->use & SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) { 532 // this may end up allowing unlimited recursion 533 // so we check the return value to make sure it's not got the same method. 534 $recode = $var->toJSON(); 535 536 if (method_exists($recode, 'toJSON')) { 537 538 return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) 539 ? 'null' 540 : new Services_JSON_Error(get_class($var). 541 " toJSON returned an object with a toJSON method."); 542 543 } 544 545 return $this->_encode( $recode ); 546 } 547 548 $vars = get_object_vars($var); 549 550 $properties = array_map(array($this, 'name_value'), 551 array_keys($vars), 552 array_values($vars)); 553 554 foreach($properties as $property) { 555 if(Services_JSON::isError($property)) { 556 return $property; 557 } 558 } 559 560 return '{' . join(',', $properties) . '}'; 561 562 default: 563 return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) 564 ? 'null' 565 : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); 566 } 567 } 568 569 /** 570 * array-walking function for use in generating JSON-formatted name-value pairs 571 * 572 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 573 * 574 * @param string $name name of key to use 575 * @param mixed $value reference to an array element to be encoded 576 * 577 * @return string JSON-formatted name-value pair, like '"name":value' 578 * @access private 579 */ 580 function name_value($name, $value) 581 { 582 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 583 584 $encoded_value = $this->_encode($value); 585 586 if(Services_JSON::isError($encoded_value)) { 587 return $encoded_value; 588 } 589 590 return $this->_encode((string) $name) . ':' . $encoded_value; 591 } 592 593 /** 594 * reduce a string by removing leading and trailing comments and whitespace 595 * 596 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 597 * 598 * @param $str string string value to strip of comments and whitespace 599 * 600 * @return string string value stripped of comments and whitespace 601 * @access private 602 */ 603 function reduce_string($str) 604 { 605 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 606 607 $str = preg_replace(array( 608 609 // eliminate single line comments in '// ...' form 610 '#^\s*//(.+)$#m', 611 612 // eliminate multi-line comments in '/* ... */' form, at start of string 613 '#^\s*/\*(.+)\*/#Us', 614 615 // eliminate multi-line comments in '/* ... */' form, at end of string 616 '#/\*(.+)\*/\s*$#Us' 617 618 ), '', $str); 619 620 // eliminate extraneous space 621 return trim($str); 622 } 623 624 /** 625 * decodes a JSON string into appropriate variable 626 * 627 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 628 * 629 * @param string $str JSON-formatted string 630 * 631 * @return mixed number, boolean, string, array, or object 632 * corresponding to given JSON input string. 633 * See argument 1 to Services_JSON() above for object-output behavior. 634 * Note that decode() always returns strings 635 * in ASCII or UTF-8 format! 636 * @access public 637 */ 638 function decode($str) 639 { 640 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 641 642 $str = $this->reduce_string($str); 643 644 switch (strtolower($str)) { 645 case 'true': 646 return true; 647 648 case 'false': 649 return false; 650 651 case 'null': 652 return null; 653 654 default: 655 $m = array(); 656 657 if (is_numeric($str)) { 658 // Lookie-loo, it's a number 659 660 // This would work on its own, but I'm trying to be 661 // good about returning integers where appropriate: 662 // return (float)$str; 663 664 // Return float or int, as appropriate 665 return ((float)$str == (integer)$str) 666 ? (integer)$str 667 : (float)$str; 668 669 } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { 670 // STRINGS RETURNED IN UTF-8 FORMAT 671 $delim = $this->substr8($str, 0, 1); 672 $chrs = $this->substr8($str, 1, -1); 673 $utf8 = ''; 674 $strlen_chrs = $this->strlen8($chrs); 675 676 for ($c = 0; $c < $strlen_chrs; ++$c) { 677 678 $substr_chrs_c_2 = $this->substr8($chrs, $c, 2); 679 $ord_chrs_c = ord($chrs[$c]); 680 681 switch (true) { 682 case $substr_chrs_c_2 == '\b': 683 $utf8 .= chr(0x08); 684 ++$c; 685 break; 686 case $substr_chrs_c_2 == '\t': 687 $utf8 .= chr(0x09); 688 ++$c; 689 break; 690 case $substr_chrs_c_2 == '\n': 691 $utf8 .= chr(0x0A); 692 ++$c; 693 break; 694 case $substr_chrs_c_2 == '\f': 695 $utf8 .= chr(0x0C); 696 ++$c; 697 break; 698 case $substr_chrs_c_2 == '\r': 699 $utf8 .= chr(0x0D); 700 ++$c; 701 break; 702 703 case $substr_chrs_c_2 == '\\"': 704 case $substr_chrs_c_2 == '\\\'': 705 case $substr_chrs_c_2 == '\\\\': 706 case $substr_chrs_c_2 == '\\/': 707 if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || 708 ($delim == "'" && $substr_chrs_c_2 != '\\"')) { 709 $utf8 .= $chrs[++$c]; 710 } 711 break; 712 713 case preg_match('/\\\u[0-9A-F]{4}/i', $this->substr8($chrs, $c, 6)): 714 // single, escaped unicode character 715 $utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2))) 716 . chr(hexdec($this->substr8($chrs, ($c + 4), 2))); 717 $utf8 .= $this->utf162utf8($utf16); 718 $c += 5; 719 break; 720 721 case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): 722 $utf8 .= $chrs[$c]; 723 break; 724 725 case ($ord_chrs_c & 0xE0) == 0xC0: 726 // characters U-00000080 - U-000007FF, mask 110XXXXX 727 //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 728 $utf8 .= $this->substr8($chrs, $c, 2); 729 ++$c; 730 break; 731 732 case ($ord_chrs_c & 0xF0) == 0xE0: 733 // characters U-00000800 - U-0000FFFF, mask 1110XXXX 734 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 735 $utf8 .= $this->substr8($chrs, $c, 3); 736 $c += 2; 737 break; 738 739 case ($ord_chrs_c & 0xF8) == 0xF0: 740 // characters U-00010000 - U-001FFFFF, mask 11110XXX 741 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 742 $utf8 .= $this->substr8($chrs, $c, 4); 743 $c += 3; 744 break; 745 746 case ($ord_chrs_c & 0xFC) == 0xF8: 747 // characters U-00200000 - U-03FFFFFF, mask 111110XX 748 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 749 $utf8 .= $this->substr8($chrs, $c, 5); 750 $c += 4; 751 break; 752 753 case ($ord_chrs_c & 0xFE) == 0xFC: 754 // characters U-04000000 - U-7FFFFFFF, mask 1111110X 755 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 756 $utf8 .= $this->substr8($chrs, $c, 6); 757 $c += 5; 758 break; 759 760 } 761 762 } 763 764 return $utf8; 765 766 } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { 767 // array, or object notation 768 769 if ($str[0] == '[') { 770 $stk = array(SERVICES_JSON_IN_ARR); 771 $arr = array(); 772 } else { 773 if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 774 $stk = array(SERVICES_JSON_IN_OBJ); 775 $obj = array(); 776 } else { 777 $stk = array(SERVICES_JSON_IN_OBJ); 778 $obj = new stdClass(); 779 } 780 } 781 782 array_push($stk, array('what' => SERVICES_JSON_SLICE, 783 'where' => 0, 784 'delim' => false)); 785 786 $chrs = $this->substr8($str, 1, -1); 787 $chrs = $this->reduce_string($chrs); 788 789 if ($chrs == '') { 790 if (reset($stk) == SERVICES_JSON_IN_ARR) { 791 return $arr; 792 793 } else { 794 return $obj; 795 796 } 797 } 798 799 //print("\nparsing {$chrs}\n"); 800 801 $strlen_chrs = $this->strlen8($chrs); 802 803 for ($c = 0; $c <= $strlen_chrs; ++$c) { 804 805 $top = end($stk); 806 $substr_chrs_c_2 = $this->substr8($chrs, $c, 2); 807 808 if (($c == $strlen_chrs) || (($chrs[$c] == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { 809 // found a comma that is not inside a string, array, etc., 810 // OR we've reached the end of the character list 811 $slice = $this->substr8($chrs, $top['where'], ($c - $top['where'])); 812 array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); 813 //print("Found split at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 814 815 if (reset($stk) == SERVICES_JSON_IN_ARR) { 816 // we are in an array, so just push an element onto the stack 817 array_push($arr, $this->decode($slice)); 818 819 } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { 820 // we are in an object, so figure 821 // out the property name and set an 822 // element in an associative array, 823 // for now 824 $parts = array(); 825 826 if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:/Uis', $slice, $parts)) { 827 // "name":value pair 828 $key = $this->decode($parts[1]); 829 $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); 830 if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 831 $obj[$key] = $val; 832 } else { 833 $obj->$key = $val; 834 } 835 } elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) { 836 // name:value pair, where name is unquoted 837 $key = $parts[1]; 838 $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); 839 840 if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 841 $obj[$key] = $val; 842 } else { 843 $obj->$key = $val; 844 } 845 } 846 847 } 848 849 } elseif ((($chrs[$c] == '"') || ($chrs[$c] == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { 850 // found a quote, and we are not inside a string 851 array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs[$c])); 852 //print("Found start of string at {$c}\n"); 853 854 } elseif (($chrs[$c] == $top['delim']) && 855 ($top['what'] == SERVICES_JSON_IN_STR) && 856 (($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($chrs, 0, $c), '\\'))) % 2 != 1)) { 857 // found a quote, we're in a string, and it's not escaped 858 // we know that it's not escaped because there is _not_ an 859 // odd number of backslashes at the end of the string so far 860 array_pop($stk); 861 //print("Found end of string at {$c}: ".$this->substr8($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); 862 863 } elseif (($chrs[$c] == '[') && 864 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { 865 // found a left-bracket, and we are in an array, object, or slice 866 array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); 867 //print("Found start of array at {$c}\n"); 868 869 } elseif (($chrs[$c] == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { 870 // found a right-bracket, and we're in an array 871 array_pop($stk); 872 //print("Found end of array at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 873 874 } elseif (($chrs[$c] == '{') && 875 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { 876 // found a left-brace, and we are in an array, object, or slice 877 array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); 878 //print("Found start of object at {$c}\n"); 879 880 } elseif (($chrs[$c] == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { 881 // found a right-brace, and we're in an object 882 array_pop($stk); 883 //print("Found end of object at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 884 885 } elseif (($substr_chrs_c_2 == '/*') && 886 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { 887 // found a comment start, and we are in an array, object, or slice 888 array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); 889 $c++; 890 //print("Found start of comment at {$c}\n"); 891 892 } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { 893 // found a comment end, and we're in one now 894 array_pop($stk); 895 $c++; 896 897 for ($i = $top['where']; $i <= $c; ++$i) 898 $chrs = substr_replace($chrs, ' ', $i, 1); 899 900 //print("Found end of comment at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 901 902 } 903 904 } 905 906 if (reset($stk) == SERVICES_JSON_IN_ARR) { 907 return $arr; 908 909 } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { 910 return $obj; 911 912 } 913 914 } 915 } 916 } 917 918 /** 919 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 920 * 921 * @todo Ultimately, this should just call PEAR::isError() 922 */ 923 function isError($data, $code = null) 924 { 925 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 926 927 if (class_exists('pear')) { 928 return PEAR::isError($data, $code); 929 } elseif (is_object($data) && ($data instanceof services_json_error || 930 is_subclass_of($data, 'services_json_error'))) { 931 return true; 932 } 933 934 return false; 935 } 936 937 /** 938 * Calculates length of string in bytes 939 * 940 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 941 * 942 * @param string 943 * @return integer length 944 */ 945 function strlen8( $str ) 946 { 947 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 948 949 if ( $this->_mb_strlen ) { 950 return mb_strlen( $str, "8bit" ); 951 } 952 return strlen( $str ); 953 } 954 955 /** 956 * Returns part of a string, interpreting $start and $length as number of bytes. 957 * 958 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 959 * 960 * @param string 961 * @param integer start 962 * @param integer length 963 * @return integer length 964 */ 965 function substr8( $string, $start, $length=false ) 966 { 967 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 968 969 if ( $length === false ) { 970 $length = $this->strlen8( $string ) - $start; 971 } 972 if ( $this->_mb_substr ) { 973 return mb_substr( $string, $start, $length, "8bit" ); 974 } 975 return substr( $string, $start, $length ); 976 } 977 978 } 979 980 if (class_exists('PEAR_Error')) { 981 982 class Services_JSON_Error extends PEAR_Error 983 { 984 /** 985 * PHP5 constructor. 986 * 987 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 988 */ 989 function __construct($message = 'unknown error', $code = null, 990 $mode = null, $options = null, $userinfo = null) 991 { 992 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 993 994 parent::PEAR_Error($message, $code, $mode, $options, $userinfo); 995 } 996 997 /** 998 * PHP4 constructor. 999 * 1000 * @deprecated 5.3.0 Use __construct() instead. 1001 * 1002 * @see Services_JSON_Error::__construct() 1003 */ 1004 public function Services_JSON_Error($message = 'unknown error', $code = null, 1005 $mode = null, $options = null, $userinfo = null) { 1006 _deprecated_constructor( 'Services_JSON_Error', '5.3.0', get_class( $this ) ); 1007 self::__construct($message, $code, $mode, $options, $userinfo); 1008 } 1009 } 1010 1011 } else { 1012 1013 /** 1014 * @todo Ultimately, this class shall be descended from PEAR_Error 1015 */ 1016 class Services_JSON_Error 1017 { 1018 /** 1019 * PHP5 constructor. 1020 * 1021 * @deprecated 5.3.0 Use the PHP native JSON extension instead. 1022 */ 1023 function __construct( $message = 'unknown error', $code = null, 1024 $mode = null, $options = null, $userinfo = null ) 1025 { 1026 _deprecated_function( __METHOD__, '5.3.0', 'The PHP native JSON extension' ); 1027 } 1028 1029 /** 1030 * PHP4 constructor. 1031 * 1032 * @deprecated 5.3.0 Use __construct() instead. 1033 * 1034 * @see Services_JSON_Error::__construct() 1035 */ 1036 public function Services_JSON_Error( $message = 'unknown error', $code = null, 1037 $mode = null, $options = null, $userinfo = null ) { 1038 _deprecated_constructor( 'Services_JSON_Error', '5.3.0', get_class( $this ) ); 1039 self::__construct( $message, $code, $mode, $options, $userinfo ); 1040 } 1041 } 1042 1043 } 1044 1045 endif;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |