ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Inline.php
Go to the documentation of this file.
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
13
16
24class Inline
25{
26 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
27
28 private static $exceptionOnInvalidType = false;
29 private static $objectSupport = false;
30 private static $objectForMap = false;
31
43 public static function parse($value, $flags = 0, $references = array())
44 {
45 if (is_bool($flags)) {
46 @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
47
48 if ($flags) {
50 } else {
51 $flags = 0;
52 }
53 }
54
55 if (func_num_args() >= 3 && !is_array($references)) {
56 @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
57
58 if ($references) {
59 $flags |= Yaml::PARSE_OBJECT;
60 }
61
62 if (func_num_args() >= 4) {
63 @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
64
65 if (func_get_arg(3)) {
67 }
68 }
69
70 if (func_num_args() >= 5) {
71 $references = func_get_arg(4);
72 } else {
73 $references = array();
74 }
75 }
76
77 self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
78 self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
79 self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
80
81 $value = trim($value);
82
83 if ('' === $value) {
84 return '';
85 }
86
87 if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
88 $mbEncoding = mb_internal_encoding();
89 mb_internal_encoding('ASCII');
90 }
91
92 $i = 0;
93 switch ($value[0]) {
94 case '[':
95 $result = self::parseSequence($value, $flags, $i, $references);
96 ++$i;
97 break;
98 case '{':
99 $result = self::parseMapping($value, $flags, $i, $references);
100 ++$i;
101 break;
102 default:
103 $result = self::parseScalar($value, $flags, null, array('"', "'"), $i, true, $references);
104 }
105
106 // some comments are allowed at the end
107 if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
108 throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)));
109 }
110
111 if (isset($mbEncoding)) {
112 mb_internal_encoding($mbEncoding);
113 }
114
115 return $result;
116 }
117
128 public static function dump($value, $flags = 0)
129 {
130 if (is_bool($flags)) {
131 @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
132
133 if ($flags) {
135 } else {
136 $flags = 0;
137 }
138 }
139
140 if (func_num_args() >= 3) {
141 @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED);
142
143 if (func_get_arg(2)) {
144 $flags |= Yaml::DUMP_OBJECT;
145 }
146 }
147
148 switch (true) {
149 case is_resource($value):
151 throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
152 }
153
154 return 'null';
155 case $value instanceof \DateTimeInterface:
156 return $value->format('c');
157 case is_object($value):
158 if (Yaml::DUMP_OBJECT & $flags) {
159 return '!php/object:'.serialize($value);
160 }
161
162 if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
163 return self::dumpArray((array) $value, $flags);
164 }
165
167 throw new DumpException('Object support when dumping a YAML file has been disabled.');
168 }
169
170 return 'null';
171 case is_array($value):
172 return self::dumpArray($value, $flags);
173 case null === $value:
174 return 'null';
175 case true === $value:
176 return 'true';
177 case false === $value:
178 return 'false';
179 case ctype_digit($value):
180 return is_string($value) ? "'$value'" : (int) $value;
181 case is_numeric($value):
182 $locale = setlocale(LC_NUMERIC, 0);
183 if (false !== $locale) {
184 setlocale(LC_NUMERIC, 'C');
185 }
186 if (is_float($value)) {
187 $repr = (string) $value;
188 if (is_infinite($value)) {
189 $repr = str_ireplace('INF', '.Inf', $repr);
190 } elseif (floor($value) == $value && $repr == $value) {
191 // Preserve float data type since storing a whole number will result in integer value.
192 $repr = '!!float '.$repr;
193 }
194 } else {
195 $repr = is_string($value) ? "'$value'" : (string) $value;
196 }
197 if (false !== $locale) {
198 setlocale(LC_NUMERIC, $locale);
199 }
200
201 return $repr;
202 case '' == $value:
203 return "''";
204 case self::isBinaryString($value):
205 return '!!binary '.base64_encode($value);
207 return Escaper::escapeWithDoubleQuotes($value);
209 case preg_match(self::getHexRegex(), $value):
210 case preg_match(self::getTimestampRegex(), $value):
211 return Escaper::escapeWithSingleQuotes($value);
212 default:
213 return $value;
214 }
215 }
216
226 public static function isHash(array $value)
227 {
228 $expectedKey = 0;
229
230 foreach ($value as $key => $val) {
231 if ($key !== $expectedKey++) {
232 return true;
233 }
234 }
235
236 return false;
237 }
238
247 private static function dumpArray($value, $flags)
248 {
249 // array
250 if ($value && !self::isHash($value)) {
251 $output = array();
252 foreach ($value as $val) {
253 $output[] = self::dump($val, $flags);
254 }
255
256 return sprintf('[%s]', implode(', ', $output));
257 }
258
259 // hash
260 $output = array();
261 foreach ($value as $key => $val) {
262 $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
263 }
264
265 return sprintf('{ %s }', implode(', ', $output));
266 }
267
285 public static function parseScalar($scalar, $flags = 0, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
286 {
287 if (in_array($scalar[$i], $stringDelimiters)) {
288 // quoted scalar
290
291 if (null !== $delimiters) {
292 $tmp = ltrim(substr($scalar, $i), ' ');
293 if (!in_array($tmp[0], $delimiters)) {
294 throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
295 }
296 }
297 } else {
298 // "normal" string
299 if (!$delimiters) {
300 $output = substr($scalar, $i);
301 $i += strlen($output);
302
303 // remove comments
304 if (preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) {
305 $output = substr($output, 0, $match[0][1]);
306 }
307 } elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
308 $output = $match[1];
309 $i += strlen($output);
310 } else {
311 throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
312 }
313
314 // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
315 if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
316 throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]));
317 }
318
319 if ($output && '%' === $output[0]) {
320 @trigger_error('Not quoting a scalar starting with the "%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.', E_USER_DEPRECATED);
321 }
322
323 if ($evaluate) {
324 $output = self::evaluateScalar($output, $flags, $references);
325 }
326 }
327
328 return $output;
329 }
330
341 private static function parseQuotedScalar($scalar, &$i)
342 {
343 if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
344 throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
345 }
346
347 $output = substr($match[0], 1, strlen($match[0]) - 2);
348
349 $unescaper = new Unescaper();
350 if ('"' == $scalar[$i]) {
351 $output = $unescaper->unescapeDoubleQuotedString($output);
352 } else {
353 $output = $unescaper->unescapeSingleQuotedString($output);
354 }
355
356 $i += strlen($match[0]);
357
358 return $output;
359 }
360
373 private static function parseSequence($sequence, $flags, &$i = 0, $references = array())
374 {
375 $output = array();
376 $len = strlen($sequence);
377 ++$i;
378
379 // [foo, bar, ...]
380 while ($i < $len) {
381 switch ($sequence[$i]) {
382 case '[':
383 // nested sequence
384 $output[] = self::parseSequence($sequence, $flags, $i, $references);
385 break;
386 case '{':
387 // nested mapping
388 $output[] = self::parseMapping($sequence, $flags, $i, $references);
389 break;
390 case ']':
391 return $output;
392 case ',':
393 case ' ':
394 break;
395 default:
396 $isQuoted = in_array($sequence[$i], array('"', "'"));
397 $value = self::parseScalar($sequence, $flags, array(',', ']'), array('"', "'"), $i, true, $references);
398
399 // the value can be an array if a reference has been resolved to an array var
400 if (is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {
401 // embedded mapping?
402 try {
403 $pos = 0;
404 $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
405 } catch (\InvalidArgumentException $e) {
406 // no, it's not
407 }
408 }
409
410 $output[] = $value;
411
412 --$i;
413 }
414
415 ++$i;
416 }
417
418 throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
419 }
420
433 private static function parseMapping($mapping, $flags, &$i = 0, $references = array())
434 {
435 $output = array();
436 $len = strlen($mapping);
437 ++$i;
438
439 // {foo: bar, bar:foo, ...}
440 while ($i < $len) {
441 switch ($mapping[$i]) {
442 case ' ':
443 case ',':
444 ++$i;
445 continue 2;
446 case '}':
447 if (self::$objectForMap) {
448 return (object) $output;
449 }
450
451 return $output;
452 }
453
454 // key
455 $key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false);
456
457 // value
458 $done = false;
459
460 while ($i < $len) {
461 switch ($mapping[$i]) {
462 case '[':
463 // nested sequence
464 $value = self::parseSequence($mapping, $flags, $i, $references);
465 // Spec: Keys MUST be unique; first one wins.
466 // Parser cannot abort this mapping earlier, since lines
467 // are processed sequentially.
468 if (!isset($output[$key])) {
469 $output[$key] = $value;
470 }
471 $done = true;
472 break;
473 case '{':
474 // nested mapping
475 $value = self::parseMapping($mapping, $flags, $i, $references);
476 // Spec: Keys MUST be unique; first one wins.
477 // Parser cannot abort this mapping earlier, since lines
478 // are processed sequentially.
479 if (!isset($output[$key])) {
480 $output[$key] = $value;
481 }
482 $done = true;
483 break;
484 case ':':
485 case ' ':
486 break;
487 default:
488 $value = self::parseScalar($mapping, $flags, array(',', '}'), array('"', "'"), $i, true, $references);
489 // Spec: Keys MUST be unique; first one wins.
490 // Parser cannot abort this mapping earlier, since lines
491 // are processed sequentially.
492 if (!isset($output[$key])) {
493 $output[$key] = $value;
494 }
495 $done = true;
496 --$i;
497 }
498
499 ++$i;
500
501 if ($done) {
502 continue 2;
503 }
504 }
505 }
506
507 throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
508 }
509
521 private static function evaluateScalar($scalar, $flags, $references = array())
522 {
523 $scalar = trim($scalar);
524 $scalarLower = strtolower($scalar);
525
526 if (0 === strpos($scalar, '*')) {
527 if (false !== $pos = strpos($scalar, '#')) {
528 $value = substr($scalar, 1, $pos - 2);
529 } else {
530 $value = substr($scalar, 1);
531 }
532
533 // an unquoted *
534 if (false === $value || '' === $value) {
535 throw new ParseException('A reference must contain at least one character.');
536 }
537
538 if (!array_key_exists($value, $references)) {
539 throw new ParseException(sprintf('Reference "%s" does not exist.', $value));
540 }
541
542 return $references[$value];
543 }
544
545 switch (true) {
546 case 'null' === $scalarLower:
547 case '' === $scalar:
548 case '~' === $scalar:
549 return;
550 case 'true' === $scalarLower:
551 return true;
552 case 'false' === $scalarLower:
553 return false;
554 // Optimise for returning strings.
555 case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]):
556 switch (true) {
557 case 0 === strpos($scalar, '!str'):
558 return (string) substr($scalar, 5);
559 case 0 === strpos($scalar, '! '):
560 return (int) self::parseScalar(substr($scalar, 2), $flags);
561 case 0 === strpos($scalar, '!php/object:'):
562 if (self::$objectSupport) {
563 return unserialize(substr($scalar, 12));
564 }
565
566 if (self::$exceptionOnInvalidType) {
567 throw new ParseException('Object support when parsing a YAML file has been disabled.');
568 }
569
570 return;
571 case 0 === strpos($scalar, '!!php/object:'):
572 if (self::$objectSupport) {
573 @trigger_error('The !!php/object tag to indicate dumped PHP objects is deprecated since version 3.1 and will be removed in 4.0. Use the !php/object tag instead.', E_USER_DEPRECATED);
574
575 return unserialize(substr($scalar, 13));
576 }
577
578 if (self::$exceptionOnInvalidType) {
579 throw new ParseException('Object support when parsing a YAML file has been disabled.');
580 }
581
582 return;
583 case 0 === strpos($scalar, '!!float '):
584 return (float) substr($scalar, 8);
585 case ctype_digit($scalar):
586 $raw = $scalar;
587 $cast = (int) $scalar;
588
589 return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
590 case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
591 $raw = $scalar;
592 $cast = (int) $scalar;
593
594 return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
595 case is_numeric($scalar):
596 case preg_match(self::getHexRegex(), $scalar):
597 return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
598 case '.inf' === $scalarLower:
599 case '.nan' === $scalarLower:
600 return -log(0);
601 case '-.inf' === $scalarLower:
602 return log(0);
603 case 0 === strpos($scalar, '!!binary '):
604 return self::evaluateBinaryScalar(substr($scalar, 9));
605 case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
606 return (float) str_replace(',', '', $scalar);
607 case preg_match(self::getTimestampRegex(), $scalar):
608 if (Yaml::PARSE_DATETIME & $flags) {
609 return new \DateTime($scalar, new \DateTimeZone('UTC'));
610 }
611
612 $timeZone = date_default_timezone_get();
613 date_default_timezone_set('UTC');
614 $time = strtotime($scalar);
615 date_default_timezone_set($timeZone);
616
617 return $time;
618 }
619 default:
620 return (string) $scalar;
621 }
622 }
623
631 public static function evaluateBinaryScalar($scalar)
632 {
633 $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
634
635 if (0 !== (strlen($parsedBinaryData) % 4)) {
636 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)));
637 }
638
639 if (!preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
640 throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData));
641 }
642
643 return base64_decode($parsedBinaryData, true);
644 }
645
646 private static function isBinaryString($value)
647 {
648 return !preg_match('//u', $value) || preg_match('/[^\x09-\x0d\x20-\xff]/', $value);
649 }
650
658 private static function getTimestampRegex()
659 {
660 return <<<EOF
661 ~^
662 (?P<year>[0-9][0-9][0-9][0-9])
663 -(?P<month>[0-9][0-9]?)
664 -(?P<day>[0-9][0-9]?)
665 (?:(?:[Tt]|[ \t]+)
666 (?P<hour>[0-9][0-9]?)
667 :(?P<minute>[0-9][0-9])
668 :(?P<second>[0-9][0-9])
669 (?:\.(?P<fraction>[0-9]*))?
670 (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
671 (?::(?P<tz_minute>[0-9][0-9]))?))?)?
672 $~x
673EOF;
674 }
675
681 private static function getHexRegex()
682 {
683 return '~^0x[0-9a-f]++$~i';
684 }
685}
$result
const EOF
How fgetc() reports an End Of File.
Definition: JSMin_lib.php:92
An exception for terminatinating execution or to throw for unit testing.
static requiresDoubleQuoting($value)
Determines if a PHP value would require double quoting in YAML.
Definition: Escaper.php:51
static escapeWithSingleQuotes($value)
Escapes and surrounds a PHP value with single quotes.
Definition: Escaper.php:95
static requiresSingleQuoting($value)
Determines if a PHP value would require single quoting in YAML.
Definition: Escaper.php:75
static escapeWithDoubleQuotes($value)
Escapes and surrounds a PHP value with double quotes.
Definition: Escaper.php:63
Exception class thrown when an error occurs during dumping.
Exception class thrown when an error occurs during parsing.
Inline implements a YAML parser/dumper for the YAML inline syntax.
Definition: Inline.php:25
static getHexRegex()
Gets a regex that matches a YAML number in hexadecimal notation.
Definition: Inline.php:681
static parse($value, $flags=0, $references=array())
Converts a YAML string to a PHP array.
Definition: Inline.php:43
static isHash(array $value)
Check if given array is hash or just normal indexed array.
Definition: Inline.php:226
static parseQuotedScalar($scalar, &$i)
Parses a quoted scalar to YAML.
Definition: Inline.php:341
static getTimestampRegex()
Gets a regex that matches a YAML date.
Definition: Inline.php:658
static evaluateBinaryScalar($scalar)
Definition: Inline.php:631
static parseScalar($scalar, $flags=0, $delimiters=null, $stringDelimiters=array('"', "'"), &$i = 0, $evaluate = true, $references = array())
Parses a scalar to a YAML string.
Definition: Inline.php:285
static dump($value, $flags=0)
Dumps a given PHP variable to a YAML string.
Definition: Inline.php:128
static evaluateScalar($scalar, $flags, $references=array())
Evaluates scalars and replaces magic values.
Definition: Inline.php:521
static parseMapping($mapping, $flags, &$i=0, $references=array())
Parses a mapping to a YAML string.
Definition: Inline.php:433
static dumpArray($value, $flags)
Dumps a PHP array to a YAML string.
Definition: Inline.php:247
static parseSequence($sequence, $flags, &$i=0, $references=array())
Parses a sequence to a YAML string.
Definition: Inline.php:373
static isBinaryString($value)
Definition: Inline.php:646
Unescaper encapsulates unescaping rules for single and double-quoted YAML strings.
Definition: Unescaper.php:25
const DUMP_EXCEPTION_ON_INVALID_TYPE
Definition: Yaml.php:27
const PARSE_EXCEPTION_ON_INVALID_TYPE
Definition: Yaml.php:24
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
$time
Definition: cron.php:21