Overview

Namespaces

  • Contrib
    • Bundle
      • CoverallsBundle
        • Console
        • Entity
      • CoverallsV1Bundle
        • Api
        • Collector
        • Command
        • Config
        • Entity
          • Git
    • Component
      • File
      • Log
      • System
        • Git
  • Guzzle
    • Batch
      • Exception
    • Cache
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
      • QueryAggregator
    • Inflection
    • Iterator
    • Log
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Async
      • Backoff
      • Cache
      • Cookie
        • CookieJar
        • Exception
      • CurlAuth
      • ErrorResponse
        • Exception
      • History
      • Log
      • Md5
      • Mock
      • Oauth
    • Service
      • Builder
      • Command
        • Factory
        • LocationVisitor
          • Request
          • Response
      • Description
      • Exception
      • Resource
    • Stream
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Config
        • Definition
          • Builder
          • Exception
        • Exception
        • Loader
        • Resource
        • Util
      • Console
        • Command
        • Formatter
        • Helper
        • Input
        • Output
        • Tester
      • EventDispatcher
        • Debug
      • Finder
        • Adapter
        • Comparator
        • Exception
        • Expression
        • Iterator
        • Shell
      • Stopwatch
      • Yaml
        • Exception

Classes

  • Dumper
  • Escaper
  • Inline
  • Parser
  • Unescaper
  • Yaml
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: /*
  4:  * This file is part of the Symfony package.
  5:  * (c) Fabien Potencier <fabien@symfony.com>
  6:  *
  7:  * For the full copyright and license information, please view the LICENSE
  8:  * file that was distributed with this source code.
  9:  */
 10: 
 11: namespace Symfony\Component\Yaml;
 12: 
 13: use Symfony\Component\Yaml\Exception\ParseException;
 14: use Symfony\Component\Yaml\Exception\DumpException;
 15: 
 16: /**
 17:  * Inline implements a YAML parser/dumper for the YAML inline syntax.
 18:  *
 19:  * @author Fabien Potencier <fabien@symfony.com>
 20:  */
 21: class Inline
 22: {
 23:     const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
 24: 
 25:     private static $exceptionOnInvalidType = false;
 26:     private static $objectSupport = false;
 27: 
 28:     /**
 29:      * Converts a YAML string to a PHP array.
 30:      *
 31:      * @param string  $value                  A YAML string
 32:      * @param Boolean $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
 33:      * @param Boolean $objectSupport          true if object support is enabled, false otherwise
 34:      *
 35:      * @return array A PHP array representing the YAML string
 36:      *
 37:      * @throws ParseException
 38:      */
 39:     public static function parse($value, $exceptionOnInvalidType = false, $objectSupport = false)
 40:     {
 41:         self::$exceptionOnInvalidType = $exceptionOnInvalidType;
 42:         self::$objectSupport = $objectSupport;
 43: 
 44:         $value = trim($value);
 45: 
 46:         if (0 == strlen($value)) {
 47:             return '';
 48:         }
 49: 
 50:         if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
 51:             $mbEncoding = mb_internal_encoding();
 52:             mb_internal_encoding('ASCII');
 53:         }
 54: 
 55:         $i = 0;
 56:         switch ($value[0]) {
 57:             case '[':
 58:                 $result = self::parseSequence($value, $i);
 59:                 ++$i;
 60:                 break;
 61:             case '{':
 62:                 $result = self::parseMapping($value, $i);
 63:                 ++$i;
 64:                 break;
 65:             default:
 66:                 $result = self::parseScalar($value, null, array('"', "'"), $i);
 67:         }
 68: 
 69:         // some comments are allowed at the end
 70:         if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
 71:             throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)));
 72:         }
 73: 
 74:         if (isset($mbEncoding)) {
 75:             mb_internal_encoding($mbEncoding);
 76:         }
 77: 
 78:         return $result;
 79:     }
 80: 
 81:     /**
 82:      * Dumps a given PHP variable to a YAML string.
 83:      *
 84:      * @param mixed   $value                  The PHP variable to convert
 85:      * @param Boolean $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
 86:      * @param Boolean $objectSupport          true if object support is enabled, false otherwise
 87:      *
 88:      * @return string The YAML string representing the PHP array
 89:      *
 90:      * @throws DumpException When trying to dump PHP resource
 91:      */
 92:     public static function dump($value, $exceptionOnInvalidType = false, $objectSupport = false)
 93:     {
 94:         switch (true) {
 95:             case is_resource($value):
 96:                 if ($exceptionOnInvalidType) {
 97:                     throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
 98:                 }
 99: 
100:                 return 'null';
101:             case is_object($value):
102:                 if ($objectSupport) {
103:                     return '!!php/object:'.serialize($value);
104:                 }
105: 
106:                 if ($exceptionOnInvalidType) {
107:                     throw new DumpException('Object support when dumping a YAML file has been disabled.');
108:                 }
109: 
110:                 return 'null';
111:             case is_array($value):
112:                 return self::dumpArray($value, $exceptionOnInvalidType, $objectSupport);
113:             case null === $value:
114:                 return 'null';
115:             case true === $value:
116:                 return 'true';
117:             case false === $value:
118:                 return 'false';
119:             case ctype_digit($value):
120:                 return is_string($value) ? "'$value'" : (int) $value;
121:             case is_numeric($value):
122:                 $locale = setlocale(LC_NUMERIC, 0);
123:                 if (false !== $locale) {
124:                     setlocale(LC_NUMERIC, 'C');
125:                 }
126:                 $repr = is_string($value) ? "'$value'" : (is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : strval($value));
127: 
128:                 if (false !== $locale) {
129:                     setlocale(LC_NUMERIC, $locale);
130:                 }
131: 
132:                 return $repr;
133:             case Escaper::requiresDoubleQuoting($value):
134:                 return Escaper::escapeWithDoubleQuotes($value);
135:             case Escaper::requiresSingleQuoting($value):
136:                 return Escaper::escapeWithSingleQuotes($value);
137:             case '' == $value:
138:                 return "''";
139:             case preg_match(self::getTimestampRegex(), $value):
140:             case in_array(strtolower($value), array('null', '~', 'true', 'false')):
141:                 return "'$value'";
142:             default:
143:                 return $value;
144:         }
145:     }
146: 
147:     /**
148:      * Dumps a PHP array to a YAML string.
149:      *
150:      * @param array   $value                  The PHP array to dump
151:      * @param Boolean $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
152:      * @param Boolean $objectSupport          true if object support is enabled, false otherwise
153:      *
154:      * @return string The YAML string representing the PHP array
155:      */
156:     private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
157:     {
158:         // array
159:         $keys = array_keys($value);
160:         if ((1 == count($keys) && '0' == $keys[0])
161:             || (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)
162:         ) {
163:             $output = array();
164:             foreach ($value as $val) {
165:                 $output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
166:             }
167: 
168:             return sprintf('[%s]', implode(', ', $output));
169:         }
170: 
171:         // mapping
172:         $output = array();
173:         foreach ($value as $key => $val) {
174:             $output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
175:         }
176: 
177:         return sprintf('{ %s }', implode(', ', $output));
178:     }
179: 
180:     /**
181:      * Parses a scalar to a YAML string.
182:      *
183:      * @param scalar $scalar
184:      * @param string $delimiters
185:      * @param array  $stringDelimiters
186:      * @param integer &$i
187:      * @param Boolean $evaluate
188:      *
189:      * @return string A YAML string
190:      *
191:      * @throws ParseException When malformed inline YAML string is parsed
192:      */
193:     public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
194:     {
195:         if (in_array($scalar[$i], $stringDelimiters)) {
196:             // quoted scalar
197:             $output = self::parseQuotedScalar($scalar, $i);
198: 
199:             if (null !== $delimiters) {
200:                 $tmp = ltrim(substr($scalar, $i), ' ');
201:                 if (!in_array($tmp[0], $delimiters)) {
202:                     throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
203:                 }
204:             }
205:         } else {
206:             // "normal" string
207:             if (!$delimiters) {
208:                 $output = substr($scalar, $i);
209:                 $i += strlen($output);
210: 
211:                 // remove comments
212:                 if (false !== $strpos = strpos($output, ' #')) {
213:                     $output = rtrim(substr($output, 0, $strpos));
214:                 }
215:             } elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
216:                 $output = $match[1];
217:                 $i += strlen($output);
218:             } else {
219:                 throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
220:             }
221: 
222:             $output = $evaluate ? self::evaluateScalar($output) : $output;
223:         }
224: 
225:         return $output;
226:     }
227: 
228:     /**
229:      * Parses a quoted scalar to YAML.
230:      *
231:      * @param string $scalar
232:      * @param integer &$i
233:      *
234:      * @return string A YAML string
235:      *
236:      * @throws ParseException When malformed inline YAML string is parsed
237:      */
238:     private static function parseQuotedScalar($scalar, &$i)
239:     {
240:         if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
241:             throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
242:         }
243: 
244:         $output = substr($match[0], 1, strlen($match[0]) - 2);
245: 
246:         $unescaper = new Unescaper();
247:         if ('"' == $scalar[$i]) {
248:             $output = $unescaper->unescapeDoubleQuotedString($output);
249:         } else {
250:             $output = $unescaper->unescapeSingleQuotedString($output);
251:         }
252: 
253:         $i += strlen($match[0]);
254: 
255:         return $output;
256:     }
257: 
258:     /**
259:      * Parses a sequence to a YAML string.
260:      *
261:      * @param string $sequence
262:      * @param integer &$i
263:      *
264:      * @return string A YAML string
265:      *
266:      * @throws ParseException When malformed inline YAML string is parsed
267:      */
268:     private static function parseSequence($sequence, &$i = 0)
269:     {
270:         $output = array();
271:         $len = strlen($sequence);
272:         $i += 1;
273: 
274:         // [foo, bar, ...]
275:         while ($i < $len) {
276:             switch ($sequence[$i]) {
277:                 case '[':
278:                     // nested sequence
279:                     $output[] = self::parseSequence($sequence, $i);
280:                     break;
281:                 case '{':
282:                     // nested mapping
283:                     $output[] = self::parseMapping($sequence, $i);
284:                     break;
285:                 case ']':
286:                     return $output;
287:                 case ',':
288:                 case ' ':
289:                     break;
290:                 default:
291:                     $isQuoted = in_array($sequence[$i], array('"', "'"));
292:                     $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
293: 
294:                     if (!$isQuoted && false !== strpos($value, ': ')) {
295:                         // embedded mapping?
296:                         try {
297:                             $value = self::parseMapping('{'.$value.'}');
298:                         } catch (\InvalidArgumentException $e) {
299:                             // no, it's not
300:                         }
301:                     }
302: 
303:                     $output[] = $value;
304: 
305:                     --$i;
306:             }
307: 
308:             ++$i;
309:         }
310: 
311:         throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
312:     }
313: 
314:     /**
315:      * Parses a mapping to a YAML string.
316:      *
317:      * @param string $mapping
318:      * @param integer &$i
319:      *
320:      * @return string A YAML string
321:      *
322:      * @throws ParseException When malformed inline YAML string is parsed
323:      */
324:     private static function parseMapping($mapping, &$i = 0)
325:     {
326:         $output = array();
327:         $len = strlen($mapping);
328:         $i += 1;
329: 
330:         // {foo: bar, bar:foo, ...}
331:         while ($i < $len) {
332:             switch ($mapping[$i]) {
333:                 case ' ':
334:                 case ',':
335:                     ++$i;
336:                     continue 2;
337:                 case '}':
338:                     return $output;
339:             }
340: 
341:             // key
342:             $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
343: 
344:             // value
345:             $done = false;
346:             while ($i < $len) {
347:                 switch ($mapping[$i]) {
348:                     case '[':
349:                         // nested sequence
350:                         $output[$key] = self::parseSequence($mapping, $i);
351:                         $done = true;
352:                         break;
353:                     case '{':
354:                         // nested mapping
355:                         $output[$key] = self::parseMapping($mapping, $i);
356:                         $done = true;
357:                         break;
358:                     case ':':
359:                     case ' ':
360:                         break;
361:                     default:
362:                         $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
363:                         $done = true;
364:                         --$i;
365:                 }
366: 
367:                 ++$i;
368: 
369:                 if ($done) {
370:                     continue 2;
371:                 }
372:             }
373:         }
374: 
375:         throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
376:     }
377: 
378:     /**
379:      * Evaluates scalars and replaces magic values.
380:      *
381:      * @param string $scalar
382:      *
383:      * @return string A YAML string
384:      */
385:     private static function evaluateScalar($scalar)
386:     {
387:         $scalar = trim($scalar);
388: 
389:         switch (true) {
390:             case 'null' == strtolower($scalar):
391:             case '' == $scalar:
392:             case '~' == $scalar:
393:                 return null;
394:             case 0 === strpos($scalar, '!str'):
395:                 return (string) substr($scalar, 5);
396:             case 0 === strpos($scalar, '! '):
397:                 return intval(self::parseScalar(substr($scalar, 2)));
398:             case 0 === strpos($scalar, '!!php/object:'):
399:                 if (self::$objectSupport) {
400:                     return unserialize(substr($scalar, 13));
401:                 }
402: 
403:                 if (self::$exceptionOnInvalidType) {
404:                     throw new ParseException('Object support when parsing a YAML file has been disabled.');
405:                 }
406: 
407:                 return null;
408:             case ctype_digit($scalar):
409:                 $raw = $scalar;
410:                 $cast = intval($scalar);
411: 
412:                 return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
413:             case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
414:                 $raw = $scalar;
415:                 $cast = intval($scalar);
416: 
417:                 return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
418:             case 'true' === strtolower($scalar):
419:                 return true;
420:             case 'false' === strtolower($scalar):
421:                 return false;
422:             case is_numeric($scalar):
423:                 return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
424:             case 0 == strcasecmp($scalar, '.inf'):
425:             case 0 == strcasecmp($scalar, '.NaN'):
426:                 return -log(0);
427:             case 0 == strcasecmp($scalar, '-.inf'):
428:                 return log(0);
429:             case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
430:                 return floatval(str_replace(',', '', $scalar));
431:             case preg_match(self::getTimestampRegex(), $scalar):
432:                 return strtotime($scalar);
433:             default:
434:                 return (string) $scalar;
435:         }
436:     }
437: 
438:     /**
439:      * Gets a regex that matches a YAML date.
440:      *
441:      * @return string The regular expression
442:      *
443:      * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
444:      */
445:     private static function getTimestampRegex()
446:     {
447:         return <<<EOF
448:         ~^
449:         (?P<year>[0-9][0-9][0-9][0-9])
450:         -(?P<month>[0-9][0-9]?)
451:         -(?P<day>[0-9][0-9]?)
452:         (?:(?:[Tt]|[ \t]+)
453:         (?P<hour>[0-9][0-9]?)
454:         :(?P<minute>[0-9][0-9])
455:         :(?P<second>[0-9][0-9])
456:         (?:\.(?P<fraction>[0-9]*))?
457:         (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
458:         (?::(?P<tz_minute>[0-9][0-9]))?))?)?
459:         $~x
460: EOF;
461:     }
462: }
463: 
php-coveralls API documentation generated by ApiGen 2.8.0