[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/include/Zend/Json/ -> Decoder.php (source)

   1  <?php
   2  /**
   3   * Zend Framework
   4   *
   5   * LICENSE
   6   *
   7   * This source file is subject to the new BSD license that is bundled
   8   * with this package in the file LICENSE.txt.
   9   * It is also available through the world-wide-web at this URL:
  10   * http://framework.zend.com/license/new-bsd
  11   * If you did not receive a copy of the license and are unable to
  12   * obtain it through the world-wide-web, please send an email
  13   * to [email protected] so we can send you a copy immediately.
  14   *
  15   * @category   Zend
  16   * @package    Zend_Json
  17   * @copyright  Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  18   * @license    http://framework.zend.com/license/new-bsd     New BSD License
  19   */
  20  
  21  /**
  22   * Zend_Json
  23   */
  24  require_once  'include/Zend/Json.php';
  25  
  26  /**
  27   * Zend_Json_Exception
  28   */
  29  require_once  'include/Zend/Json/Exception.php';
  30  
  31  
  32  /**
  33   * Decode JSON encoded string to PHP variable constructs
  34   *
  35   * @category   Zend
  36   * @package    Zend_Json
  37   * @copyright  Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  38   * @license    http://framework.zend.com/license/new-bsd     New BSD License
  39   */
  40  class Zend_Json_Decoder
  41  {
  42      /**
  43       * Parse tokens used to decode the JSON object. These are not
  44       * for public consumption, they are just used internally to the
  45       * class.
  46       */
  47      const EOF         = 0;
  48      const DATUM        = 1;
  49      const LBRACE    = 2;
  50      const LBRACKET    = 3;
  51      const RBRACE     = 4;
  52      const RBRACKET    = 5;
  53      const COMMA       = 6;
  54      const COLON        = 7;
  55  
  56      /**
  57       * Use to maintain a "pointer" to the source being decoded
  58       *
  59       * @var string
  60       */
  61      protected $_source;
  62  
  63      /**
  64       * Caches the source length
  65       *
  66       * @var int
  67       */
  68      protected $_sourceLength;
  69  
  70      /**
  71       * The offset within the souce being decoded
  72       *
  73       * @var int
  74       *
  75       */
  76      protected $_offset;
  77  
  78      /**
  79       * The current token being considered in the parser cycle
  80       *
  81       * @var int
  82       */
  83      protected $_token;
  84  
  85      /**
  86       * Flag indicating how objects should be decoded
  87       *
  88       * @var int
  89       * @access protected
  90       */
  91      protected $_decodeType;
  92  
  93      /**
  94       * Constructor
  95       *
  96       * @param string $source String source to decode
  97       * @param int $decodeType How objects should be decoded -- see
  98       * {@link Zend_Json::TYPE_ARRAY} and {@link Zend_Json::TYPE_OBJECT} for
  99       * valid values
 100       * @return void
 101       */
 102      protected function __construct($source, $decodeType)
 103      {
 104          // Set defaults
 105          $this->_source       = $source;
 106          $this->_sourceLength = strlen($source);
 107          $this->_token        = self::EOF;
 108          $this->_offset       = 0;
 109  
 110          // Normalize and set $decodeType
 111          if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT)))
 112          {
 113              $decodeType = Zend_Json::TYPE_ARRAY;
 114          }
 115          $this->_decodeType   = $decodeType;
 116  
 117          // Set pointer at first token
 118          $this->_getNextToken();
 119      }
 120  
 121      /**
 122       * Decode a JSON source string
 123       *
 124       * Decodes a JSON encoded string. The value returned will be one of the
 125       * following:
 126       *        - integer
 127       *        - float
 128       *        - boolean
 129       *        - null
 130       *      - StdClass
 131       *      - array
 132       *         - array of one or more of the above types
 133       *
 134       * By default, decoded objects will be returned as associative arrays; to
 135       * return a StdClass object instead, pass {@link Zend_Json::TYPE_OBJECT} to
 136       * the $objectDecodeType parameter.
 137       *
 138       * Throws a Zend_Json_Exception if the source string is null.
 139       *
 140       * @static
 141       * @access public
 142       * @param string $source String to be decoded
 143       * @param int $objectDecodeType How objects should be decoded; should be
 144       * either or {@link Zend_Json::TYPE_ARRAY} or
 145       * {@link Zend_Json::TYPE_OBJECT}; defaults to TYPE_ARRAY
 146       * @return mixed
 147       * @throws Zend_Json_Exception
 148       */
 149      public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY)
 150      {
 151          if (null === $source) {
 152              throw new Zend_Json_Exception('Must specify JSON encoded source for decoding');
 153          } elseif (!is_string($source)) {
 154              throw new Zend_Json_Exception('Can only decode JSON encoded strings');
 155          }
 156  
 157          $decoder = new self($source, $objectDecodeType);
 158  
 159          return $decoder->_decodeValue();
 160      }
 161  
 162  
 163      /**
 164       * Recursive driving rountine for supported toplevel tops
 165       *
 166       * @return mixed
 167       */
 168      protected function _decodeValue()
 169      {
 170          switch ($this->_token) {
 171              case self::DATUM:
 172                  $result  = $this->_tokenValue;
 173                  $this->_getNextToken();
 174                  return($result);
 175                  break;
 176              case self::LBRACE:
 177                  return($this->_decodeObject());
 178                  break;
 179              case self::LBRACKET:
 180                  return($this->_decodeArray());
 181                  break;
 182              default:
 183                  return null;
 184                  break;
 185          }
 186      }
 187  
 188      /**
 189       * Decodes an object of the form:
 190       *  { "attribute: value, "attribute2" : value,...}
 191       *
 192       * If ZJsonEnoder or ZJAjax was used to encode the original object
 193       * then a special attribute called __className which specifies a class
 194       * name that should wrap the data contained within the encoded source.
 195       *
 196       * Decodes to either an array or StdClass object, based on the value of
 197       * {@link $_decodeType}. If invalid $_decodeType present, returns as an
 198       * array.
 199       *
 200       * @return array|StdClass
 201       */
 202      protected function _decodeObject()
 203      {
 204          $members = array();
 205          $tok = $this->_getNextToken();
 206  
 207          while ($tok && $tok != self::RBRACE) {
 208              if ($tok != self::DATUM || ! is_string($this->_tokenValue)) {
 209                  throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source);
 210              }
 211  
 212              $key = $this->_tokenValue;
 213              $tok = $this->_getNextToken();
 214  
 215              if ($tok != self::COLON) {
 216                  throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source);
 217              }
 218  
 219              $tok = $this->_getNextToken();
 220              $members[$key] = $this->_decodeValue();
 221              $tok = $this->_token;
 222  
 223              if ($tok == self::RBRACE) {
 224                  break;
 225              }
 226  
 227              if ($tok != self::COMMA) {
 228                  throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source);
 229              }
 230  
 231              $tok = $this->_getNextToken();
 232          }
 233  
 234          switch ($this->_decodeType) {
 235              case Zend_Json::TYPE_OBJECT:
 236                  // Create new StdClass and populate with $members
 237                  $result = new StdClass();
 238                  foreach ($members as $key => $value) {
 239                      $result->$key = $value;
 240                  }
 241                  break;
 242              case Zend_Json::TYPE_ARRAY:
 243              default:
 244                  $result = $members;
 245                  break;
 246          }
 247  
 248          $this->_getNextToken();
 249          return $result;
 250      }
 251  
 252      /**
 253       * Decodes a JSON array format:
 254       *    [element, element2,...,elementN]
 255       *
 256       * @return array
 257       */
 258      protected function _decodeArray()
 259      {
 260          $result = array();
 261          $starttok = $tok = $this->_getNextToken(); // Move past the '['
 262          $index  = 0;
 263  
 264          while ($tok && $tok != self::RBRACKET) {
 265              $result[$index++] = $this->_decodeValue();
 266  
 267              $tok = $this->_token;
 268  
 269              if ($tok == self::RBRACKET || !$tok) {
 270                  break;
 271              }
 272  
 273              if ($tok != self::COMMA) {
 274                  throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source);
 275              }
 276  
 277              $tok = $this->_getNextToken();
 278          }
 279  
 280          $this->_getNextToken();
 281          return($result);
 282      }
 283  
 284  
 285      /**
 286       * Removes whitepsace characters from the source input
 287       */
 288      protected function _eatWhitespace()
 289      {
 290          if (preg_match(
 291                  '/([\t\b\f\n\r ])*/s',
 292                  $this->_source,
 293                  $matches,
 294                  PREG_OFFSET_CAPTURE,
 295                  $this->_offset)
 296              && $matches[0][1] == $this->_offset)
 297          {
 298              $this->_offset += strlen($matches[0][0]);
 299          }
 300      }
 301  
 302  
 303      /**
 304       * Retrieves the next token from the source stream
 305       *
 306       * @return int Token constant value specified in class definition
 307       */
 308      protected function _getNextToken()
 309      {
 310          $this->_token      = self::EOF;
 311          $this->_tokenValue = null;
 312          $this->_eatWhitespace();
 313  
 314          if ($this->_offset >= $this->_sourceLength) {
 315              return(self::EOF);
 316          }
 317  
 318          $str        = $this->_source;
 319          $str_length = $this->_sourceLength;
 320          $i          = $this->_offset;
 321          $start      = $i;
 322  
 323          switch ($str{$i}) {
 324              case '{':
 325                 $this->_token = self::LBRACE;
 326                 break;
 327              case '}':
 328                  $this->_token = self::RBRACE;
 329                  break;
 330              case '[':
 331                  $this->_token = self::LBRACKET;
 332                  break;
 333              case ']':
 334                  $this->_token = self::RBRACKET;
 335                  break;
 336              case ',':
 337                  $this->_token = self::COMMA;
 338                  break;
 339              case ':':
 340                  $this->_token = self::COLON;
 341                  break;
 342              case  '"':
 343                  $result = '';
 344                  do {
 345                      $i++;
 346                      if ($i >= $str_length) {
 347                          break;
 348                      }
 349  
 350                      $chr = $str{$i};
 351                      if ($chr == '\\') {
 352                          $i++;
 353                          if ($i >= $str_length) {
 354                              break;
 355                          }
 356                          $chr = $str{$i};
 357                          switch ($chr) {
 358                              case '"' :
 359                                  $result .= '"';
 360                                  break;
 361                              case '\\':
 362                                  $result .= '\\';
 363                                  break;
 364                              case '/' :
 365                                  $result .= '/';
 366                                  break;
 367                              case 'b' :
 368                                  $result .= chr(8);
 369                                  break;
 370                              case 'f' :
 371                                  $result .= chr(12);
 372                                  break;
 373                              case 'n' :
 374                                  $result .= chr(10);
 375                                  break;
 376                              case 'r' :
 377                                  $result .= chr(13);
 378                                  break;
 379                              case 't' :
 380                                  $result .= chr(9);
 381                                  break;
 382                              case '\'' :
 383                                  $result .= '\'';
 384                                  break;
 385                              default:
 386                                  throw new Zend_Json_Exception("Illegal escape "
 387                                      .  "sequence '" . $chr . "'");
 388                              }
 389                      } elseif ($chr == '"') {
 390                          break;
 391                      } else {
 392                          $result .= $chr;
 393                      }
 394                  } while ($i < $str_length);
 395  
 396                  $this->_token = self::DATUM;
 397                  //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1);
 398                  $this->_tokenValue = $result;
 399                  break;
 400              case 't':
 401                  if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") {
 402                      $this->_token = self::DATUM;
 403                  }
 404                  $this->_tokenValue = true;
 405                  $i += 3;
 406                  break;
 407              case 'f':
 408                  if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") {
 409                      $this->_token = self::DATUM;
 410                  }
 411                  $this->_tokenValue = false;
 412                  $i += 4;
 413                  break;
 414              case 'n':
 415                  if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") {
 416                      $this->_token = self::DATUM;
 417                  }
 418                  $this->_tokenValue = NULL;
 419                  $i += 3;
 420                  break;
 421          }
 422  
 423          if ($this->_token != self::EOF) {
 424              $this->_offset = $i + 1; // Consume the last token character
 425              return($this->_token);
 426          }
 427  
 428          $chr = $str{$i};
 429          if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) {
 430              if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s',
 431                  $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) {
 432  
 433                  $datum = $matches[0][0];
 434  
 435                  if (is_numeric($datum)) {
 436                      if (preg_match('/^0\d+$/', $datum)) {
 437                          throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)");
 438                      } else {
 439                          $val  = intval($datum);
 440                          $fVal = floatval($datum);
 441                          $this->_tokenValue = ($val == $fVal ? $val : $fVal);
 442                      }
 443                  } else {
 444                      throw new Zend_Json_Exception("Illegal number format: $datum");
 445                  }
 446  
 447                  $this->_token = self::DATUM;
 448                  $this->_offset = $start + strlen($datum);
 449              }
 450          } else {
 451              throw new Zend_Json_Exception('Illegal Token');
 452          }
 453  
 454          return($this->_token);
 455      }
 456  }
 457  


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1