Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/yaml/Inline.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
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\ParseException; | |
15 use Symfony\Component\Yaml\Exception\DumpException; | |
16 | |
17 /** | |
18 * Inline implements a YAML parser/dumper for the YAML inline syntax. | |
19 * | |
20 * @author Fabien Potencier <fabien@symfony.com> | |
21 * | |
22 * @internal | |
23 */ | |
24 class Inline | |
25 { | |
26 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')'; | |
27 | |
28 public static $parsedLineNumber; | |
29 | |
30 private static $exceptionOnInvalidType = false; | |
31 private static $objectSupport = false; | |
32 private static $objectForMap = false; | |
33 private static $constantSupport = false; | |
34 | |
35 /** | |
36 * Converts a YAML string to a PHP value. | |
37 * | |
38 * @param string $value A YAML string | |
39 * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior | |
40 * @param array $references Mapping of variable names to values | |
41 * | |
42 * @return mixed A PHP value | |
43 * | |
44 * @throws ParseException | |
45 */ | |
46 public static function parse($value, $flags = 0, $references = array()) | |
47 { | |
48 if (is_bool($flags)) { | |
49 @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); | |
50 | |
51 if ($flags) { | |
52 $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE; | |
53 } else { | |
54 $flags = 0; | |
55 } | |
56 } | |
57 | |
58 if (func_num_args() >= 3 && !is_array($references)) { | |
59 @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); | |
60 | |
61 if ($references) { | |
62 $flags |= Yaml::PARSE_OBJECT; | |
63 } | |
64 | |
65 if (func_num_args() >= 4) { | |
66 @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); | |
67 | |
68 if (func_get_arg(3)) { | |
69 $flags |= Yaml::PARSE_OBJECT_FOR_MAP; | |
70 } | |
71 } | |
72 | |
73 if (func_num_args() >= 5) { | |
74 $references = func_get_arg(4); | |
75 } else { | |
76 $references = array(); | |
77 } | |
78 } | |
79 | |
80 self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags); | |
81 self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); | |
82 self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags); | |
83 self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags); | |
84 | |
85 $value = trim($value); | |
86 | |
87 if ('' === $value) { | |
88 return ''; | |
89 } | |
90 | |
91 if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) { | |
92 $mbEncoding = mb_internal_encoding(); | |
93 mb_internal_encoding('ASCII'); | |
94 } | |
95 | |
96 $i = 0; | |
97 switch ($value[0]) { | |
98 case '[': | |
99 $result = self::parseSequence($value, $flags, $i, $references); | |
100 ++$i; | |
101 break; | |
102 case '{': | |
103 $result = self::parseMapping($value, $flags, $i, $references); | |
104 ++$i; | |
105 break; | |
106 default: | |
107 $result = self::parseScalar($value, $flags, null, array('"', "'"), $i, true, $references); | |
108 } | |
109 | |
110 // some comments are allowed at the end | |
111 if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) { | |
112 throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i))); | |
113 } | |
114 | |
115 if (isset($mbEncoding)) { | |
116 mb_internal_encoding($mbEncoding); | |
117 } | |
118 | |
119 return $result; | |
120 } | |
121 | |
122 /** | |
123 * Dumps a given PHP variable to a YAML string. | |
124 * | |
125 * @param mixed $value The PHP variable to convert | |
126 * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string | |
127 * | |
128 * @return string The YAML string representing the PHP value | |
129 * | |
130 * @throws DumpException When trying to dump PHP resource | |
131 */ | |
132 public static function dump($value, $flags = 0) | |
133 { | |
134 if (is_bool($flags)) { | |
135 @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); | |
136 | |
137 if ($flags) { | |
138 $flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE; | |
139 } else { | |
140 $flags = 0; | |
141 } | |
142 } | |
143 | |
144 if (func_num_args() >= 3) { | |
145 @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); | |
146 | |
147 if (func_get_arg(2)) { | |
148 $flags |= Yaml::DUMP_OBJECT; | |
149 } | |
150 } | |
151 | |
152 switch (true) { | |
153 case is_resource($value): | |
154 if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) { | |
155 throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value))); | |
156 } | |
157 | |
158 return 'null'; | |
159 case $value instanceof \DateTimeInterface: | |
160 return $value->format('c'); | |
161 case is_object($value): | |
162 if (Yaml::DUMP_OBJECT & $flags) { | |
163 return '!php/object:'.serialize($value); | |
164 } | |
165 | |
166 if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) { | |
167 return self::dumpArray((array) $value, $flags); | |
168 } | |
169 | |
170 if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) { | |
171 throw new DumpException('Object support when dumping a YAML file has been disabled.'); | |
172 } | |
173 | |
174 return 'null'; | |
175 case is_array($value): | |
176 return self::dumpArray($value, $flags); | |
177 case null === $value: | |
178 return 'null'; | |
179 case true === $value: | |
180 return 'true'; | |
181 case false === $value: | |
182 return 'false'; | |
183 case ctype_digit($value): | |
184 return is_string($value) ? "'$value'" : (int) $value; | |
185 case is_numeric($value): | |
186 $locale = setlocale(LC_NUMERIC, 0); | |
187 if (false !== $locale) { | |
188 setlocale(LC_NUMERIC, 'C'); | |
189 } | |
190 if (is_float($value)) { | |
191 $repr = (string) $value; | |
192 if (is_infinite($value)) { | |
193 $repr = str_ireplace('INF', '.Inf', $repr); | |
194 } elseif (floor($value) == $value && $repr == $value) { | |
195 // Preserve float data type since storing a whole number will result in integer value. | |
196 $repr = '!!float '.$repr; | |
197 } | |
198 } else { | |
199 $repr = is_string($value) ? "'$value'" : (string) $value; | |
200 } | |
201 if (false !== $locale) { | |
202 setlocale(LC_NUMERIC, $locale); | |
203 } | |
204 | |
205 return $repr; | |
206 case '' == $value: | |
207 return "''"; | |
208 case self::isBinaryString($value): | |
209 return '!!binary '.base64_encode($value); | |
210 case Escaper::requiresDoubleQuoting($value): | |
211 return Escaper::escapeWithDoubleQuotes($value); | |
212 case Escaper::requiresSingleQuoting($value): | |
213 case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value): | |
214 case Parser::preg_match(self::getHexRegex(), $value): | |
215 case Parser::preg_match(self::getTimestampRegex(), $value): | |
216 return Escaper::escapeWithSingleQuotes($value); | |
217 default: | |
218 return $value; | |
219 } | |
220 } | |
221 | |
222 /** | |
223 * Check if given array is hash or just normal indexed array. | |
224 * | |
225 * @internal | |
226 * | |
227 * @param array $value The PHP array to check | |
228 * | |
229 * @return bool true if value is hash array, false otherwise | |
230 */ | |
231 public static function isHash(array $value) | |
232 { | |
233 $expectedKey = 0; | |
234 | |
235 foreach ($value as $key => $val) { | |
236 if ($key !== $expectedKey++) { | |
237 return true; | |
238 } | |
239 } | |
240 | |
241 return false; | |
242 } | |
243 | |
244 /** | |
245 * Dumps a PHP array to a YAML string. | |
246 * | |
247 * @param array $value The PHP array to dump | |
248 * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string | |
249 * | |
250 * @return string The YAML string representing the PHP array | |
251 */ | |
252 private static function dumpArray($value, $flags) | |
253 { | |
254 // array | |
255 if ($value && !self::isHash($value)) { | |
256 $output = array(); | |
257 foreach ($value as $val) { | |
258 $output[] = self::dump($val, $flags); | |
259 } | |
260 | |
261 return sprintf('[%s]', implode(', ', $output)); | |
262 } | |
263 | |
264 // hash | |
265 $output = array(); | |
266 foreach ($value as $key => $val) { | |
267 $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags)); | |
268 } | |
269 | |
270 return sprintf('{ %s }', implode(', ', $output)); | |
271 } | |
272 | |
273 /** | |
274 * Parses a YAML scalar. | |
275 * | |
276 * @param string $scalar | |
277 * @param int $flags | |
278 * @param string[] $delimiters | |
279 * @param string[] $stringDelimiters | |
280 * @param int &$i | |
281 * @param bool $evaluate | |
282 * @param array $references | |
283 * | |
284 * @return string | |
285 * | |
286 * @throws ParseException When malformed inline YAML string is parsed | |
287 * | |
288 * @internal | |
289 */ | |
290 public static function parseScalar($scalar, $flags = 0, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array()) | |
291 { | |
292 if (in_array($scalar[$i], $stringDelimiters)) { | |
293 // quoted scalar | |
294 $output = self::parseQuotedScalar($scalar, $i); | |
295 | |
296 if (null !== $delimiters) { | |
297 $tmp = ltrim(substr($scalar, $i), ' '); | |
298 if (!in_array($tmp[0], $delimiters)) { | |
299 throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i))); | |
300 } | |
301 } | |
302 } else { | |
303 // "normal" string | |
304 if (!$delimiters) { | |
305 $output = substr($scalar, $i); | |
306 $i += strlen($output); | |
307 | |
308 // remove comments | |
309 if (Parser::preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) { | |
310 $output = substr($output, 0, $match[0][1]); | |
311 } | |
312 } elseif (Parser::preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) { | |
313 $output = $match[1]; | |
314 $i += strlen($output); | |
315 } else { | |
316 throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar)); | |
317 } | |
318 | |
319 // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >) | |
320 if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) { | |
321 throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0])); | |
322 } | |
323 | |
324 if ($output && '%' === $output[0]) { | |
325 @trigger_error(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); | |
326 } | |
327 | |
328 if ($evaluate) { | |
329 $output = self::evaluateScalar($output, $flags, $references); | |
330 } | |
331 } | |
332 | |
333 return $output; | |
334 } | |
335 | |
336 /** | |
337 * Parses a YAML quoted scalar. | |
338 * | |
339 * @param string $scalar | |
340 * @param int &$i | |
341 * | |
342 * @return string | |
343 * | |
344 * @throws ParseException When malformed inline YAML string is parsed | |
345 */ | |
346 private static function parseQuotedScalar($scalar, &$i) | |
347 { | |
348 if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { | |
349 throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i))); | |
350 } | |
351 | |
352 $output = substr($match[0], 1, strlen($match[0]) - 2); | |
353 | |
354 $unescaper = new Unescaper(); | |
355 if ('"' == $scalar[$i]) { | |
356 $output = $unescaper->unescapeDoubleQuotedString($output); | |
357 } else { | |
358 $output = $unescaper->unescapeSingleQuotedString($output); | |
359 } | |
360 | |
361 $i += strlen($match[0]); | |
362 | |
363 return $output; | |
364 } | |
365 | |
366 /** | |
367 * Parses a YAML sequence. | |
368 * | |
369 * @param string $sequence | |
370 * @param int $flags | |
371 * @param int &$i | |
372 * @param array $references | |
373 * | |
374 * @return array | |
375 * | |
376 * @throws ParseException When malformed inline YAML string is parsed | |
377 */ | |
378 private static function parseSequence($sequence, $flags, &$i = 0, $references = array()) | |
379 { | |
380 $output = array(); | |
381 $len = strlen($sequence); | |
382 ++$i; | |
383 | |
384 // [foo, bar, ...] | |
385 while ($i < $len) { | |
386 switch ($sequence[$i]) { | |
387 case '[': | |
388 // nested sequence | |
389 $output[] = self::parseSequence($sequence, $flags, $i, $references); | |
390 break; | |
391 case '{': | |
392 // nested mapping | |
393 $output[] = self::parseMapping($sequence, $flags, $i, $references); | |
394 break; | |
395 case ']': | |
396 return $output; | |
397 case ',': | |
398 case ' ': | |
399 break; | |
400 default: | |
401 $isQuoted = in_array($sequence[$i], array('"', "'")); | |
402 $value = self::parseScalar($sequence, $flags, array(',', ']'), array('"', "'"), $i, true, $references); | |
403 | |
404 // the value can be an array if a reference has been resolved to an array var | |
405 if (is_string($value) && !$isQuoted && false !== strpos($value, ': ')) { | |
406 // embedded mapping? | |
407 try { | |
408 $pos = 0; | |
409 $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references); | |
410 } catch (\InvalidArgumentException $e) { | |
411 // no, it's not | |
412 } | |
413 } | |
414 | |
415 $output[] = $value; | |
416 | |
417 --$i; | |
418 } | |
419 | |
420 ++$i; | |
421 } | |
422 | |
423 throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence)); | |
424 } | |
425 | |
426 /** | |
427 * Parses a YAML mapping. | |
428 * | |
429 * @param string $mapping | |
430 * @param int $flags | |
431 * @param int &$i | |
432 * @param array $references | |
433 * | |
434 * @return array|\stdClass | |
435 * | |
436 * @throws ParseException When malformed inline YAML string is parsed | |
437 */ | |
438 private static function parseMapping($mapping, $flags, &$i = 0, $references = array()) | |
439 { | |
440 $output = array(); | |
441 $len = strlen($mapping); | |
442 ++$i; | |
443 | |
444 // {foo: bar, bar:foo, ...} | |
445 while ($i < $len) { | |
446 switch ($mapping[$i]) { | |
447 case ' ': | |
448 case ',': | |
449 ++$i; | |
450 continue 2; | |
451 case '}': | |
452 if (self::$objectForMap) { | |
453 return (object) $output; | |
454 } | |
455 | |
456 return $output; | |
457 } | |
458 | |
459 // key | |
460 $key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false); | |
461 | |
462 if (':' !== $key && false === $i = strpos($mapping, ':', $i)) { | |
463 break; | |
464 } | |
465 | |
466 if (':' !== $key && (!isset($mapping[$i + 1]) || !in_array($mapping[$i + 1], array(' ', ',', '[', ']', '{', '}'), true))) { | |
467 @trigger_error('Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0.', E_USER_DEPRECATED); | |
468 } | |
469 | |
470 // value | |
471 $done = false; | |
472 | |
473 while ($i < $len) { | |
474 switch ($mapping[$i]) { | |
475 case '[': | |
476 // nested sequence | |
477 $value = self::parseSequence($mapping, $flags, $i, $references); | |
478 // Spec: Keys MUST be unique; first one wins. | |
479 // Parser cannot abort this mapping earlier, since lines | |
480 // are processed sequentially. | |
481 if (!isset($output[$key])) { | |
482 $output[$key] = $value; | |
483 } else { | |
484 @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED); | |
485 } | |
486 $done = true; | |
487 break; | |
488 case '{': | |
489 // nested mapping | |
490 $value = self::parseMapping($mapping, $flags, $i, $references); | |
491 // Spec: Keys MUST be unique; first one wins. | |
492 // Parser cannot abort this mapping earlier, since lines | |
493 // are processed sequentially. | |
494 if (!isset($output[$key])) { | |
495 $output[$key] = $value; | |
496 } else { | |
497 @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED); | |
498 } | |
499 $done = true; | |
500 break; | |
501 case ':': | |
502 case ' ': | |
503 break; | |
504 default: | |
505 $value = self::parseScalar($mapping, $flags, array(',', '}'), array('"', "'"), $i, true, $references); | |
506 // Spec: Keys MUST be unique; first one wins. | |
507 // Parser cannot abort this mapping earlier, since lines | |
508 // are processed sequentially. | |
509 if (!isset($output[$key])) { | |
510 $output[$key] = $value; | |
511 } else { | |
512 @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED); | |
513 } | |
514 $done = true; | |
515 --$i; | |
516 } | |
517 | |
518 ++$i; | |
519 | |
520 if ($done) { | |
521 continue 2; | |
522 } | |
523 } | |
524 } | |
525 | |
526 throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping)); | |
527 } | |
528 | |
529 /** | |
530 * Evaluates scalars and replaces magic values. | |
531 * | |
532 * @param string $scalar | |
533 * @param int $flags | |
534 * @param array $references | |
535 * | |
536 * @return mixed The evaluated YAML string | |
537 * | |
538 * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved | |
539 */ | |
540 private static function evaluateScalar($scalar, $flags, $references = array()) | |
541 { | |
542 $scalar = trim($scalar); | |
543 $scalarLower = strtolower($scalar); | |
544 | |
545 if (0 === strpos($scalar, '*')) { | |
546 if (false !== $pos = strpos($scalar, '#')) { | |
547 $value = substr($scalar, 1, $pos - 2); | |
548 } else { | |
549 $value = substr($scalar, 1); | |
550 } | |
551 | |
552 // an unquoted * | |
553 if (false === $value || '' === $value) { | |
554 throw new ParseException('A reference must contain at least one character.'); | |
555 } | |
556 | |
557 if (!array_key_exists($value, $references)) { | |
558 throw new ParseException(sprintf('Reference "%s" does not exist.', $value)); | |
559 } | |
560 | |
561 return $references[$value]; | |
562 } | |
563 | |
564 switch (true) { | |
565 case 'null' === $scalarLower: | |
566 case '' === $scalar: | |
567 case '~' === $scalar: | |
568 return; | |
569 case 'true' === $scalarLower: | |
570 return true; | |
571 case 'false' === $scalarLower: | |
572 return false; | |
573 // Optimise for returning strings. | |
574 case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]): | |
575 switch (true) { | |
576 case 0 === strpos($scalar, '!str'): | |
577 return (string) substr($scalar, 5); | |
578 case 0 === strpos($scalar, '! '): | |
579 return (int) self::parseScalar(substr($scalar, 2), $flags); | |
580 case 0 === strpos($scalar, '!php/object:'): | |
581 if (self::$objectSupport) { | |
582 return unserialize(substr($scalar, 12)); | |
583 } | |
584 | |
585 if (self::$exceptionOnInvalidType) { | |
586 throw new ParseException('Object support when parsing a YAML file has been disabled.'); | |
587 } | |
588 | |
589 return; | |
590 case 0 === strpos($scalar, '!!php/object:'): | |
591 if (self::$objectSupport) { | |
592 @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); | |
593 | |
594 return unserialize(substr($scalar, 13)); | |
595 } | |
596 | |
597 if (self::$exceptionOnInvalidType) { | |
598 throw new ParseException('Object support when parsing a YAML file has been disabled.'); | |
599 } | |
600 | |
601 return; | |
602 case 0 === strpos($scalar, '!php/const:'): | |
603 if (self::$constantSupport) { | |
604 if (defined($const = substr($scalar, 11))) { | |
605 return constant($const); | |
606 } | |
607 | |
608 throw new ParseException(sprintf('The constant "%s" is not defined.', $const)); | |
609 } | |
610 if (self::$exceptionOnInvalidType) { | |
611 throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar)); | |
612 } | |
613 | |
614 return; | |
615 case 0 === strpos($scalar, '!!float '): | |
616 return (float) substr($scalar, 8); | |
617 case Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar): | |
618 $scalar = str_replace('_', '', (string) $scalar); | |
619 // omitting the break / return as integers are handled in the next case | |
620 case ctype_digit($scalar): | |
621 $raw = $scalar; | |
622 $cast = (int) $scalar; | |
623 | |
624 return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw); | |
625 case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)): | |
626 $raw = $scalar; | |
627 $cast = (int) $scalar; | |
628 | |
629 return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw); | |
630 case is_numeric($scalar): | |
631 case Parser::preg_match(self::getHexRegex(), $scalar): | |
632 $scalar = str_replace('_', '', $scalar); | |
633 | |
634 return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar; | |
635 case '.inf' === $scalarLower: | |
636 case '.nan' === $scalarLower: | |
637 return -log(0); | |
638 case '-.inf' === $scalarLower: | |
639 return log(0); | |
640 case 0 === strpos($scalar, '!!binary '): | |
641 return self::evaluateBinaryScalar(substr($scalar, 9)); | |
642 case Parser::preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar): | |
643 case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar): | |
644 if (false !== strpos($scalar, ',')) { | |
645 @trigger_error('Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0.', E_USER_DEPRECATED); | |
646 } | |
647 | |
648 return (float) str_replace(array(',', '_'), '', $scalar); | |
649 case Parser::preg_match(self::getTimestampRegex(), $scalar): | |
650 if (Yaml::PARSE_DATETIME & $flags) { | |
651 // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. | |
652 return new \DateTime($scalar, new \DateTimeZone('UTC')); | |
653 } | |
654 | |
655 $timeZone = date_default_timezone_get(); | |
656 date_default_timezone_set('UTC'); | |
657 $time = strtotime($scalar); | |
658 date_default_timezone_set($timeZone); | |
659 | |
660 return $time; | |
661 } | |
662 default: | |
663 return (string) $scalar; | |
664 } | |
665 } | |
666 | |
667 /** | |
668 * @param string $scalar | |
669 * | |
670 * @return string | |
671 * | |
672 * @internal | |
673 */ | |
674 public static function evaluateBinaryScalar($scalar) | |
675 { | |
676 $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar)); | |
677 | |
678 if (0 !== (strlen($parsedBinaryData) % 4)) { | |
679 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))); | |
680 } | |
681 | |
682 if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) { | |
683 throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData)); | |
684 } | |
685 | |
686 return base64_decode($parsedBinaryData, true); | |
687 } | |
688 | |
689 private static function isBinaryString($value) | |
690 { | |
691 return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value); | |
692 } | |
693 | |
694 /** | |
695 * Gets a regex that matches a YAML date. | |
696 * | |
697 * @return string The regular expression | |
698 * | |
699 * @see http://www.yaml.org/spec/1.2/spec.html#id2761573 | |
700 */ | |
701 private static function getTimestampRegex() | |
702 { | |
703 return <<<EOF | |
704 ~^ | |
705 (?P<year>[0-9][0-9][0-9][0-9]) | |
706 -(?P<month>[0-9][0-9]?) | |
707 -(?P<day>[0-9][0-9]?) | |
708 (?:(?:[Tt]|[ \t]+) | |
709 (?P<hour>[0-9][0-9]?) | |
710 :(?P<minute>[0-9][0-9]) | |
711 :(?P<second>[0-9][0-9]) | |
712 (?:\.(?P<fraction>[0-9]*))? | |
713 (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?) | |
714 (?::(?P<tz_minute>[0-9][0-9]))?))?)? | |
715 $~x | |
716 EOF; | |
717 } | |
718 | |
719 /** | |
720 * Gets a regex that matches a YAML number in hexadecimal notation. | |
721 * | |
722 * @return string | |
723 */ | |
724 private static function getHexRegex() | |
725 { | |
726 return '~^0x[0-9a-f_]++$~i'; | |
727 } | |
728 } |