Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Decoder.php
Go to the documentation of this file.
1 <?php
25 #require_once 'Zend/Json.php';
26 
36 {
42  const EOF = 0;
43  const DATUM = 1;
44  const LBRACE = 2;
45  const LBRACKET = 3;
46  const RBRACE = 4;
47  const RBRACKET = 5;
48  const COMMA = 6;
49  const COLON = 7;
50 
56  protected $_source;
57 
63  protected $_sourceLength;
64 
71  protected $_offset;
72 
78  protected $_token;
79 
86  protected $_decodeType;
87 
97  protected function __construct($source, $decodeType)
98  {
99  // Set defaults
100  $this->_source = self::decodeUnicodeString($source);
101  $this->_sourceLength = strlen($this->_source);
102  $this->_token = self::EOF;
103  $this->_offset = 0;
104 
105  // Normalize and set $decodeType
106  if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT)))
107  {
108  $decodeType = Zend_Json::TYPE_ARRAY;
109  }
110  $this->_decodeType = $decodeType;
111 
112  // Set pointer at first token
113  $this->_getNextToken();
114  }
115 
144  public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY)
145  {
146  if (null === $source) {
147  #require_once 'Zend/Json/Exception.php';
148  throw new Zend_Json_Exception('Must specify JSON encoded source for decoding');
149  } elseif (!is_string($source)) {
150  #require_once 'Zend/Json/Exception.php';
151  throw new Zend_Json_Exception('Can only decode JSON encoded strings');
152  }
153 
154  $decoder = new self($source, $objectDecodeType);
155 
156  return $decoder->_decodeValue();
157  }
158 
159 
165  protected function _decodeValue()
166  {
167  switch ($this->_token) {
168  case self::DATUM:
169  $result = $this->_tokenValue;
170  $this->_getNextToken();
171  return($result);
172  break;
173  case self::LBRACE:
174  return($this->_decodeObject());
175  break;
176  case self::LBRACKET:
177  return($this->_decodeArray());
178  break;
179  default:
180  return null;
181  break;
182  }
183  }
184 
199  protected function _decodeObject()
200  {
201  $members = array();
202  $tok = $this->_getNextToken();
203 
204  while ($tok && $tok != self::RBRACE) {
205  if ($tok != self::DATUM || ! is_string($this->_tokenValue)) {
206  #require_once 'Zend/Json/Exception.php';
207  throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source);
208  }
209 
210  $key = $this->_tokenValue;
211  $tok = $this->_getNextToken();
212 
213  if ($tok != self::COLON) {
214  #require_once 'Zend/Json/Exception.php';
215  throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source);
216  }
217 
218  $tok = $this->_getNextToken();
219  $members[$key] = $this->_decodeValue();
220  $tok = $this->_token;
221 
222  if ($tok == self::RBRACE) {
223  break;
224  }
225 
226  if ($tok != self::COMMA) {
227  #require_once 'Zend/Json/Exception.php';
228  throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source);
229  }
230 
231  $tok = $this->_getNextToken();
232  }
233 
234  switch ($this->_decodeType) {
236  // Create new StdClass and populate with $members
237  $result = new StdClass();
238  foreach ($members as $key => $value) {
239  if ($key === '') {
240  $key = '_empty_';
241  }
242  $result->$key = $value;
243  }
244  break;
246  default:
247  $result = $members;
248  break;
249  }
250 
251  $this->_getNextToken();
252  return $result;
253  }
254 
261  protected function _decodeArray()
262  {
263  $result = array();
264  $starttok = $tok = $this->_getNextToken(); // Move past the '['
265  $index = 0;
266 
267  while ($tok && $tok != self::RBRACKET) {
268  $result[$index++] = $this->_decodeValue();
269 
270  $tok = $this->_token;
271 
272  if ($tok == self::RBRACKET || !$tok) {
273  break;
274  }
275 
276  if ($tok != self::COMMA) {
277  #require_once 'Zend/Json/Exception.php';
278  throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source);
279  }
280 
281  $tok = $this->_getNextToken();
282  }
283 
284  $this->_getNextToken();
285  return($result);
286  }
287 
288 
292  protected function _eatWhitespace()
293  {
294  if (preg_match(
295  '/([\t\b\f\n\r ])*/s',
296  $this->_source,
297  $matches,
298  PREG_OFFSET_CAPTURE,
299  $this->_offset)
300  && $matches[0][1] == $this->_offset)
301  {
302  $this->_offset += strlen($matches[0][0]);
303  }
304  }
305 
306 
312  protected function _getNextToken()
313  {
314  $this->_token = self::EOF;
315  $this->_tokenValue = null;
316  $this->_eatWhitespace();
317 
318  if ($this->_offset >= $this->_sourceLength) {
319  return(self::EOF);
320  }
321 
322  $str = $this->_source;
323  $str_length = $this->_sourceLength;
324  $i = $this->_offset;
325  $start = $i;
326 
327  switch ($str{$i}) {
328  case '{':
329  $this->_token = self::LBRACE;
330  break;
331  case '}':
332  $this->_token = self::RBRACE;
333  break;
334  case '[':
335  $this->_token = self::LBRACKET;
336  break;
337  case ']':
338  $this->_token = self::RBRACKET;
339  break;
340  case ',':
341  $this->_token = self::COMMA;
342  break;
343  case ':':
344  $this->_token = self::COLON;
345  break;
346  case '"':
347  $result = '';
348  do {
349  $i++;
350  if ($i >= $str_length) {
351  break;
352  }
353 
354  $chr = $str{$i};
355 
356  if ($chr == '\\') {
357  $i++;
358  if ($i >= $str_length) {
359  break;
360  }
361  $chr = $str{$i};
362  switch ($chr) {
363  case '"' :
364  $result .= '"';
365  break;
366  case '\\':
367  $result .= '\\';
368  break;
369  case '/' :
370  $result .= '/';
371  break;
372  case 'b' :
373  $result .= "\x08";
374  break;
375  case 'f' :
376  $result .= "\x0c";
377  break;
378  case 'n' :
379  $result .= "\x0a";
380  break;
381  case 'r' :
382  $result .= "\x0d";
383  break;
384  case 't' :
385  $result .= "\x09";
386  break;
387  case '\'' :
388  $result .= '\'';
389  break;
390  default:
391  #require_once 'Zend/Json/Exception.php';
392  throw new Zend_Json_Exception("Illegal escape "
393  . "sequence '" . $chr . "'");
394  }
395  } elseif($chr == '"') {
396  break;
397  } else {
398  $result .= $chr;
399  }
400  } while ($i < $str_length);
401 
402  $this->_token = self::DATUM;
403  //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1);
404  $this->_tokenValue = $result;
405  break;
406  case 't':
407  if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") {
408  $this->_token = self::DATUM;
409  }
410  $this->_tokenValue = true;
411  $i += 3;
412  break;
413  case 'f':
414  if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") {
415  $this->_token = self::DATUM;
416  }
417  $this->_tokenValue = false;
418  $i += 4;
419  break;
420  case 'n':
421  if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") {
422  $this->_token = self::DATUM;
423  }
424  $this->_tokenValue = NULL;
425  $i += 3;
426  break;
427  }
428 
429  if ($this->_token != self::EOF) {
430  $this->_offset = $i + 1; // Consume the last token character
431  return($this->_token);
432  }
433 
434  $chr = $str{$i};
435  if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) {
436  if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s',
437  $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) {
438 
439  $datum = $matches[0][0];
440 
441  if (is_numeric($datum)) {
442  if (preg_match('/^0\d+$/', $datum)) {
443  #require_once 'Zend/Json/Exception.php';
444  throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)");
445  } else {
446  $val = intval($datum);
447  $fVal = floatval($datum);
448  $this->_tokenValue = ($val == $fVal ? $val : $fVal);
449  }
450  } else {
451  #require_once 'Zend/Json/Exception.php';
452  throw new Zend_Json_Exception("Illegal number format: $datum");
453  }
454 
455  $this->_token = self::DATUM;
456  $this->_offset = $start + strlen($datum);
457  }
458  } else {
459  #require_once 'Zend/Json/Exception.php';
460  throw new Zend_Json_Exception('Illegal Token');
461  }
462 
463  return($this->_token);
464  }
465 
477  public static function decodeUnicodeString($chrs)
478  {
479  $delim = substr($chrs, 0, 1);
480  $utf8 = '';
481  $strlen_chrs = strlen($chrs);
482 
483  for($i = 0; $i < $strlen_chrs; $i++) {
484 
485  $substr_chrs_c_2 = substr($chrs, $i, 2);
486  $ord_chrs_c = ord($chrs[$i]);
487 
488  switch (true) {
489  case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $i, 6)):
490  // single, escaped unicode character
491  $utf16 = chr(hexdec(substr($chrs, ($i + 2), 2)))
492  . chr(hexdec(substr($chrs, ($i + 4), 2)));
493  $utf8 .= self::_utf162utf8($utf16);
494  $i += 5;
495  break;
496  case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
497  $utf8 .= $chrs{$i};
498  break;
499  case ($ord_chrs_c & 0xE0) == 0xC0:
500  // characters U-00000080 - U-000007FF, mask 110XXXXX
501  //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
502  $utf8 .= substr($chrs, $i, 2);
503  ++$i;
504  break;
505  case ($ord_chrs_c & 0xF0) == 0xE0:
506  // characters U-00000800 - U-0000FFFF, mask 1110XXXX
507  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
508  $utf8 .= substr($chrs, $i, 3);
509  $i += 2;
510  break;
511  case ($ord_chrs_c & 0xF8) == 0xF0:
512  // characters U-00010000 - U-001FFFFF, mask 11110XXX
513  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
514  $utf8 .= substr($chrs, $i, 4);
515  $i += 3;
516  break;
517  case ($ord_chrs_c & 0xFC) == 0xF8:
518  // characters U-00200000 - U-03FFFFFF, mask 111110XX
519  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
520  $utf8 .= substr($chrs, $i, 5);
521  $i += 4;
522  break;
523  case ($ord_chrs_c & 0xFE) == 0xFC:
524  // characters U-04000000 - U-7FFFFFFF, mask 1111110X
525  // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
526  $utf8 .= substr($chrs, $i, 6);
527  $i += 5;
528  break;
529  }
530  }
531 
532  return $utf8;
533  }
534 
548  protected static function _utf162utf8($utf16)
549  {
550  // Check for mb extension otherwise do by hand.
551  if( function_exists('mb_convert_encoding') ) {
552  return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
553  }
554 
555  $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
556 
557  switch (true) {
558  case ((0x7F & $bytes) == $bytes):
559  // this case should never be reached, because we are in ASCII range
560  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
561  return chr(0x7F & $bytes);
562 
563  case (0x07FF & $bytes) == $bytes:
564  // return a 2-byte UTF-8 character
565  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
566  return chr(0xC0 | (($bytes >> 6) & 0x1F))
567  . chr(0x80 | ($bytes & 0x3F));
568 
569  case (0xFFFF & $bytes) == $bytes:
570  // return a 3-byte UTF-8 character
571  // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
572  return chr(0xE0 | (($bytes >> 12) & 0x0F))
573  . chr(0x80 | (($bytes >> 6) & 0x3F))
574  . chr(0x80 | ($bytes & 0x3F));
575  }
576 
577  // ignoring UTF-32 for now, sorry
578  return '';
579  }
580 }
581 
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$source
Definition: source.php:23
__construct($source, $decodeType)
Definition: Decoder.php:97
$start
Definition: listing.phtml:18
$value
Definition: gender.phtml:16
const TYPE_ARRAY
Definition: Json.php:48
static _utf162utf8($utf16)
Definition: Decoder.php:548
const TYPE_OBJECT
Definition: Json.php:49
static decodeUnicodeString($chrs)
Definition: Decoder.php:477
$i
Definition: gallery.phtml:31
$index
Definition: list.phtml:44
static decode($source=null, $objectDecodeType=Zend_Json::TYPE_ARRAY)
Definition: Decoder.php:144