[ Index ]

PHP Cross Reference of MyBB 1.8.29

title

Body

[close]

/inc/3rdparty/json/ -> json.php (source)

   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  }


2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup Cross-referenced by PHPXref