source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/Symfony/Component/Yaml/Inline.php @ 345

Last change on this file since 345 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 12.2 KB
Line 
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
11namespace Symfony\Component\Yaml;
12
13use Symfony\Component\Yaml\Exception\ParseException;
14use 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 */
21class Inline
22{
23    const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
24
25    /**
26     * Converts a YAML string to a PHP array.
27     *
28     * @param string $value A YAML string
29     *
30     * @return array A PHP array representing the YAML string
31     */
32    static public function parse($value)
33    {
34        $value = trim($value);
35
36        if (0 == strlen($value)) {
37            return '';
38        }
39
40        if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
41            $mbEncoding = mb_internal_encoding();
42            mb_internal_encoding('ASCII');
43        }
44
45        switch ($value[0]) {
46            case '[':
47                $result = self::parseSequence($value);
48                break;
49            case '{':
50                $result = self::parseMapping($value);
51                break;
52            default:
53                $result = self::parseScalar($value);
54        }
55
56        if (isset($mbEncoding)) {
57            mb_internal_encoding($mbEncoding);
58        }
59
60        return $result;
61    }
62
63    /**
64     * Dumps a given PHP variable to a YAML string.
65     *
66     * @param mixed $value The PHP variable to convert
67     *
68     * @return string The YAML string representing the PHP array
69     *
70     * @throws DumpException When trying to dump PHP resource
71     */
72    static public function dump($value)
73    {
74        switch (true) {
75            case is_resource($value):
76                throw new DumpException('Unable to dump PHP resources in a YAML file.');
77            case is_object($value):
78                return '!!php/object:'.serialize($value);
79            case is_array($value):
80                return self::dumpArray($value);
81            case null === $value:
82                return 'null';
83            case true === $value:
84                return 'true';
85            case false === $value:
86                return 'false';
87            case ctype_digit($value):
88                return is_string($value) ? "'$value'" : (int) $value;
89            case is_numeric($value):
90                return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
91            case Escaper::requiresDoubleQuoting($value):
92                return Escaper::escapeWithDoubleQuotes($value);
93            case Escaper::requiresSingleQuoting($value):
94                return Escaper::escapeWithSingleQuotes($value);
95            case '' == $value:
96                return "''";
97            case preg_match(self::getTimestampRegex(), $value):
98            case in_array(strtolower($value), array('null', '~', 'true', 'false')):
99                return "'$value'";
100            default:
101                return $value;
102        }
103    }
104
105    /**
106     * Dumps a PHP array to a YAML string.
107     *
108     * @param array $value The PHP array to dump
109     *
110     * @return string The YAML string representing the PHP array
111     */
112    static private function dumpArray($value)
113    {
114        // array
115        $keys = array_keys($value);
116        if ((1 == count($keys) && '0' == $keys[0])
117            || (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)
118        ) {
119            $output = array();
120            foreach ($value as $val) {
121                $output[] = self::dump($val);
122            }
123
124            return sprintf('[%s]', implode(', ', $output));
125        }
126
127        // mapping
128        $output = array();
129        foreach ($value as $key => $val) {
130            $output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
131        }
132
133        return sprintf('{ %s }', implode(', ', $output));
134    }
135
136    /**
137     * Parses a scalar to a YAML string.
138     *
139     * @param scalar  $scalar
140     * @param string  $delimiters
141     * @param array   $stringDelimiters
142     * @param integer &$i
143     * @param Boolean $evaluate
144     *
145     * @return string A YAML string
146     *
147     * @throws ParseException When malformed inline YAML string is parsed
148     */
149    static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
150    {
151        if (in_array($scalar[$i], $stringDelimiters)) {
152            // quoted scalar
153            $output = self::parseQuotedScalar($scalar, $i);
154        } else {
155            // "normal" string
156            if (!$delimiters) {
157                $output = substr($scalar, $i);
158                $i += strlen($output);
159
160                // remove comments
161                if (false !== $strpos = strpos($output, ' #')) {
162                    $output = rtrim(substr($output, 0, $strpos));
163                }
164            } else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
165                $output = $match[1];
166                $i += strlen($output);
167            } else {
168                throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
169            }
170
171            $output = $evaluate ? self::evaluateScalar($output) : $output;
172        }
173
174        return $output;
175    }
176
177    /**
178     * Parses a quoted scalar to YAML.
179     *
180     * @param string  $scalar
181     * @param integer $i
182     *
183     * @return string A YAML string
184     *
185     * @throws ParseException When malformed inline YAML string is parsed
186     */
187    static private function parseQuotedScalar($scalar, &$i)
188    {
189        if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
190            throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
191        }
192
193        $output = substr($match[0], 1, strlen($match[0]) - 2);
194
195        $unescaper = new Unescaper();
196        if ('"' == $scalar[$i]) {
197            $output = $unescaper->unescapeDoubleQuotedString($output);
198        } else {
199            $output = $unescaper->unescapeSingleQuotedString($output);
200        }
201
202        $i += strlen($match[0]);
203
204        return $output;
205    }
206
207    /**
208     * Parses a sequence to a YAML string.
209     *
210     * @param string  $sequence
211     * @param integer $i
212     *
213     * @return string A YAML string
214     *
215     * @throws ParseException When malformed inline YAML string is parsed
216     */
217    static private function parseSequence($sequence, &$i = 0)
218    {
219        $output = array();
220        $len = strlen($sequence);
221        $i += 1;
222
223        // [foo, bar, ...]
224        while ($i < $len) {
225            switch ($sequence[$i]) {
226                case '[':
227                    // nested sequence
228                    $output[] = self::parseSequence($sequence, $i);
229                    break;
230                case '{':
231                    // nested mapping
232                    $output[] = self::parseMapping($sequence, $i);
233                    break;
234                case ']':
235                    return $output;
236                case ',':
237                case ' ':
238                    break;
239                default:
240                    $isQuoted = in_array($sequence[$i], array('"', "'"));
241                    $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
242
243                    if (!$isQuoted && false !== strpos($value, ': ')) {
244                        // embedded mapping?
245                        try {
246                            $value = self::parseMapping('{'.$value.'}');
247                        } catch (\InvalidArgumentException $e) {
248                            // no, it's not
249                        }
250                    }
251
252                    $output[] = $value;
253
254                    --$i;
255            }
256
257            ++$i;
258        }
259
260        throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
261    }
262
263    /**
264     * Parses a mapping to a YAML string.
265     *
266     * @param string  $mapping
267     * @param integer $i
268     *
269     * @return string A YAML string
270     *
271     * @throws ParseException When malformed inline YAML string is parsed
272     */
273    static private function parseMapping($mapping, &$i = 0)
274    {
275        $output = array();
276        $len = strlen($mapping);
277        $i += 1;
278
279        // {foo: bar, bar:foo, ...}
280        while ($i < $len) {
281            switch ($mapping[$i]) {
282                case ' ':
283                case ',':
284                    ++$i;
285                    continue 2;
286                case '}':
287                    return $output;
288            }
289
290            // key
291            $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
292
293            // value
294            $done = false;
295            while ($i < $len) {
296                switch ($mapping[$i]) {
297                    case '[':
298                        // nested sequence
299                        $output[$key] = self::parseSequence($mapping, $i);
300                        $done = true;
301                        break;
302                    case '{':
303                        // nested mapping
304                        $output[$key] = self::parseMapping($mapping, $i);
305                        $done = true;
306                        break;
307                    case ':':
308                    case ' ':
309                        break;
310                    default:
311                        $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
312                        $done = true;
313                        --$i;
314                }
315
316                ++$i;
317
318                if ($done) {
319                    continue 2;
320                }
321            }
322        }
323
324        throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
325    }
326
327    /**
328     * Evaluates scalars and replaces magic values.
329     *
330     * @param string $scalar
331     *
332     * @return string A YAML string
333     */
334    static private function evaluateScalar($scalar)
335    {
336        $scalar = trim($scalar);
337
338        switch (true) {
339            case 'null' == strtolower($scalar):
340            case '' == $scalar:
341            case '~' == $scalar:
342                return null;
343            case 0 === strpos($scalar, '!str'):
344                return (string) substr($scalar, 5);
345            case 0 === strpos($scalar, '! '):
346                return intval(self::parseScalar(substr($scalar, 2)));
347            case 0 === strpos($scalar, '!!php/object:'):
348                return unserialize(substr($scalar, 13));
349            case ctype_digit($scalar):
350                $raw = $scalar;
351                $cast = intval($scalar);
352
353                return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
354            case 'true' === strtolower($scalar):
355                return true;
356            case 'false' === strtolower($scalar):
357                return false;
358            case is_numeric($scalar):
359                return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
360            case 0 == strcasecmp($scalar, '.inf'):
361            case 0 == strcasecmp($scalar, '.NaN'):
362                return -log(0);
363            case 0 == strcasecmp($scalar, '-.inf'):
364                return log(0);
365            case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
366                return floatval(str_replace(',', '', $scalar));
367            case preg_match(self::getTimestampRegex(), $scalar):
368                return strtotime($scalar);
369            default:
370                return (string) $scalar;
371        }
372    }
373
374    /**
375     * Gets a regex that matches an unix timestamp
376     *
377     * @return string The regular expression
378     */
379    static private function getTimestampRegex()
380    {
381        return <<<EOF
382        ~^
383        (?P<year>[0-9][0-9][0-9][0-9])
384        -(?P<month>[0-9][0-9]?)
385        -(?P<day>[0-9][0-9]?)
386        (?:(?:[Tt]|[ \t]+)
387        (?P<hour>[0-9][0-9]?)
388        :(?P<minute>[0-9][0-9])
389        :(?P<second>[0-9][0-9])
390        (?:\.(?P<fraction>[0-9]*))?
391        (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
392        (?::(?P<tz_minute>[0-9][0-9]))?))?)?
393        $~x
394EOF;
395    }
396}
Note: See TracBrowser for help on using the repository browser.