[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |