[ Index ] |
PHP Cross Reference of phool |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @category phool 4 * @package phool 5 */ 6 //============================================================================ 7 /** 8 * This file is adapted from the PEAR Services_JSON package version 1.0.3, 9 * available at http://pear.php.net/package/Services_JSON. 10 * 11 * Changes from PEAR version: 12 * - switch to PHP 5 object syntax 13 * - make independant from PEAR error handling using exceptions . Also 14 * remove SERVICES_JSON_SUPPRESS_ERRORS flag (replace with a try/catch 15 * construct) 16 */ 17 18 namespace Phool\Web; 19 20 /** 21 * Converts to and from JSON format. 22 * 23 * JSON (JavaScript Object Notation) is a lightweight data-interchange 24 * format. It is easy for humans to read and write. It is easy for machines 25 * to parse and generate. It is based on a subset of the JavaScript 26 * Programming Language, Standard ECMA-262 3rd Edition - December 1999. 27 * This feature can also be found in Python. JSON is a text format that is 28 * completely language independent but uses conventions that are familiar 29 * to programmers of the C-family of languages, including C, C++, C#, Java, 30 * JavaScript, Perl, TCL, and many others. These properties make JSON an 31 * ideal data-interchange language. 32 * 33 * This package provides a simple encoder and decoder for JSON notation. It 34 * is intended for use with client-side Javascript applications that make 35 * use of HTTPRequest to perform server communication functions - data can 36 * be encoded into JSON notation for use in a client-side javascript, or 37 * decoded from incoming Javascript requests. JSON format is native to 38 * Javascript, and can be directly eval()'ed with no further parsing 39 * overhead 40 * 41 * All strings should be in ASCII or UTF-8 format! 42 * 43 * LICENSE: Redistribution and use in source and binary forms, with or 44 * without modification, are permitted provided that the following 45 * conditions are met: Redistributions of source code must retain the 46 * above copyright notice, this list of conditions and the following 47 * disclaimer. Redistributions in binary form must reproduce the above 48 * copyright notice, this list of conditions and the following disclaimer 49 * in the documentation and/or other materials provided with the 50 * distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 53 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 54 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 55 * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 57 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 58 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 59 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 60 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 61 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 62 * DAMAGE. 63 * 64 * @category 65 * @package Services_JSON 66 * @author Michal Migurski <mike-json@teczno.com> 67 * @author Matt Knapp <mdknapp[at]gmail[dot]com> 68 * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com> 69 * @author Francois Laupretre <francois@tekwire.net> 70 * @copyright 2005 Michal Migurski 71 * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ 72 * @license http://www.opensource.org/licenses/bsd-license.php 73 * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 74 */ 75 76 /** 77 * Marker constant for Services_JSON::decode(), used to flag stack state 78 */ 79 const SERVICES_JSON_SLICE=1; 80 81 /** 82 * Marker constant for Services_JSON::decode(), used to flag stack state 83 */ 84 const SERVICES_JSON_IN_STR=2; 85 86 /** 87 * Marker constant for Services_JSON::decode(), used to flag stack state 88 */ 89 const SERVICES_JSON_IN_ARR=3; 90 91 /** 92 * Marker constant for Services_JSON::decode(), used to flag stack state 93 */ 94 const SERVICES_JSON_IN_OBJ=4; 95 96 /** 97 * Marker constant for Services_JSON::decode(), used to flag stack state 98 */ 99 const SERVICES_JSON_IN_CMT=5; 100 101 /** 102 * Behavior switch for Services_JSON::decode() 103 */ 104 const SERVICES_JSON_LOOSE_TYPE=16; 105 106 /** 107 * Converts to and from JSON format. 108 * 109 * Brief example of use: 110 * 111 * <code> 112 * // create a new instance of Services_JSON 113 * $json = new \Phool\Web\Services_JSON(); 114 * 115 * // convert a complexe value to JSON notation, and send it to the browser 116 * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); 117 * $output = $json->encode($value); 118 * 119 * print($output); 120 * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] 121 * 122 * // accept incoming POST data, assumed to be in JSON notation 123 * $input = file_get_contents('php://input', 1000000); 124 * $value = $json->decode($input); 125 * </code> 126 */ 127 class Services_JSON 128 { 129 /** 130 * constructs a new JSON instance 131 */ 132 133 /** @var int object behavior flags; combine with boolean-OR */ 134 135 private $use; 136 137 /** 138 * @param int $use object behavior flags; combine with boolean-OR 139 * 140 * possible values: 141 * - SERVICES_JSON_LOOSE_TYPE: loose typing. 142 * "{...}" syntax creates associative arrays 143 * instead of objects in decode(). 144 */ 145 public function __construct($use = 0) 146 { 147 $this->use = $use; 148 } 149 150 /** 151 * convert a string from one UTF-16 char to one UTF-8 char 152 * 153 * Normally should be handled by mb_convert_encoding, but 154 * provides a slower PHP-only method for installations 155 * that lack the multibye string extension. 156 * 157 * @param string $utf16 UTF-16 character 158 * @return string UTF-8 character 159 */ 160 private function utf162utf8($utf16) 161 { 162 // oh please oh please oh please oh please oh please 163 if(function_exists('mb_convert_encoding')) { 164 return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); 165 } 166 167 $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); 168 169 switch(true) { 170 case ((0x7F & $bytes) == $bytes): 171 // this case should never be reached, because we are in ASCII range 172 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 173 return chr(0x7F & $bytes); 174 175 case (0x07FF & $bytes) == $bytes: 176 // return a 2-byte UTF-8 character 177 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 178 return chr(0xC0 | (($bytes >> 6) & 0x1F)) 179 . chr(0x80 | ($bytes & 0x3F)); 180 181 case (0xFFFF & $bytes) == $bytes: 182 // return a 3-byte UTF-8 character 183 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 184 return chr(0xE0 | (($bytes >> 12) & 0x0F)) 185 . chr(0x80 | (($bytes >> 6) & 0x3F)) 186 . chr(0x80 | ($bytes & 0x3F)); 187 } 188 189 // ignoring UTF-32 for now, sorry 190 return ''; 191 } 192 193 /** 194 * convert a string from one UTF-8 char to one UTF-16 char 195 * 196 * Normally should be handled by mb_convert_encoding, but 197 * provides a slower PHP-only method for installations 198 * that lack the multibye string extension. 199 * 200 * @param string $utf8 UTF-8 character 201 * @return string UTF-16 character 202 */ 203 private function utf82utf16($utf8) 204 { 205 // oh please oh please oh please oh please oh please 206 if(function_exists('mb_convert_encoding')) { 207 return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); 208 } 209 210 switch(strlen($utf8)) { 211 case 1: 212 // this case should never be reached, because we are in ASCII range 213 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 214 return $utf8; 215 216 case 2: 217 // return a UTF-16 character from a 2-byte UTF-8 char 218 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 219 return chr(0x07 & (ord($utf8{0}) >> 2)) 220 . chr((0xC0 & (ord($utf8{0}) << 6)) 221 | (0x3F & ord($utf8{1}))); 222 223 case 3: 224 // return a UTF-16 character from a 3-byte UTF-8 char 225 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 226 return chr((0xF0 & (ord($utf8{0}) << 4)) 227 | (0x0F & (ord($utf8{1}) >> 2))) 228 . chr((0xC0 & (ord($utf8{1}) << 6)) 229 | (0x7F & ord($utf8{2}))); 230 } 231 232 // ignoring UTF-32 for now, sorry 233 return ''; 234 } 235 236 /** 237 * encodes an arbitrary variable into JSON format 238 * 239 * @param mixed $var any number, boolean, string, array, or object to be encoded. 240 * see argument 1 to Services_JSON() above for array-parsing behavior. 241 * if var is a strng, note that encode() always expects it 242 * to be in ASCII or UTF-8 format! 243 * 244 * @return mixed JSON string representation of input var 245 * @throws Exception if a problem occurs 246 */ 247 public function encode($var) 248 { 249 switch (gettype($var)) { 250 case 'boolean': 251 return $var ? 'true' : 'false'; 252 253 case 'NULL': 254 return 'null'; 255 256 case 'integer': 257 return (int) $var; 258 259 case 'double': 260 case 'float': 261 return (float) $var; 262 263 case 'string': 264 // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT 265 $ascii = ''; 266 $strlen_var = strlen($var); 267 268 /* 269 * Iterate over every character in the string, 270 * escaping with a slash or encoding to UTF-8 where necessary 271 */ 272 for ($c = 0; $c < $strlen_var; ++$c) { 273 274 $ord_var_c = ord($var{$c}); 275 276 switch (true) { 277 case $ord_var_c == 0x08: 278 $ascii .= '\b'; 279 break; 280 case $ord_var_c == 0x09: 281 $ascii .= '\t'; 282 break; 283 case $ord_var_c == 0x0A: 284 $ascii .= '\n'; 285 break; 286 case $ord_var_c == 0x0C: 287 $ascii .= '\f'; 288 break; 289 case $ord_var_c == 0x0D: 290 $ascii .= '\r'; 291 break; 292 293 case $ord_var_c == 0x22: 294 case $ord_var_c == 0x2F: 295 case $ord_var_c == 0x5C: 296 // double quote, slash, slosh 297 $ascii .= '\\'.$var{$c}; 298 break; 299 300 case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): 301 // characters U-00000000 - U-0000007F (same as ASCII) 302 $ascii .= $var{$c}; 303 break; 304 305 case (($ord_var_c & 0xE0) == 0xC0): 306 // characters U-00000080 - U-000007FF, mask 110XXXXX 307 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 308 $char = pack('C*', $ord_var_c, ord($var{$c + 1})); 309 $c += 1; 310 $utf16 = $this->utf82utf16($char); 311 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 312 break; 313 314 case (($ord_var_c & 0xF0) == 0xE0): 315 // characters U-00000800 - U-0000FFFF, mask 1110XXXX 316 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 317 $char = pack('C*', $ord_var_c, 318 ord($var{$c + 1}), 319 ord($var{$c + 2})); 320 $c += 2; 321 $utf16 = $this->utf82utf16($char); 322 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 323 break; 324 325 case (($ord_var_c & 0xF8) == 0xF0): 326 // characters U-00010000 - U-001FFFFF, mask 11110XXX 327 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 328 $char = pack('C*', $ord_var_c, 329 ord($var{$c + 1}), 330 ord($var{$c + 2}), 331 ord($var{$c + 3})); 332 $c += 3; 333 $utf16 = $this->utf82utf16($char); 334 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 335 break; 336 337 case (($ord_var_c & 0xFC) == 0xF8): 338 // characters U-00200000 - U-03FFFFFF, mask 111110XX 339 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 340 $char = pack('C*', $ord_var_c, 341 ord($var{$c + 1}), 342 ord($var{$c + 2}), 343 ord($var{$c + 3}), 344 ord($var{$c + 4})); 345 $c += 4; 346 $utf16 = $this->utf82utf16($char); 347 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 348 break; 349 350 case (($ord_var_c & 0xFE) == 0xFC): 351 // characters U-04000000 - U-7FFFFFFF, mask 1111110X 352 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 353 $char = pack('C*', $ord_var_c, 354 ord($var{$c + 1}), 355 ord($var{$c + 2}), 356 ord($var{$c + 3}), 357 ord($var{$c + 4}), 358 ord($var{$c + 5})); 359 $c += 5; 360 $utf16 = $this->utf82utf16($char); 361 $ascii .= sprintf('\u%04s', bin2hex($utf16)); 362 break; 363 } 364 } 365 366 return '"'.$ascii.'"'; 367 368 case 'array': 369 /* 370 * As per JSON spec if any array key is not an integer 371 * we must treat the the whole array as an object. We 372 * also try to catch a sparsely populated associative 373 * array with numeric keys here because some JS engines 374 * will create an array with empty indexes up to 375 * max_index which can cause memory issues and because 376 * the keys, which may be relevant, will be remapped 377 * otherwise. 378 * 379 * As per the ECMA and JSON specification an object may 380 * have any string as a property. Unfortunately due to 381 * a hole in the ECMA specification if the key is a 382 * ECMA reserved word or starts with a digit the 383 * parameter is only accessible using ECMAScript's 384 * bracket notation. 385 */ 386 387 // treat as a JSON object 388 if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { 389 $properties = array_map(array($this, 'name_value'), 390 array_keys($var), 391 array_values($var)); 392 return '{' . join(',', $properties) . '}'; 393 } 394 395 // treat it like a regular array 396 $elements = array_map(array($this, 'encode'), $var); 397 return '[' . join(',', $elements) . ']'; 398 399 case 'object': 400 $vars = get_object_vars($var); 401 402 $properties = array_map(array($this, 'name_value'), 403 array_keys($vars), 404 array_values($vars)); 405 return '{' . join(',', $properties) . '}'; 406 407 default: 408 throw new \Exception(gettype($var)." can not be encoded as JSON string"); 409 } 410 } 411 412 /** 413 * array-walking function for use in generating JSON-formatted name-value pairs 414 * 415 * @param string $name name of key to use 416 * @param mixed $value reference to an array element to be encoded 417 * 418 * @return string JSON-formatted name-value pair, like '"name":value' 419 */ 420 private function name_value($name, $value) 421 { 422 return $this->encode(strval($name)) . ':' . $this->encode($value); 423 } 424 425 /** 426 * reduce a string by removing leading and trailing comments and whitespace 427 * 428 * @param $str string string value to strip of comments and whitespace 429 * 430 * @return string string value stripped of comments and whitespace 431 */ 432 private function reduce_string($str) 433 { 434 $str = preg_replace(array( 435 436 // eliminate single line comments in '// ...' form 437 '#^\s*//(.+)$#m', 438 439 // eliminate multi-line comments in '/* ... */' form, at start of string 440 '#^\s*/\*(.+)\*/#Us', 441 442 // eliminate multi-line comments in '/* ... */' form, at end of string 443 '#/\*(.+)\*/\s*$#Us' 444 445 ), '', $str); 446 447 // eliminate extraneous space 448 return trim($str); 449 } 450 451 /** 452 * decodes a JSON string into appropriate variable 453 * 454 * @param string $str JSON-formatted string 455 * 456 * @return mixed number, boolean, string, array, or object 457 * corresponding to given JSON input string. 458 * See argument 1 to Services_JSON() above for object-output behavior. 459 * Note that decode() always returns strings 460 * in ASCII or UTF-8 format! 461 */ 462 public function decode($str) 463 { 464 $str = $this->reduce_string($str); 465 466 switch (strtolower($str)) { 467 case 'true': 468 return true; 469 470 case 'false': 471 return false; 472 473 case 'null': 474 return null; 475 476 default: 477 $m = array(); 478 479 if (is_numeric($str)) { 480 // Lookie-loo, it's a number 481 482 // This would work on its own, but I'm trying to be 483 // good about returning integers where appropriate: 484 // return (float)$str; 485 486 // Return float or int, as appropriate 487 return ((float)$str == (integer)$str) 488 ? (integer)$str 489 : (float)$str; 490 491 } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { 492 // STRINGS RETURNED IN UTF-8 FORMAT 493 $delim = substr($str, 0, 1); 494 $chrs = substr($str, 1, -1); 495 $utf8 = ''; 496 $strlen_chrs = strlen($chrs); 497 498 for ($c = 0; $c < $strlen_chrs; ++$c) { 499 500 $substr_chrs_c_2 = substr($chrs, $c, 2); 501 $ord_chrs_c = ord($chrs{$c}); 502 503 switch (true) { 504 case $substr_chrs_c_2 == '\b': 505 $utf8 .= chr(0x08); 506 ++$c; 507 break; 508 case $substr_chrs_c_2 == '\t': 509 $utf8 .= chr(0x09); 510 ++$c; 511 break; 512 case $substr_chrs_c_2 == '\n': 513 $utf8 .= chr(0x0A); 514 ++$c; 515 break; 516 case $substr_chrs_c_2 == '\f': 517 $utf8 .= chr(0x0C); 518 ++$c; 519 break; 520 case $substr_chrs_c_2 == '\r': 521 $utf8 .= chr(0x0D); 522 ++$c; 523 break; 524 525 case $substr_chrs_c_2 == '\\"': 526 case $substr_chrs_c_2 == '\\\'': 527 case $substr_chrs_c_2 == '\\\\': 528 case $substr_chrs_c_2 == '\\/': 529 if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || 530 ($delim == "'" && $substr_chrs_c_2 != '\\"')) { 531 $utf8 .= $chrs{++$c}; 532 } 533 break; 534 535 case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): 536 // single, escaped unicode character 537 $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) 538 . chr(hexdec(substr($chrs, ($c + 4), 2))); 539 $utf8 .= $this->utf162utf8($utf16); 540 $c += 5; 541 break; 542 543 case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): 544 $utf8 .= $chrs{$c}; 545 break; 546 547 case ($ord_chrs_c & 0xE0) == 0xC0: 548 // characters U-00000080 - U-000007FF, mask 110XXXXX 549 //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 550 $utf8 .= substr($chrs, $c, 2); 551 ++$c; 552 break; 553 554 case ($ord_chrs_c & 0xF0) == 0xE0: 555 // characters U-00000800 - U-0000FFFF, mask 1110XXXX 556 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 557 $utf8 .= substr($chrs, $c, 3); 558 $c += 2; 559 break; 560 561 case ($ord_chrs_c & 0xF8) == 0xF0: 562 // characters U-00010000 - U-001FFFFF, mask 11110XXX 563 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 564 $utf8 .= substr($chrs, $c, 4); 565 $c += 3; 566 break; 567 568 case ($ord_chrs_c & 0xFC) == 0xF8: 569 // characters U-00200000 - U-03FFFFFF, mask 111110XX 570 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 571 $utf8 .= substr($chrs, $c, 5); 572 $c += 4; 573 break; 574 575 case ($ord_chrs_c & 0xFE) == 0xFC: 576 // characters U-04000000 - U-7FFFFFFF, mask 1111110X 577 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 578 $utf8 .= substr($chrs, $c, 6); 579 $c += 5; 580 break; 581 582 } 583 584 } 585 586 return $utf8; 587 588 } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { 589 // array, or object notation 590 591 if ($str{0} == '[') { 592 $stk = array(SERVICES_JSON_IN_ARR); 593 $arr = array(); 594 } else { 595 if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 596 $stk = array(SERVICES_JSON_IN_OBJ); 597 $obj = array(); 598 } else { 599 $stk = array(SERVICES_JSON_IN_OBJ); 600 $obj = new \stdClass(); 601 } 602 } 603 604 array_push($stk, array('what' => SERVICES_JSON_SLICE, 605 'where' => 0, 606 'delim' => false)); 607 608 $chrs = substr($str, 1, -1); 609 $chrs = $this->reduce_string($chrs); 610 611 if ($chrs == '') { 612 if (reset($stk) == SERVICES_JSON_IN_ARR) { 613 return $arr; 614 615 } else { 616 return $obj; 617 618 } 619 } 620 621 //print("\nparsing {$chrs}\n"); 622 623 $strlen_chrs = strlen($chrs); 624 625 for ($c = 0; $c <= $strlen_chrs; ++$c) { 626 627 $top = end($stk); 628 $substr_chrs_c_2 = substr($chrs, $c, 2); 629 630 if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { 631 // found a comma that is not inside a string, array, etc., 632 // OR we've reached the end of the character list 633 $slice = substr($chrs, $top['where'], ($c - $top['where'])); 634 array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); 635 //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 636 637 if (reset($stk) == SERVICES_JSON_IN_ARR) { 638 // we are in an array, so just push an element onto the stack 639 array_push($arr, $this->decode($slice)); 640 641 } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { 642 // we are in an object, so figure 643 // out the property name and set an 644 // element in an associative array, 645 // for now 646 $parts = array(); 647 648 if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { 649 // "name":value pair 650 $key = $this->decode($parts[1]); 651 $val = $this->decode($parts[2]); 652 653 if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 654 $obj[$key] = $val; 655 } else { 656 $obj->$key = $val; 657 } 658 } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { 659 // name:value pair, where name is unquoted 660 $key = $parts[1]; 661 $val = $this->decode($parts[2]); 662 663 if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 664 $obj[$key] = $val; 665 } else { 666 $obj->$key = $val; 667 } 668 } 669 670 } 671 672 } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { 673 // found a quote, and we are not inside a string 674 array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); 675 //print("Found start of string at {$c}\n"); 676 677 } elseif (($chrs{$c} == $top['delim']) && 678 ($top['what'] == SERVICES_JSON_IN_STR) && 679 ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { 680 // found a quote, we're in a string, and it's not escaped 681 // we know that it's not escaped becase there is _not_ an 682 // odd number of backslashes at the end of the string so far 683 array_pop($stk); 684 //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); 685 686 } elseif (($chrs{$c} == '[') && 687 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { 688 // found a left-bracket, and we are in an array, object, or slice 689 array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); 690 //print("Found start of array at {$c}\n"); 691 692 } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { 693 // found a right-bracket, and we're in an array 694 array_pop($stk); 695 //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 696 697 } elseif (($chrs{$c} == '{') && 698 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { 699 // found a left-brace, and we are in an array, object, or slice 700 array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); 701 //print("Found start of object at {$c}\n"); 702 703 } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { 704 // found a right-brace, and we're in an object 705 array_pop($stk); 706 //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 707 708 } elseif (($substr_chrs_c_2 == '/*') && 709 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { 710 // found a comment start, and we are in an array, object, or slice 711 array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); 712 $c++; 713 //print("Found start of comment at {$c}\n"); 714 715 } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { 716 // found a comment end, and we're in one now 717 array_pop($stk); 718 $c++; 719 720 for ($i = $top['where']; $i <= $c; ++$i) 721 $chrs = substr_replace($chrs, ' ', $i, 1); 722 723 //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 724 725 } 726 727 } 728 729 if (reset($stk) == SERVICES_JSON_IN_ARR) { 730 return $arr; 731 732 } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { 733 return $obj; 734 735 } 736 737 } 738 } 739 } 740 } 741 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jun 4 19:17:11 2015 | Cross-referenced by PHPXref 0.7.1 |