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