[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/vendor/symfony/yaml/ -> Inline.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\Yaml;
  13  
  14  use Symfony\Component\Yaml\Exception\DumpException;
  15  use Symfony\Component\Yaml\Exception\ParseException;
  16  
  17  /**
  18   * Inline implements a YAML parser/dumper for the YAML inline syntax.
  19   *
  20   * @author Fabien Potencier <fabien@symfony.com>
  21   */
  22  class Inline
  23  {
  24      const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
  25  
  26      private static $exceptionOnInvalidType = false;
  27      private static $objectSupport = false;
  28      private static $objectForMap = false;
  29  
  30      /**
  31       * Converts a YAML string to a PHP value.
  32       *
  33       * @param string $value                  A YAML string
  34       * @param bool   $exceptionOnInvalidType True if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
  35       * @param bool   $objectSupport          True if object support is enabled, false otherwise
  36       * @param bool   $objectForMap           True if maps should return a stdClass instead of array()
  37       * @param array  $references             Mapping of variable names to values
  38       *
  39       * @return mixed A PHP value
  40       *
  41       * @throws ParseException
  42       */
  43      public static function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false, $references = array())
  44      {
  45          self::$exceptionOnInvalidType = $exceptionOnInvalidType;
  46          self::$objectSupport = $objectSupport;
  47          self::$objectForMap = $objectForMap;
  48  
  49          $value = trim($value);
  50  
  51          if ('' === $value) {
  52              return '';
  53          }
  54  
  55          if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
  56              $mbEncoding = mb_internal_encoding();
  57              mb_internal_encoding('ASCII');
  58          }
  59  
  60          $i = 0;
  61          switch ($value[0]) {
  62              case '[':
  63                  $result = self::parseSequence($value, $i, $references);
  64                  ++$i;
  65                  break;
  66              case '{':
  67                  $result = self::parseMapping($value, $i, $references);
  68                  ++$i;
  69                  break;
  70              default:
  71                  $result = self::parseScalar($value, null, array('"', "'"), $i, true, $references);
  72          }
  73  
  74          // some comments are allowed at the end
  75          if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
  76              throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)));
  77          }
  78  
  79          if (isset($mbEncoding)) {
  80              mb_internal_encoding($mbEncoding);
  81          }
  82  
  83          return $result;
  84      }
  85  
  86      /**
  87       * Dumps a given PHP variable to a YAML string.
  88       *
  89       * @param mixed $value                  The PHP variable to convert
  90       * @param bool  $exceptionOnInvalidType True if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
  91       * @param bool  $objectSupport          True if object support is enabled, false otherwise
  92       *
  93       * @return string The YAML string representing the PHP value
  94       *
  95       * @throws DumpException When trying to dump PHP resource
  96       */
  97      public static function dump($value, $exceptionOnInvalidType = false, $objectSupport = false)
  98      {
  99          switch (true) {
 100              case \is_resource($value):
 101                  if ($exceptionOnInvalidType) {
 102                      throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
 103                  }
 104  
 105                  return 'null';
 106              case \is_object($value):
 107                  if ($objectSupport) {
 108                      return '!php/object:'.serialize($value);
 109                  }
 110  
 111                  if ($exceptionOnInvalidType) {
 112                      throw new DumpException('Object support when dumping a YAML file has been disabled.');
 113                  }
 114  
 115                  return 'null';
 116              case \is_array($value):
 117                  return self::dumpArray($value, $exceptionOnInvalidType, $objectSupport);
 118              case null === $value:
 119                  return 'null';
 120              case true === $value:
 121                  return 'true';
 122              case false === $value:
 123                  return 'false';
 124              case ctype_digit($value):
 125                  return \is_string($value) ? "'$value'" : (int) $value;
 126              case is_numeric($value):
 127                  $locale = setlocale(LC_NUMERIC, 0);
 128                  if (false !== $locale) {
 129                      setlocale(LC_NUMERIC, 'C');
 130                  }
 131                  if (\is_float($value)) {
 132                      $repr = (string) $value;
 133                      if (is_infinite($value)) {
 134                          $repr = str_ireplace('INF', '.Inf', $repr);
 135                      } elseif (floor($value) == $value && $repr == $value) {
 136                          // Preserve float data type since storing a whole number will result in integer value.
 137                          $repr = '!!float '.$repr;
 138                      }
 139                  } else {
 140                      $repr = \is_string($value) ? "'$value'" : (string) $value;
 141                  }
 142                  if (false !== $locale) {
 143                      setlocale(LC_NUMERIC, $locale);
 144                  }
 145  
 146                  return $repr;
 147              case '' == $value:
 148                  return "''";
 149              case Escaper::requiresDoubleQuoting($value):
 150                  return Escaper::escapeWithDoubleQuotes($value);
 151              case Escaper::requiresSingleQuoting($value):
 152              case Parser::preg_match(self::getHexRegex(), $value):
 153              case Parser::preg_match(self::getTimestampRegex(), $value):
 154                  return Escaper::escapeWithSingleQuotes($value);
 155              default:
 156                  return $value;
 157          }
 158      }
 159  
 160      /**
 161       * Check if given array is hash or just normal indexed array.
 162       *
 163       * @internal
 164       *
 165       * @param array $value The PHP array to check
 166       *
 167       * @return bool true if value is hash array, false otherwise
 168       */
 169      public static function isHash(array $value)
 170      {
 171          $expectedKey = 0;
 172  
 173          foreach ($value as $key => $val) {
 174              if ($key !== $expectedKey++) {
 175                  return true;
 176              }
 177          }
 178  
 179          return false;
 180      }
 181  
 182      /**
 183       * Dumps a PHP array to a YAML string.
 184       *
 185       * @param array $value                  The PHP array to dump
 186       * @param bool  $exceptionOnInvalidType True if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
 187       * @param bool  $objectSupport          True if object support is enabled, false otherwise
 188       *
 189       * @return string The YAML string representing the PHP array
 190       */
 191      private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
 192      {
 193          // array
 194          if ($value && !self::isHash($value)) {
 195              $output = array();
 196              foreach ($value as $val) {
 197                  $output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
 198              }
 199  
 200              return sprintf('[%s]', implode(', ', $output));
 201          }
 202  
 203          // hash
 204          $output = array();
 205          foreach ($value as $key => $val) {
 206              $output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
 207          }
 208  
 209          return sprintf('{ %s }', implode(', ', $output));
 210      }
 211  
 212      /**
 213       * Parses a YAML scalar.
 214       *
 215       * @param string   $scalar
 216       * @param string[] $delimiters
 217       * @param string[] $stringDelimiters
 218       * @param int      &$i
 219       * @param bool     $evaluate
 220       * @param array    $references
 221       *
 222       * @return string
 223       *
 224       * @throws ParseException When malformed inline YAML string is parsed
 225       *
 226       * @internal
 227       */
 228      public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
 229      {
 230          if (\in_array($scalar[$i], $stringDelimiters)) {
 231              // quoted scalar
 232              $output = self::parseQuotedScalar($scalar, $i);
 233  
 234              if (null !== $delimiters) {
 235                  $tmp = ltrim(substr($scalar, $i), ' ');
 236                  if ('' === $tmp) {
 237                      throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)));
 238                  }
 239                  if (!\in_array($tmp[0], $delimiters)) {
 240                      throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
 241                  }
 242              }
 243          } else {
 244              // "normal" string
 245              if (!$delimiters) {
 246                  $output = substr($scalar, $i);
 247                  $i += \strlen($output);
 248  
 249                  // remove comments
 250                  if (Parser::preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) {
 251                      $output = substr($output, 0, $match[0][1]);
 252                  }
 253              } elseif (Parser::preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
 254                  $output = $match[1];
 255                  $i += \strlen($output);
 256              } else {
 257                  throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar));
 258              }
 259  
 260              // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
 261              if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
 262                  @trigger_error(sprintf('Not quoting the scalar "%s" starting with "%s" is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $output, $output[0]), E_USER_DEPRECATED);
 263  
 264                  // to be thrown in 3.0
 265                  // throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]));
 266              }
 267  
 268              if ($evaluate) {
 269                  $output = self::evaluateScalar($output, $references);
 270              }
 271          }
 272  
 273          return $output;
 274      }
 275  
 276      /**
 277       * Parses a YAML quoted scalar.
 278       *
 279       * @param string $scalar
 280       * @param int    &$i
 281       *
 282       * @return string
 283       *
 284       * @throws ParseException When malformed inline YAML string is parsed
 285       */
 286      private static function parseQuotedScalar($scalar, &$i)
 287      {
 288          if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
 289              throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i)));
 290          }
 291  
 292          $output = substr($match[0], 1, \strlen($match[0]) - 2);
 293  
 294          $unescaper = new Unescaper();
 295          if ('"' == $scalar[$i]) {
 296              $output = $unescaper->unescapeDoubleQuotedString($output);
 297          } else {
 298              $output = $unescaper->unescapeSingleQuotedString($output);
 299          }
 300  
 301          $i += \strlen($match[0]);
 302  
 303          return $output;
 304      }
 305  
 306      /**
 307       * Parses a YAML sequence.
 308       *
 309       * @param string $sequence
 310       * @param int    &$i
 311       * @param array  $references
 312       *
 313       * @return array
 314       *
 315       * @throws ParseException When malformed inline YAML string is parsed
 316       */
 317      private static function parseSequence($sequence, &$i = 0, $references = array())
 318      {
 319          $output = array();
 320          $len = \strlen($sequence);
 321          ++$i;
 322  
 323          // [foo, bar, ...]
 324          while ($i < $len) {
 325              switch ($sequence[$i]) {
 326                  case '[':
 327                      // nested sequence
 328                      $output[] = self::parseSequence($sequence, $i, $references);
 329                      break;
 330                  case '{':
 331                      // nested mapping
 332                      $output[] = self::parseMapping($sequence, $i, $references);
 333                      break;
 334                  case ']':
 335                      return $output;
 336                  case ',':
 337                  case ' ':
 338                      break;
 339                  default:
 340                      $isQuoted = \in_array($sequence[$i], array('"', "'"));
 341                      $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i, true, $references);
 342  
 343                      // the value can be an array if a reference has been resolved to an array var
 344                      if (!\is_array($value) && !$isQuoted && false !== strpos($value, ': ')) {
 345                          // embedded mapping?
 346                          try {
 347                              $pos = 0;
 348                              $value = self::parseMapping('{'.$value.'}', $pos, $references);
 349                          } catch (\InvalidArgumentException $e) {
 350                              // no, it's not
 351                          }
 352                      }
 353  
 354                      $output[] = $value;
 355  
 356                      --$i;
 357              }
 358  
 359              ++$i;
 360          }
 361  
 362          throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence));
 363      }
 364  
 365      /**
 366       * Parses a YAML mapping.
 367       *
 368       * @param string $mapping
 369       * @param int    &$i
 370       * @param array  $references
 371       *
 372       * @return array|\stdClass
 373       *
 374       * @throws ParseException When malformed inline YAML string is parsed
 375       */
 376      private static function parseMapping($mapping, &$i = 0, $references = array())
 377      {
 378          $output = array();
 379          $len = \strlen($mapping);
 380          ++$i;
 381          $allowOverwrite = false;
 382  
 383          // {foo: bar, bar:foo, ...}
 384          while ($i < $len) {
 385              switch ($mapping[$i]) {
 386                  case ' ':
 387                  case ',':
 388                      ++$i;
 389                      continue 2;
 390                  case '}':
 391                      if (self::$objectForMap) {
 392                          return (object) $output;
 393                      }
 394  
 395                      return $output;
 396              }
 397  
 398              // key
 399              $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
 400  
 401              if ('<<' === $key) {
 402                  $allowOverwrite = true;
 403              }
 404  
 405              // value
 406              $done = false;
 407  
 408              while ($i < $len) {
 409                  switch ($mapping[$i]) {
 410                      case '[':
 411                          // nested sequence
 412                          $value = self::parseSequence($mapping, $i, $references);
 413                          // Spec: Keys MUST be unique; first one wins.
 414                          // Parser cannot abort this mapping earlier, since lines
 415                          // are processed sequentially.
 416                          // But overwriting is allowed when a merge node is used in current block.
 417                          if ('<<' === $key) {
 418                              foreach ($value as $parsedValue) {
 419                                  $output += $parsedValue;
 420                              }
 421                          } elseif ($allowOverwrite || !isset($output[$key])) {
 422                              $output[$key] = $value;
 423                          }
 424                          $done = true;
 425                          break;
 426                      case '{':
 427                          // nested mapping
 428                          $value = self::parseMapping($mapping, $i, $references);
 429                          // Spec: Keys MUST be unique; first one wins.
 430                          // Parser cannot abort this mapping earlier, since lines
 431                          // are processed sequentially.
 432                          // But overwriting is allowed when a merge node is used in current block.
 433                          if ('<<' === $key) {
 434                              $output += $value;
 435                          } elseif ($allowOverwrite || !isset($output[$key])) {
 436                              $output[$key] = $value;
 437                          }
 438                          $done = true;
 439                          break;
 440                      case ':':
 441                      case ' ':
 442                          break;
 443                      default:
 444                          $value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i, true, $references);
 445                          // Spec: Keys MUST be unique; first one wins.
 446                          // Parser cannot abort this mapping earlier, since lines
 447                          // are processed sequentially.
 448                          // But overwriting is allowed when a merge node is used in current block.
 449                          if ('<<' === $key) {
 450                              $output += $value;
 451                          } elseif ($allowOverwrite || !isset($output[$key])) {
 452                              $output[$key] = $value;
 453                          }
 454                          $done = true;
 455                          --$i;
 456                  }
 457  
 458                  ++$i;
 459  
 460                  if ($done) {
 461                      continue 2;
 462                  }
 463              }
 464          }
 465  
 466          throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping));
 467      }
 468  
 469      /**
 470       * Evaluates scalars and replaces magic values.
 471       *
 472       * @param string $scalar
 473       * @param array  $references
 474       *
 475       * @return mixed The evaluated YAML string
 476       *
 477       * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
 478       */
 479      private static function evaluateScalar($scalar, $references = array())
 480      {
 481          $scalar = trim($scalar);
 482          $scalarLower = strtolower($scalar);
 483  
 484          if (0 === strpos($scalar, '*')) {
 485              if (false !== $pos = strpos($scalar, '#')) {
 486                  $value = substr($scalar, 1, $pos - 2);
 487              } else {
 488                  $value = substr($scalar, 1);
 489              }
 490  
 491              // an unquoted *
 492              if (false === $value || '' === $value) {
 493                  throw new ParseException('A reference must contain at least one character.');
 494              }
 495  
 496              if (!array_key_exists($value, $references)) {
 497                  throw new ParseException(sprintf('Reference "%s" does not exist.', $value));
 498              }
 499  
 500              return $references[$value];
 501          }
 502  
 503          switch (true) {
 504              case 'null' === $scalarLower:
 505              case '' === $scalar:
 506              case '~' === $scalar:
 507                  return;
 508              case 'true' === $scalarLower:
 509                  return true;
 510              case 'false' === $scalarLower:
 511                  return false;
 512              // Optimise for returning strings.
 513              case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || '!' === $scalar[0] || is_numeric($scalar[0]):
 514                  switch (true) {
 515                      case 0 === strpos($scalar, '!str'):
 516                          return (string) substr($scalar, 5);
 517                      case 0 === strpos($scalar, '! '):
 518                          return (int) self::parseScalar(substr($scalar, 2));
 519                      case 0 === strpos($scalar, '!php/object:'):
 520                          if (self::$objectSupport) {
 521                              return unserialize(substr($scalar, 12));
 522                          }
 523  
 524                          if (self::$exceptionOnInvalidType) {
 525                              throw new ParseException('Object support when parsing a YAML file has been disabled.');
 526                          }
 527  
 528                          return;
 529                      case 0 === strpos($scalar, '!!php/object:'):
 530                          if (self::$objectSupport) {
 531                              return unserialize(substr($scalar, 13));
 532                          }
 533  
 534                          if (self::$exceptionOnInvalidType) {
 535                              throw new ParseException('Object support when parsing a YAML file has been disabled.');
 536                          }
 537  
 538                          return;
 539                      case 0 === strpos($scalar, '!!float '):
 540                          return (float) substr($scalar, 8);
 541                      case ctype_digit($scalar):
 542                          $raw = $scalar;
 543                          $cast = (int) $scalar;
 544  
 545                          return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
 546                      case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
 547                          $raw = $scalar;
 548                          $cast = (int) $scalar;
 549  
 550                          return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
 551                      case is_numeric($scalar):
 552                      case Parser::preg_match(self::getHexRegex(), $scalar):
 553                          return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
 554                      case '.inf' === $scalarLower:
 555                      case '.nan' === $scalarLower:
 556                          return -log(0);
 557                      case '-.inf' === $scalarLower:
 558                          return log(0);
 559                      case Parser::preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
 560                          return (float) str_replace(',', '', $scalar);
 561                      case Parser::preg_match(self::getTimestampRegex(), $scalar):
 562                          $timeZone = date_default_timezone_get();
 563                          date_default_timezone_set('UTC');
 564                          $time = strtotime($scalar);
 565                          date_default_timezone_set($timeZone);
 566  
 567                          return $time;
 568                  }
 569                  // no break
 570              default:
 571                  return (string) $scalar;
 572          }
 573      }
 574  
 575      /**
 576       * Gets a regex that matches a YAML date.
 577       *
 578       * @return string The regular expression
 579       *
 580       * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
 581       */
 582      private static function getTimestampRegex()
 583      {
 584          return <<<EOF
 585          ~^
 586          (?P<year>[0-9][0-9][0-9][0-9])
 587          -(?P<month>[0-9][0-9]?)
 588          -(?P<day>[0-9][0-9]?)
 589          (?:(?:[Tt]|[ \t]+)
 590          (?P<hour>[0-9][0-9]?)
 591          :(?P<minute>[0-9][0-9])
 592          :(?P<second>[0-9][0-9])
 593          (?:\.(?P<fraction>[0-9]*))?
 594          (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
 595          (?::(?P<tz_minute>[0-9][0-9]))?))?)?
 596          $~x
 597  EOF;
 598      }
 599  
 600      /**
 601       * Gets a regex that matches a YAML number in hexadecimal notation.
 602       *
 603       * @return string
 604       */
 605      private static function getHexRegex()
 606      {
 607          return '~^0x[0-9a-f]++$~i';
 608      }
 609  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1