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