Overview

Namespaces

  • Composer
    • Autoload
  • Guzzle
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
        • Header
      • QueryAggregator
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Mock
    • Stream
  • Mockery
    • Adapter
      • Phpunit
    • CountValidator
    • Exception
    • Generator
      • StringManipulation
        • Pass
    • Loader
    • Matcher
  • None
  • Omnipay
    • Common
      • Exception
      • Message
    • Dummy
      • Message
    • Fatzebra
      • Message
  • PHP
  • Symfony
    • Component
      • EventDispatcher
        • Debug
        • DependencyInjection
        • Tests
          • Debug
          • DependencyInjection
      • HttpFoundation
        • File
          • Exception
          • MimeType
        • Session
          • Attribute
          • Flash
          • Storage
            • Handler
            • Proxy
        • Tests
          • File
            • MimeType
          • Session
            • Attribute
            • Flash
            • Storage
              • Handler
              • Proxy
      • Yaml
        • Exception
        • Tests

Classes

  • Symfony\Component\Yaml\Tests\A
  • Symfony\Component\Yaml\Tests\B
  • Symfony\Component\Yaml\Tests\DumperTest
  • Symfony\Component\Yaml\Tests\InlineTest
  • Symfony\Component\Yaml\Tests\ParseExceptionTest
  • Symfony\Component\Yaml\Tests\ParserTest
  • Symfony\Component\Yaml\Tests\YamlTest
  • Overview
  • Namespace
  • Function
  • Tree
  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: 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 array.
 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 array A PHP array representing the YAML string
 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 (0 == strlen($value)) {
 52:             return '';
 53:         }
 54: 
 55:         if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
 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 array
 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 = strval($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'" : strval($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 preg_match(self::getTimestampRegex(), $value):
153:                 return Escaper::escapeWithSingleQuotes($value);
154:             default:
155:                 return $value;
156:         }
157:     }
158: 
159:     /**
160:      * Dumps a PHP array to a YAML string.
161:      *
162:      * @param array $value                  The PHP array to dump
163:      * @param bool  $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
164:      * @param bool  $objectSupport          true if object support is enabled, false otherwise
165:      *
166:      * @return string The YAML string representing the PHP array
167:      */
168:     private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
169:     {
170:         // array
171:         $keys = array_keys($value);
172:         if ((1 == count($keys) && '0' == $keys[0])
173:             || (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (int) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)
174:         ) {
175:             $output = array();
176:             foreach ($value as $val) {
177:                 $output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
178:             }
179: 
180:             return sprintf('[%s]', implode(', ', $output));
181:         }
182: 
183:         // mapping
184:         $output = array();
185:         foreach ($value as $key => $val) {
186:             $output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
187:         }
188: 
189:         return sprintf('{ %s }', implode(', ', $output));
190:     }
191: 
192:     /**
193:      * Parses a scalar to a YAML string.
194:      *
195:      * @param string $scalar
196:      * @param string $delimiters
197:      * @param array  $stringDelimiters
198:      * @param int    &$i
199:      * @param bool   $evaluate
200:      * @param array  $references
201:      *
202:      * @return string A YAML string
203:      *
204:      * @throws ParseException When malformed inline YAML string is parsed
205:      */
206:     public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
207:     {
208:         if (in_array($scalar[$i], $stringDelimiters)) {
209:             // quoted scalar
210:             $output = self::parseQuotedScalar($scalar, $i);
211: 
212:             if (null !== $delimiters) {
213:                 $tmp = ltrim(substr($scalar, $i), ' ');
214:                 if (!in_array($tmp[0], $delimiters)) {
215:                     throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
216:                 }
217:             }
218:         } else {
219:             // "normal" string
220:             if (!$delimiters) {
221:                 $output = substr($scalar, $i);
222:                 $i += strlen($output);
223: 
224:                 // remove comments
225:                 if (false !== $strpos = strpos($output, ' #')) {
226:                     $output = rtrim(substr($output, 0, $strpos));
227:                 }
228:             } elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
229:                 $output = $match[1];
230:                 $i += strlen($output);
231:             } else {
232:                 throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
233:             }
234: 
235:             if ($evaluate) {
236:                 $output = self::evaluateScalar($output, $references);
237:             }
238:         }
239: 
240:         return $output;
241:     }
242: 
243:     /**
244:      * Parses a quoted scalar to YAML.
245:      *
246:      * @param string $scalar
247:      * @param int    &$i
248:      *
249:      * @return string A YAML string
250:      *
251:      * @throws ParseException When malformed inline YAML string is parsed
252:      */
253:     private static function parseQuotedScalar($scalar, &$i)
254:     {
255:         if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
256:             throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
257:         }
258: 
259:         $output = substr($match[0], 1, strlen($match[0]) - 2);
260: 
261:         $unescaper = new Unescaper();
262:         if ('"' == $scalar[$i]) {
263:             $output = $unescaper->unescapeDoubleQuotedString($output);
264:         } else {
265:             $output = $unescaper->unescapeSingleQuotedString($output);
266:         }
267: 
268:         $i += strlen($match[0]);
269: 
270:         return $output;
271:     }
272: 
273:     /**
274:      * Parses a sequence to a YAML string.
275:      *
276:      * @param string $sequence
277:      * @param int    &$i
278:      * @param array  $references
279:      *
280:      * @return string A YAML string
281:      *
282:      * @throws ParseException When malformed inline YAML string is parsed
283:      */
284:     private static function parseSequence($sequence, &$i = 0, $references = array())
285:     {
286:         $output = array();
287:         $len = strlen($sequence);
288:         $i += 1;
289: 
290:         // [foo, bar, ...]
291:         while ($i < $len) {
292:             switch ($sequence[$i]) {
293:                 case '[':
294:                     // nested sequence
295:                     $output[] = self::parseSequence($sequence, $i, $references);
296:                     break;
297:                 case '{':
298:                     // nested mapping
299:                     $output[] = self::parseMapping($sequence, $i, $references);
300:                     break;
301:                 case ']':
302:                     return $output;
303:                 case ',':
304:                 case ' ':
305:                     break;
306:                 default:
307:                     $isQuoted = in_array($sequence[$i], array('"', "'"));
308:                     $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i, true, $references);
309: 
310:                     // the value can be an array if a reference has been resolved to an array var
311:                     if (!is_array($value) && !$isQuoted && false !== strpos($value, ': ')) {
312:                         // embedded mapping?
313:                         try {
314:                             $pos = 0;
315:                             $value = self::parseMapping('{'.$value.'}', $pos, $references);
316:                         } catch (\InvalidArgumentException $e) {
317:                             // no, it's not
318:                         }
319:                     }
320: 
321:                     $output[] = $value;
322: 
323:                     --$i;
324:             }
325: 
326:             ++$i;
327:         }
328: 
329:         throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
330:     }
331: 
332:     /**
333:      * Parses a mapping to a YAML string.
334:      *
335:      * @param string $mapping
336:      * @param int    &$i
337:      * @param array  $references
338:      *
339:      * @return string A YAML string
340:      *
341:      * @throws ParseException When malformed inline YAML string is parsed
342:      */
343:     private static function parseMapping($mapping, &$i = 0, $references = array())
344:     {
345:         $output = array();
346:         $len = strlen($mapping);
347:         $i += 1;
348: 
349:         // {foo: bar, bar:foo, ...}
350:         while ($i < $len) {
351:             switch ($mapping[$i]) {
352:                 case ' ':
353:                 case ',':
354:                     ++$i;
355:                     continue 2;
356:                 case '}':
357:                     if (self::$objectForMap) {
358:                         return (object) $output;
359:                     }
360: 
361:                     return $output;
362:             }
363: 
364:             // key
365:             $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
366: 
367:             // value
368:             $done = false;
369: 
370:             while ($i < $len) {
371:                 switch ($mapping[$i]) {
372:                     case '[':
373:                         // nested sequence
374:                         $value = self::parseSequence($mapping, $i, $references);
375:                         // Spec: Keys MUST be unique; first one wins.
376:                         // Parser cannot abort this mapping earlier, since lines
377:                         // are processed sequentially.
378:                         if (!isset($output[$key])) {
379:                             $output[$key] = $value;
380:                         }
381:                         $done = true;
382:                         break;
383:                     case '{':
384:                         // nested mapping
385:                         $value = self::parseMapping($mapping, $i, $references);
386:                         // Spec: Keys MUST be unique; first one wins.
387:                         // Parser cannot abort this mapping earlier, since lines
388:                         // are processed sequentially.
389:                         if (!isset($output[$key])) {
390:                             $output[$key] = $value;
391:                         }
392:                         $done = true;
393:                         break;
394:                     case ':':
395:                     case ' ':
396:                         break;
397:                     default:
398:                         $value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i, true, $references);
399:                         // Spec: Keys MUST be unique; first one wins.
400:                         // Parser cannot abort this mapping earlier, since lines
401:                         // are processed sequentially.
402:                         if (!isset($output[$key])) {
403:                             $output[$key] = $value;
404:                         }
405:                         $done = true;
406:                         --$i;
407:                 }
408: 
409:                 ++$i;
410: 
411:                 if ($done) {
412:                     continue 2;
413:                 }
414:             }
415:         }
416: 
417:         throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
418:     }
419: 
420:     /**
421:      * Evaluates scalars and replaces magic values.
422:      *
423:      * @param string $scalar
424:      * @param array  $references
425:      *
426:      * @return string A YAML string
427:      *
428:      * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
429:      */
430:     private static function evaluateScalar($scalar, $references = array())
431:     {
432:         $scalar = trim($scalar);
433:         $scalarLower = strtolower($scalar);
434: 
435:         if (0 === strpos($scalar, '*')) {
436:             if (false !== $pos = strpos($scalar, '#')) {
437:                 $value = substr($scalar, 1, $pos - 2);
438:             } else {
439:                 $value = substr($scalar, 1);
440:             }
441: 
442:             // an unquoted *
443:             if (false === $value || '' === $value) {
444:                 throw new ParseException('A reference must contain at least one character.');
445:             }
446: 
447:             if (!array_key_exists($value, $references)) {
448:                 throw new ParseException(sprintf('Reference "%s" does not exist.', $value));
449:             }
450: 
451:             return $references[$value];
452:         }
453: 
454:         switch (true) {
455:             case 'null' === $scalarLower:
456:             case '' === $scalar:
457:             case '~' === $scalar:
458:                 return;
459:             case 'true' === $scalarLower:
460:                 return true;
461:             case 'false' === $scalarLower:
462:                 return false;
463:             // Optimise for returning strings.
464:             case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]):
465:                 switch (true) {
466:                     case 0 === strpos($scalar, '!str'):
467:                         return (string) substr($scalar, 5);
468:                     case 0 === strpos($scalar, '! '):
469:                         return intval(self::parseScalar(substr($scalar, 2)));
470:                     case 0 === strpos($scalar, '!!php/object:'):
471:                         if (self::$objectSupport) {
472:                             return unserialize(substr($scalar, 13));
473:                         }
474: 
475:                         if (self::$exceptionOnInvalidType) {
476:                             throw new ParseException('Object support when parsing a YAML file has been disabled.');
477:                         }
478: 
479:                         return;
480:                     case 0 === strpos($scalar, '!!float '):
481:                         return (float) substr($scalar, 8);
482:                     case ctype_digit($scalar):
483:                         $raw = $scalar;
484:                         $cast = intval($scalar);
485: 
486:                         return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
487:                     case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
488:                         $raw = $scalar;
489:                         $cast = intval($scalar);
490: 
491:                         return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
492:                     case is_numeric($scalar):
493:                         return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
494:                     case '.inf' === $scalarLower:
495:                     case '.nan' === $scalarLower:
496:                         return -log(0);
497:                     case '-.inf' === $scalarLower:
498:                         return log(0);
499:                     case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
500:                         return floatval(str_replace(',', '', $scalar));
501:                     case preg_match(self::getTimestampRegex(), $scalar):
502:                         return strtotime($scalar);
503:                 }
504:             default:
505:                 return (string) $scalar;
506:         }
507:     }
508: 
509:     /**
510:      * Gets a regex that matches a YAML date.
511:      *
512:      * @return string The regular expression
513:      *
514:      * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
515:      */
516:     private static function getTimestampRegex()
517:     {
518:         return <<<EOF
519:         ~^
520:         (?P<year>[0-9][0-9][0-9][0-9])
521:         -(?P<month>[0-9][0-9]?)
522:         -(?P<day>[0-9][0-9]?)
523:         (?:(?:[Tt]|[ \t]+)
524:         (?P<hour>[0-9][0-9]?)
525:         :(?P<minute>[0-9][0-9])
526:         :(?P<second>[0-9][0-9])
527:         (?:\.(?P<fraction>[0-9]*))?
528:         (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
529:         (?::(?P<tz_minute>[0-9][0-9]))?))?)?
530:         $~x
531: EOF;
532:     }
533: }
534: 
Omnipay Fat Zebra / Paystream Gateway Module API Documentation API documentation generated by ApiGen