Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Inline.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 37.78 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\Yaml;
013   
014  use Symfony\Component\Yaml\Exception\DumpException;
015  use Symfony\Component\Yaml\Exception\ParseException;
016  use Symfony\Component\Yaml\Tag\TaggedValue;
017   
018  /**
019   * Inline implements a YAML parser/dumper for the YAML inline syntax.
020   *
021   * @author Fabien Potencier <fabien@symfony.com>
022   *
023   * @internal
024   */
025  class Inline
026  {
027      const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
028   
029      public static $parsedLineNumber = -1;
030      public static $parsedFilename;
031   
032      private static $exceptionOnInvalidType = false;
033      private static $objectSupport = false;
034      private static $objectForMap = false;
035      private static $constantSupport = false;
036   
037      /**
038       * @param int         $flags
039       * @param int|null    $parsedLineNumber
040       * @param string|null $parsedFilename
041       */
042      public static function initialize($flags, $parsedLineNumber = null, $parsedFilename = null)
043      {
044          self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
045          self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
046          self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
047          self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
048          self::$parsedFilename = $parsedFilename;
049   
050          if (null !== $parsedLineNumber) {
051              self::$parsedLineNumber = $parsedLineNumber;
052          }
053      }
054   
055      /**
056       * Converts a YAML string to a PHP value.
057       *
058       * @param string $value      A YAML string
059       * @param int    $flags      A bit field of PARSE_* constants to customize the YAML parser behavior
060       * @param array  $references Mapping of variable names to values
061       *
062       * @return mixed A PHP value
063       *
064       * @throws ParseException
065       */
066      public static function parse($value, $flags = 0, $references = [])
067      {
068          if (\is_bool($flags)) {
069              @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', \E_USER_DEPRECATED);
070   
071              if ($flags) {
072                  $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
073              } else {
074                  $flags = 0;
075              }
076          }
077   
078          if (\func_num_args() >= 3 && !\is_array($references)) {
079              @trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', \E_USER_DEPRECATED);
080   
081              if ($references) {
082                  $flags |= Yaml::PARSE_OBJECT;
083              }
084   
085              if (\func_num_args() >= 4) {
086                  @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', \E_USER_DEPRECATED);
087   
088                  if (func_get_arg(3)) {
089                      $flags |= Yaml::PARSE_OBJECT_FOR_MAP;
090                  }
091              }
092   
093              if (\func_num_args() >= 5) {
094                  $references = func_get_arg(4);
095              } else {
096                  $references = [];
097              }
098          }
099   
100          self::initialize($flags);
101   
102          $value = trim($value);
103   
104          if ('' === $value) {
105              return '';
106          }
107   
108          if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
109              $mbEncoding = mb_internal_encoding();
110              mb_internal_encoding('ASCII');
111          }
112   
113          try {
114              $i = 0;
115              $tag = self::parseTag($value, $i, $flags);
116              switch ($value[$i]) {
117                  case '[':
118                      $result = self::parseSequence($value, $flags, $i, $references);
119                      ++$i;
120                      break;
121                  case '{':
122                      $result = self::parseMapping($value, $flags, $i, $references);
123                      ++$i;
124                      break;
125                  default:
126                      $result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
127              }
128   
129              // some comments are allowed at the end
130              if (preg_replace('/\s*#.*$/A', '', substr($value, $i))) {
131                  throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
132              }
133   
134              if (null !== $tag) {
135                  return new TaggedValue($tag, $result);
136              }
137   
138              return $result;
139          } finally {
140              if (isset($mbEncoding)) {
141                  mb_internal_encoding($mbEncoding);
142              }
143          }
144      }
145   
146      /**
147       * Dumps a given PHP variable to a YAML string.
148       *
149       * @param mixed $value The PHP variable to convert
150       * @param int   $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
151       *
152       * @return string The YAML string representing the PHP value
153       *
154       * @throws DumpException When trying to dump PHP resource
155       */
156      public static function dump($value, $flags = 0)
157      {
158          if (\is_bool($flags)) {
159              @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', \E_USER_DEPRECATED);
160   
161              if ($flags) {
162                  $flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE;
163              } else {
164                  $flags = 0;
165              }
166          }
167   
168          if (\func_num_args() >= 3) {
169              @trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', \E_USER_DEPRECATED);
170   
171              if (func_get_arg(2)) {
172                  $flags |= Yaml::DUMP_OBJECT;
173              }
174          }
175   
176          switch (true) {
177              case \is_resource($value):
178                  if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
179                      throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
180                  }
181   
182                  return 'null';
183              case $value instanceof \DateTimeInterface:
184                  return $value->format('c');
185              case \is_object($value):
186                  if ($value instanceof TaggedValue) {
187                      return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
188                  }
189   
190                  if (Yaml::DUMP_OBJECT & $flags) {
191                      return '!php/object '.self::dump(serialize($value));
192                  }
193   
194                  if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
195                      return self::dumpArray($value, $flags & ~Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
196                  }
197   
198                  if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
199                      throw new DumpException('Object support when dumping a YAML file has been disabled.');
200                  }
201   
202                  return 'null';
203              case \is_array($value):
204                  return self::dumpArray($value, $flags);
205              case null === $value:
206                  return 'null';
207              case true === $value:
208                  return 'true';
209              case false === $value:
210                  return 'false';
211              case ctype_digit($value):
212                  return \is_string($value) ? "'$value'" : (int) $value;
213              case is_numeric($value) && false === strpos($value, "\f") && false === strpos($value, "\n") && false === strpos($value, "\r") && false === strpos($value, "\t") && false === strpos($value, "\v"):
214                  $locale = setlocale(\LC_NUMERIC, 0);
215                  if (false !== $locale) {
216                      setlocale(\LC_NUMERIC, 'C');
217                  }
218                  if (\is_float($value)) {
219                      $repr = (string) $value;
220                      if (is_infinite($value)) {
221                          $repr = str_ireplace('INF', '.Inf', $repr);
222                      } elseif (floor($value) == $value && $repr == $value) {
223                          // Preserve float data type since storing a whole number will result in integer value.
224                          $repr = '!!float '.$repr;
225                      }
226                  } else {
227                      $repr = \is_string($value) ? "'$value'" : (string) $value;
228                  }
229                  if (false !== $locale) {
230                      setlocale(\LC_NUMERIC, $locale);
231                  }
232   
233                  return $repr;
234              case '' == $value:
235                  return "''";
236              case self::isBinaryString($value):
237                  return '!!binary '.base64_encode($value);
238              case Escaper::requiresDoubleQuoting($value):
239                  return Escaper::escapeWithDoubleQuotes($value);
240              case Escaper::requiresSingleQuoting($value):
241              case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
242              case Parser::preg_match(self::getHexRegex(), $value):
243              case Parser::preg_match(self::getTimestampRegex(), $value):
244                  return Escaper::escapeWithSingleQuotes($value);
245              default:
246                  return $value;
247          }
248      }
249   
250      /**
251       * Check if given array is hash or just normal indexed array.
252       *
253       * @internal
254       *
255       * @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
256       *
257       * @return bool true if value is hash array, false otherwise
258       */
259      public static function isHash($value)
260      {
261          if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
262              return true;
263          }
264   
265          $expectedKey = 0;
266   
267          foreach ($value as $key => $val) {
268              if ($key !== $expectedKey++) {
269                  return true;
270              }
271          }
272   
273          return false;
274      }
275   
276      /**
277       * Dumps a PHP array to a YAML string.
278       *
279       * @param array $value The PHP array to dump
280       * @param int   $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
281       *
282       * @return string The YAML string representing the PHP array
283       */
284      private static function dumpArray($value, $flags)
285      {
286          // array
287          if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
288              $output = [];
289              foreach ($value as $val) {
290                  $output[] = self::dump($val, $flags);
291              }
292   
293              return sprintf('[%s]', implode(', ', $output));
294          }
295   
296          // hash
297          $output = [];
298          foreach ($value as $key => $val) {
299              $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
300          }
301   
302          return sprintf('{ %s }', implode(', ', $output));
303      }
304   
305      /**
306       * Parses a YAML scalar.
307       *
308       * @param string   $scalar
309       * @param int      $flags
310       * @param string[] $delimiters
311       * @param int      &$i
312       * @param bool     $evaluate
313       * @param array    $references
314       *
315       * @return string
316       *
317       * @throws ParseException When malformed inline YAML string is parsed
318       *
319       * @internal
320       */
321      public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i = 0, $evaluate = true, $references = [], $legacyOmittedKeySupport = false)
322      {
323          if (\in_array($scalar[$i], ['"', "'"])) {
324              // quoted scalar
325              $output = self::parseQuotedScalar($scalar, $i);
326   
327              if (null !== $delimiters) {
328                  $tmp = ltrim(substr($scalar, $i), ' ');
329                  if ('' === $tmp) {
330                      throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
331                  }
332                  if (!\in_array($tmp[0], $delimiters)) {
333                      throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
334                  }
335              }
336          } else {
337              // "normal" string
338              if (!$delimiters) {
339                  $output = substr($scalar, $i);
340                  $i += \strlen($output);
341   
342                  // remove comments
343                  if (Parser::preg_match('/[ \t]+#/', $output, $match, \PREG_OFFSET_CAPTURE)) {
344                      $output = substr($output, 0, $match[0][1]);
345                  }
346              } elseif (Parser::preg_match('/^(.'.($legacyOmittedKeySupport ? '+' : '*').'?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
347                  $output = $match[1];
348                  $i += \strlen($output);
349              } else {
350                  throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
351              }
352   
353              // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
354              if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
355                  throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber + 1, $output, self::$parsedFilename);
356              }
357   
358              if ($output && '%' === $output[0]) {
359                  @trigger_error(self::getDeprecationMessage(sprintf('Not quoting the scalar "%s" starting with the "%%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.', $output)), \E_USER_DEPRECATED);
360              }
361   
362              if ($evaluate) {
363                  $output = self::evaluateScalar($output, $flags, $references);
364              }
365          }
366   
367          return $output;
368      }
369   
370      /**
371       * Parses a YAML quoted scalar.
372       *
373       * @param string $scalar
374       * @param int    &$i
375       *
376       * @return string
377       *
378       * @throws ParseException When malformed inline YAML string is parsed
379       */
380      private static function parseQuotedScalar($scalar, &$i)
381      {
382          if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
383              throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
384          }
385   
386          $output = substr($match[0], 1, \strlen($match[0]) - 2);
387   
388          $unescaper = new Unescaper();
389          if ('"' == $scalar[$i]) {
390              $output = $unescaper->unescapeDoubleQuotedString($output);
391          } else {
392              $output = $unescaper->unescapeSingleQuotedString($output);
393          }
394   
395          $i += \strlen($match[0]);
396   
397          return $output;
398      }
399   
400      /**
401       * Parses a YAML sequence.
402       *
403       * @param string $sequence
404       * @param int    $flags
405       * @param int    &$i
406       * @param array  $references
407       *
408       * @return array
409       *
410       * @throws ParseException When malformed inline YAML string is parsed
411       */
412      private static function parseSequence($sequence, $flags, &$i = 0, $references = [])
413      {
414          $output = [];
415          $len = \strlen($sequence);
416          ++$i;
417   
418          // [foo, bar, ...]
419          while ($i < $len) {
420              if (']' === $sequence[$i]) {
421                  return $output;
422              }
423              if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
424                  ++$i;
425   
426                  continue;
427              }
428   
429              $tag = self::parseTag($sequence, $i, $flags);
430              switch ($sequence[$i]) {
431                  case '[':
432                      // nested sequence
433                      $value = self::parseSequence($sequence, $flags, $i, $references);
434                      break;
435                  case '{':
436                      // nested mapping
437                      $value = self::parseMapping($sequence, $flags, $i, $references);
438                      break;
439                  default:
440                      $isQuoted = \in_array($sequence[$i], ['"', "'"]);
441                      $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references);
442   
443                      // the value can be an array if a reference has been resolved to an array var
444                      if (\is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {
445                          // embedded mapping?
446                          try {
447                              $pos = 0;
448                              $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
449                          } catch (\InvalidArgumentException $e) {
450                              // no, it's not
451                          }
452                      }
453   
454                      --$i;
455              }
456   
457              if (null !== $tag) {
458                  $value = new TaggedValue($tag, $value);
459              }
460   
461              $output[] = $value;
462   
463              ++$i;
464          }
465   
466          throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename);
467      }
468   
469      /**
470       * Parses a YAML mapping.
471       *
472       * @param string $mapping
473       * @param int    $flags
474       * @param int    &$i
475       * @param array  $references
476       *
477       * @return array|\stdClass
478       *
479       * @throws ParseException When malformed inline YAML string is parsed
480       */
481      private static function parseMapping($mapping, $flags, &$i = 0, $references = [])
482      {
483          $output = [];
484          $len = \strlen($mapping);
485          ++$i;
486          $allowOverwrite = false;
487   
488          // {foo: bar, bar:foo, ...}
489          while ($i < $len) {
490              switch ($mapping[$i]) {
491                  case ' ':
492                  case ',':
493                      ++$i;
494                      continue 2;
495                  case '}':
496                      if (self::$objectForMap) {
497                          return (object) $output;
498                      }
499   
500                      return $output;
501              }
502   
503              // key
504              $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
505              $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true);
506   
507              if ('!php/const' === $key) {
508                  $key .= self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true);
509                  if ('!php/const:' === $key && ':' !== $mapping[$i]) {
510                      $key = '';
511                      --$i;
512                  } else {
513                      $key = self::evaluateScalar($key, $flags);
514                  }
515              }
516   
517              if (':' !== $key && false === $i = strpos($mapping, ':', $i)) {
518                  break;
519              }
520   
521              if (':' === $key) {
522                  @trigger_error(self::getDeprecationMessage('Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0.'), \E_USER_DEPRECATED);
523              }
524   
525              if (!$isKeyQuoted) {
526                  $evaluatedKey = self::evaluateScalar($key, $flags, $references);
527   
528                  if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
529                      @trigger_error(self::getDeprecationMessage('Implicit casting of incompatible mapping keys to strings is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.'), \E_USER_DEPRECATED);
530                  }
531              }
532   
533              if (':' !== $key && !$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}'], true))) {
534                  @trigger_error(self::getDeprecationMessage('Using a colon after an unquoted mapping key that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}") is deprecated since Symfony 3.2 and will throw a ParseException in 4.0.'), \E_USER_DEPRECATED);
535              }
536   
537              if ('<<' === $key) {
538                  $allowOverwrite = true;
539              }
540   
541              while ($i < $len) {
542                  if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
543                      ++$i;
544   
545                      continue;
546                  }
547   
548                  $tag = self::parseTag($mapping, $i, $flags);
549                  switch ($mapping[$i]) {
550                      case '[':
551                          // nested sequence
552                          $value = self::parseSequence($mapping, $flags, $i, $references);
553                          // Spec: Keys MUST be unique; first one wins.
554                          // Parser cannot abort this mapping earlier, since lines
555                          // are processed sequentially.
556                          // But overwriting is allowed when a merge node is used in current block.
557                          if ('<<' === $key) {
558                              foreach ($value as $parsedValue) {
559                                  $output += $parsedValue;
560                              }
561                          } elseif ($allowOverwrite || !isset($output[$key])) {
562                              if (null !== $tag) {
563                                  $output[$key] = new TaggedValue($tag, $value);
564                              } else {
565                                  $output[$key] = $value;
566                              }
567                          } elseif (isset($output[$key])) {
568                              @trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), \E_USER_DEPRECATED);
569                          }
570                          break;
571                      case '{':
572                          // nested mapping
573                          $value = self::parseMapping($mapping, $flags, $i, $references);
574                          // Spec: Keys MUST be unique; first one wins.
575                          // Parser cannot abort this mapping earlier, since lines
576                          // are processed sequentially.
577                          // But overwriting is allowed when a merge node is used in current block.
578                          if ('<<' === $key) {
579                              $output += $value;
580                          } elseif ($allowOverwrite || !isset($output[$key])) {
581                              if (null !== $tag) {
582                                  $output[$key] = new TaggedValue($tag, $value);
583                              } else {
584                                  $output[$key] = $value;
585                              }
586                          } elseif (isset($output[$key])) {
587                              @trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), \E_USER_DEPRECATED);
588                          }
589                          break;
590                      default:
591                          $value = self::parseScalar($mapping, $flags, [',', '}'], $i, null === $tag, $references);
592                          // Spec: Keys MUST be unique; first one wins.
593                          // Parser cannot abort this mapping earlier, since lines
594                          // are processed sequentially.
595                          // But overwriting is allowed when a merge node is used in current block.
596                          if ('<<' === $key) {
597                              $output += $value;
598                          } elseif ($allowOverwrite || !isset($output[$key])) {
599                              if (null !== $tag) {
600                                  $output[$key] = new TaggedValue($tag, $value);
601                              } else {
602                                  $output[$key] = $value;
603                              }
604                          } elseif (isset($output[$key])) {
605                              @trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), \E_USER_DEPRECATED);
606                          }
607                          --$i;
608                  }
609                  ++$i;
610   
611                  continue 2;
612              }
613          }
614   
615          throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
616      }
617   
618      /**
619       * Evaluates scalars and replaces magic values.
620       *
621       * @param string $scalar
622       * @param int    $flags
623       * @param array  $references
624       *
625       * @return mixed The evaluated YAML string
626       *
627       * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
628       */
629      private static function evaluateScalar($scalar, $flags, $references = [])
630      {
631          $scalar = trim($scalar);
632          $scalarLower = strtolower($scalar);
633   
634          if (0 === strpos($scalar, '*')) {
635              if (false !== $pos = strpos($scalar, '#')) {
636                  $value = substr($scalar, 1, $pos - 2);
637              } else {
638                  $value = substr($scalar, 1);
639              }
640   
641              // an unquoted *
642              if (false === $value || '' === $value) {
643                  throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
644              }
645   
646              if (!\array_key_exists($value, $references)) {
647                  throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
648              }
649   
650              return $references[$value];
651          }
652   
653          switch (true) {
654              case 'null' === $scalarLower:
655              case '' === $scalar:
656              case '~' === $scalar:
657                  return null;
658              case 'true' === $scalarLower:
659                  return true;
660              case 'false' === $scalarLower:
661                  return false;
662              case '!' === $scalar[0]:
663                  switch (true) {
664                      case 0 === strpos($scalar, '!str'):
665                          @trigger_error(self::getDeprecationMessage('Support for the !str tag is deprecated since Symfony 3.4. Use the !!str tag instead.'), \E_USER_DEPRECATED);
666   
667                          return (string) substr($scalar, 5);
668                      case 0 === strpos($scalar, '!!str '):
669                          return (string) substr($scalar, 6);
670                      case 0 === strpos($scalar, '! '):
671                          @trigger_error(self::getDeprecationMessage('Using the non-specific tag "!" is deprecated since Symfony 3.4 as its behavior will change in 4.0. It will force non-evaluating your values in 4.0. Use plain integers or !!float instead.'), \E_USER_DEPRECATED);
672   
673                          return (int) self::parseScalar(substr($scalar, 2), $flags);
674                      case 0 === strpos($scalar, '!php/object:'):
675                          if (self::$objectSupport) {
676                              @trigger_error(self::getDeprecationMessage('The !php/object: tag to indicate dumped PHP objects is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.'), \E_USER_DEPRECATED);
677   
678                              return unserialize(substr($scalar, 12));
679                          }
680   
681                          if (self::$exceptionOnInvalidType) {
682                              throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
683                          }
684   
685                          return null;
686                      case 0 === strpos($scalar, '!!php/object:'):
687                          if (self::$objectSupport) {
688                              @trigger_error(self::getDeprecationMessage('The !!php/object: tag to indicate dumped PHP objects is deprecated since Symfony 3.1 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.'), \E_USER_DEPRECATED);
689   
690                              return unserialize(substr($scalar, 13));
691                          }
692   
693                          if (self::$exceptionOnInvalidType) {
694                              throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
695                          }
696   
697                          return null;
698                      case 0 === strpos($scalar, '!php/object'):
699                          if (self::$objectSupport) {
700                              if (!isset($scalar[12])) {
701                                  return false;
702                              }
703   
704                              return unserialize(self::parseScalar(substr($scalar, 12)));
705                          }
706   
707                          if (self::$exceptionOnInvalidType) {
708                              throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
709                          }
710   
711                          return null;
712                      case 0 === strpos($scalar, '!php/const:'):
713                          if (self::$constantSupport) {
714                              @trigger_error(self::getDeprecationMessage('The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead.'), \E_USER_DEPRECATED);
715   
716                              if (\defined($const = substr($scalar, 11))) {
717                                  return \constant($const);
718                              }
719   
720                              throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
721                          }
722                          if (self::$exceptionOnInvalidType) {
723                              throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
724                          }
725   
726                          return null;
727                      case 0 === strpos($scalar, '!php/const'):
728                          if (self::$constantSupport) {
729                              if (!isset($scalar[11])) {
730                                  return '';
731                              }
732   
733                              $i = 0;
734                              if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, false))) {
735                                  return \constant($const);
736                              }
737   
738                              throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
739                          }
740                          if (self::$exceptionOnInvalidType) {
741                              throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
742                          }
743   
744                          return null;
745                      case 0 === strpos($scalar, '!!float '):
746                          return (float) substr($scalar, 8);
747                      case 0 === strpos($scalar, '!!binary '):
748                          return self::evaluateBinaryScalar(substr($scalar, 9));
749                      default:
750                          @trigger_error(self::getDeprecationMessage(sprintf('Using the unquoted scalar value "%s" is deprecated since Symfony 3.3 and will be considered as a tagged value in 4.0. You must quote it.', $scalar)), \E_USER_DEPRECATED);
751                  }
752   
753              // Optimize for returning strings.
754              // no break
755              case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]):
756                  if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
757                      $scalar = str_replace('_', '', (string) $scalar);
758                  }
759   
760                  switch (true) {
761                      case ctype_digit($scalar):
762                          if (preg_match('/^0[0-7]+$/', $scalar)) {
763                              return octdec($scalar);
764                          }
765   
766                          $cast = (int) $scalar;
767   
768                          return ($scalar === (string) $cast) ? $cast : $scalar;
769                      case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
770                          if (preg_match('/^-0[0-7]+$/', $scalar)) {
771                              return -octdec(substr($scalar, 1));
772                          }
773   
774                          $cast = (int) $scalar;
775   
776                          return ($scalar === (string) $cast) ? $cast : $scalar;
777                      case is_numeric($scalar):
778                      case Parser::preg_match(self::getHexRegex(), $scalar):
779                          $scalar = str_replace('_', '', $scalar);
780   
781                          return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
782                      case '.inf' === $scalarLower:
783                      case '.nan' === $scalarLower:
784                          return -log(0);
785                      case '-.inf' === $scalarLower:
786                          return log(0);
787                      case Parser::preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar):
788                      case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
789                          if (false !== strpos($scalar, ',')) {
790                              @trigger_error(self::getDeprecationMessage('Using the comma as a group separator for floats is deprecated since Symfony 3.2 and will be removed in 4.0.'), \E_USER_DEPRECATED);
791                          }
792   
793                          return (float) str_replace([',', '_'], '', $scalar);
794                      case Parser::preg_match(self::getTimestampRegex(), $scalar):
795                          if (Yaml::PARSE_DATETIME & $flags) {
796                              // When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
797                              return new \DateTime($scalar, new \DateTimeZone('UTC'));
798                          }
799   
800                          $timeZone = date_default_timezone_get();
801                          date_default_timezone_set('UTC');
802                          $time = strtotime($scalar);
803                          date_default_timezone_set($timeZone);
804   
805                          return $time;
806                  }
807          }
808   
809          return (string) $scalar;
810      }
811   
812      /**
813       * @param string $value
814       * @param int    &$i
815       * @param int    $flags
816       *
817       * @return string|null
818       */
819      private static function parseTag($value, &$i, $flags)
820      {
821          if ('!' !== $value[$i]) {
822              return null;
823          }
824   
825          $tagLength = strcspn($value, " \t\n", $i + 1);
826          $tag = substr($value, $i + 1, $tagLength);
827   
828          $nextOffset = $i + $tagLength + 1;
829          $nextOffset += strspn($value, ' ', $nextOffset);
830   
831          // Is followed by a scalar
832          if ((!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && 'tagged' !== $tag) {
833              // Manage non-whitelisted scalars in {@link self::evaluateScalar()}
834              return null;
835          }
836   
837          // Built-in tags
838          if ($tag && '!' === $tag[0]) {
839              throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
840          }
841   
842          if (Yaml::PARSE_CUSTOM_TAGS & $flags) {
843              $i = $nextOffset;
844   
845              return $tag;
846          }
847   
848          throw new ParseException(sprintf('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
849      }
850   
851      /**
852       * @param string $scalar
853       *
854       * @return string
855       *
856       * @internal
857       */
858      public static function evaluateBinaryScalar($scalar)
859      {
860          $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
861   
862          if (0 !== (\strlen($parsedBinaryData) % 4)) {
863              throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', \strlen($parsedBinaryData)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
864          }
865   
866          if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
867              throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
868          }
869   
870          return base64_decode($parsedBinaryData, true);
871      }
872   
873      private static function isBinaryString($value)
874      {
875          return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
876      }
877   
878      /**
879       * Gets a regex that matches a YAML date.
880       *
881       * @return string The regular expression
882       *
883       * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
884       */
885      private static function getTimestampRegex()
886      {
887          return <<<EOF
888          ~^
889          (?P<year>[0-9][0-9][0-9][0-9])
890          -(?P<month>[0-9][0-9]?)
891          -(?P<day>[0-9][0-9]?)
892          (?:(?:[Tt]|[ \t]+)
893          (?P<hour>[0-9][0-9]?)
894          :(?P<minute>[0-9][0-9])
895          :(?P<second>[0-9][0-9])
896          (?:\.(?P<fraction>[0-9]*))?
897          (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
898          (?::(?P<tz_minute>[0-9][0-9]))?))?)?
899          $~x
900  EOF;
901   
902      }
903   
904      /**
905       * Gets a regex that matches a YAML number in hexadecimal notation.
906       *
907       * @return string
908       */
909      private static function getHexRegex()
910      {
911          return '~^0x[0-9a-f_]++$~i';
912      }
913   
914      private static function getDeprecationMessage($message)
915      {
916          $message = rtrim($message, '.');
917   
918          if (null !== self::$parsedFilename) {
919              $message .= ' in '.self::$parsedFilename;
920          }
921   
922          if (-1 !== self::$parsedLineNumber) {
923              $message .= ' on line '.(self::$parsedLineNumber + 1);
924          }
925   
926          return $message.'.';
927      }
928  }
929