Browse Source

Suppression de la librairie obsolète sfYaml

master v3.0.2
Eric Lupinacci 1 week ago
parent
commit
18510f66eb
  1. 95
      demo/formulaire-contact-sfyaml.yaml
  2. 222
      demo/test_sfyaml.yaml
  3. 1
      demo/yaml.html
  4. 2
      demo/yaml_fonctions.php
  5. 81
      inc/sfyaml.php
  6. 11
      inc/yaml.php
  7. 137
      sfyaml/sfYaml.php
  8. 74
      sfyaml/sfYamlDumper.php
  9. 409
      sfyaml/sfYamlInline.php
  10. 536
      sfyaml/sfYamlParser.php

95
demo/formulaire-contact-sfyaml.yaml

File diff suppressed because one or more lines are too long

222
demo/test_sfyaml.yaml

@ -1,222 +0,0 @@
#
# S P Y C
# a simple php yaml class
#
# authors: [vlad andersen (vlad.andersen@gmail.com), chris wanstrath (chris@ozmm.org)]
# websites: [http://www.yaml.org, http://spyc.sourceforge.net/]
# license: [MIT License, http://www.opensource.org/licenses/mit-license.php]
# copyright: (c) 2005-2006 Chris Wanstrath, 2006-2014 Vlad Andersen
#
# spyc.yaml - A file containing the YAML that Spyc understands.
#
# ----------------------------------------------------------------------------------------
# Tests pour la librairie sfyaml : les cas qui ne fonctionnent pas sont mis en commentaire
#---
# Mappings - with proper types
String: Anyone's name, really.
Int: 13
BadHex: f0xf3
Hex: 0xf3
True: true
False: false
Zero: 0
Null: NULL
NotNull: 'null'
NotTrue: 'y'
NotBoolTrue: 'true'
NotInt: '5'
Float: 5.34
Negative: -90
SmallFloat: 0.7
NewLine: \n
QuotedNewLine: "\n"
# A sequence
- PHP Class
- Basic YAML Loader
- Very Basic YAML Dumper
# A sequence of a sequence
-
- YAML is so easy to learn.
- Your config files will never be the same.
# Sequence of mappings
-
cpu: 1.5ghz
ram: 1 gig
os : os x 10.4.1
# Mapped sequence
domains:
- yaml.org
- php.net
# A sequence like this.
- program: Adium
platform: OS X
type: Chat Client
# A folded block as a mapped value
no time: >
There isn't any time
for your tricks!
Do you understand?
# A literal block as a mapped value
some time: |
There is nothing but time
for your tricks.
# Crazy combinations
databases:
- name: spartan
notes:
- Needs to be backed up
- Needs to be normalized
type: mysql
# You can be a bit tricky
"if: you'd": like
# Inline sequences
- [One, Two, Three, Four]
# Nested Inline Sequences
- [One, [Two, And, Three], Four, Five]
# Nested Nested Inline Sequences
- [This, [Is, Getting, [Ridiculous, Guys]], Seriously, [Show, Mercy]]
# Inline mappings
- {name: chris, age: young, brand: lucky strike}
# Nested inline mappings
- {name: mark, age: older than chris, brand: [marlboro, lucky strike]}
# References -- they're shaky, but functional
dynamic languages: &DLANGS
- Perl
- Python
- PHP
- Ruby
compiled languages: &CLANGS
- C/C++
- Java
all languages:
- *DLANGS
- *CLANGS
# Added in .2.2: Escaped quotes
- you know, this shouldn't work. but it does.
- 'that''s my value.'
- 'again, that\'s my value.'
- "here's to \"quotes\", boss."
# added in .2.3
- {name: "Foo, Bar's", age: 20}
# Added in .2.4: bug [ 1418193 ] Quote Values in Nested Arrays
- [a, ['1', "2"], b]
# Add in .5.2: Quoted new line values.
- "First line\nSecond line\nThird line"
# Added in .2.4: malformed YAML
#all
# javascripts: [dom1.js, dom.js]
# Added in .2
1040: Ooo, a numeric key! # And working comments? Wow! Colons in comments: a menace (0.3).
hash_1: Hash #and a comment
hash_2: "Hash #and a comment"
"hash#3": "Hash (#) can appear in key too"
float_test: 1.0
float_test_with_quotes: '1.0'
float_inverse_test: 001
a_really_large_number: 115792089237316195423570985008687907853269984665640564039457584007913129639936 # 2^256
int array: [ 1, 2, 3 ]
#array on several lines:
# [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
# 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
morelesskey: "<value>"
array_of_zero: [0]
sophisticated_array_of_zero: {rx: {tx: [0]} }
switches:
- { row: 0, col: 0, func: {tx: [0, 1]} }
empty_sequence: [ ]
empty_hash: { }
special_characters: "[{]]{{]]"
asterisks: "*"
#empty_key:
# :
# key: value
trailing_colon: "foo:"
#multiline_items:
# - type: SomeItem
# values: [blah, blah, blah,
# blah]
# ints: [2, 54, 12,
# 2143]
many_lines: |
A quick
fox
jumped
over
a lazy
dog
werte:
1: nummer 1
0: Stunde 0
noindent_records:
- record1: value1
- record2: value2
"a:1": [1000]
"a:2":
- 2000
a:3: [3000]
complex_unquoted_key:
a:b:''test': value
array with commas:
["0","1"]
invoice: ["Something", "", '', "Something else"]
quotes: ['Something', "Nothing", 'Anything', "Thing"]
# [Endloop]
endloop: |
Does this line in the end indeed make Spyc go to an infinite loop?

1
demo/yaml.html

@ -34,7 +34,6 @@
}
#SET{menu_librairies,
#ARRAY{
sfyaml, Symfony YAML v1,
symfony, Symfony YAML v4,
spyc, Spyc
}

2
demo/yaml_fonctions.php

@ -25,7 +25,7 @@ function decoder_fichier_yaml($filename, $options = []) {
$duree = ($timestamp_fin - $timestamp_debut) * 1000;
return [
'lib' => sinon($options['library'], 'sfyaml'),
'lib' => sinon($options['library'], 'symfony'),
'fichier' => $file,
'duree' => $duree . ' ms',
'yaml' => $parsed,

81
inc/sfyaml.php

@ -1,81 +0,0 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Encode une structure de données PHP en une chaîne YAML.
* Utilise pour cela la librairie symfony/yaml (branche v1) qui n'est plus maintenue mais
* conservée par souci de compatibilité.
*
* @param mixed $structure
* Structure PHP, tableau, chaine... à convertir en YAML.
* @param array $options
* Tableau associatif des options du dump. Cette librairie accepte:
* - 'inline' : niveau à partir duquel la présentation du YAML devient inline, 2 par défaut.
* - 'indent' : nombre d'espaces pour chaque niveau d'indentation, 2 par défaut.
*
* @return string
* Chaîne YAML construite.
*/
function sfyaml_yaml_encode($structure, $options = []) {
require_once _DIR_PLUGIN_YAML . 'sfyaml/sfYaml.php';
require_once _DIR_PLUGIN_YAML . 'sfyaml/sfYamlDumper.php';
// Traitement des options
if (empty($options['inline']) or (isset($options['inline']) and !is_int($options['inline']))) {
$options['inline'] = 3;
}
if (empty($options['indent']) or (isset($options['indent']) and !is_int($options['indent']))) {
$options['indent'] = 2;
}
// On crée l'objet de dump avec le paramètre d'indentation.
$yaml = new sfYamlDumper($options['indent']);
return $yaml->dump($structure, $options['inline']);
}
/**
* Décode une chaîne YAML en une structure de données PHP adaptée.
* Utilise pour cela la librairie symfony/yaml (branche v1) qui n'est plus maintenue mais
* conservée par souci de compatibilité.
*
* @param string $input
* La chaîne YAML à décoder.
* @param array $options
* Tableau associatif des options du parsing. Cette librairie accepte:
* - 'show_error' : indicateur d'affichage des erreurs de parsing, false par défaut.
* @param bool $show_error
* Indicateur d'affichage des erreurs de parsing.
*
* @return bool|mixed
* Structure PHP produite par le parsing de la chaîne YAML.
*/
function sfyaml_yaml_decode($input, $options = []) {
require_once _DIR_PLUGIN_YAML . 'sfyaml/sfYaml.php';
require_once _DIR_PLUGIN_YAML . 'sfyaml/sfYamlParser.php';
// On crée l'objet de parsing.
$yaml = new sfYamlParser();
$parsed = false;
try {
$parsed = $yaml->parse($input);
} catch (Exception $exception) {
// On garde la compatibilité ascendante avec l'ancien argument $show_error qui a été remplacé par $options
// mais on inverse la valeur par défaut.
if ((is_bool($options) and $options) or (!empty($options['show_error']))) {
throw new InvalidArgumentException(sprintf('Unable to parse string: %s', $exception->getMessage()));
}
// Pour compenser l'absence par défaut d'erreurs, on loge l'erreur dans les logs SPIP.
spip_log("Erreur d'analyse YAML : " . $exception->getMessage(), 'yaml' . _LOG_ERREUR);
}
return $parsed;
}

11
inc/yaml.php

@ -4,20 +4,9 @@ if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
# textwheel fournit yaml_decode() aussi...
# include_spip('inc/yaml-mini');
# wrapper de la class sfYAML pour SPIP
#
# fournit deux fonctions pour YAML,
# analogues a json_encode() et json_decode
#
# Regle de dev: ne pas se rendre dependant de la lib sous-jacente
if (!defined('_LIB_YAML')) {
/**
* Les valeurs possibles sont :
* - 'sfyaml' pour l'ancienne librairie symfony v1 (compatibilité ascendante, par défaut)
* - 'symfony' pour le composant YAML le plus récent de Symfony
* - 'spyc' pour la librairie YAML spyc la plus récente
* - 'libyaml' pour le composant PECL basé sur la librairie libYAML écrite en C.

137
sfyaml/sfYaml.php

@ -1,137 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfYaml offers convenience methods to load and dump YAML.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $
* version 1.0.6 - plus maintenue
*/
class sfYaml
{
static protected $spec = '1.2';
/**
* Sets the YAML specification version to use.
*
* @param string $version The YAML specification version
*/
public static function setSpecVersion($version) {
if (!in_array($version, ['1.1', '1.2'])) {
throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
}
self::$spec = $version;
}
/**
* Gets the YAML specification version to use.
*
* @return string The YAML specification version
*/
public static function getSpecVersion() {
return self::$spec;
}
/**
* Loads YAML into a PHP array.
*
* The load method, when supplied with a YAML stream (string or file),
* will do its best to convert YAML in a file into a PHP array.
*
* Usage:
* <code>
* $array = sfYaml::load('config.yml');
* print_r($array);
* </code>
*
* @param string $input Path of YAML file or string containing YAML
*
* @return array The YAML converted to a PHP array
*
* @throws InvalidArgumentException If the YAML is not valid
*/
public static function load($input) {
$file = '';
// if input is a file, load it
if (strpos($input, "\n") === false && is_file($input)) {
$file = $input;
$content = $yaml = file_get_contents($input);
// if the file contains valid PHP, process it
if (
strpos($content, '<' . '?') !== false
and !(defined('_YAML_EVAL_PHP') and !_YAML_EVAL_PHP)
) {
ob_start();
$retval = eval('?' . '>' . $yaml);
$content = ob_get_clean();
// syntax error?
if ($retval === false) {
$content = $yaml;
}
}
// if an array is returned by the config file assume it's in plain php form else in YAML
$input = is_array($retval) ? $retval : $content;
}
// if an array is returned by the config file assume it's in plain php form else in YAML
if (is_array($input)) {
return $input;
}
require_once dirname(__FILE__) . '/sfYamlParser.php';
$yaml = new sfYamlParser();
try {
$ret = $yaml->parse($input);
}
catch (Exception $e) {
throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
}
return $ret;
}
/**
* Dumps a PHP array to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param array $array PHP array
* @param integer $inline The level where you switch to inline YAML
*
* @return string A YAML string representing the original PHP array
*/
public static function dump($array, $inline = 2, $indent = 2) {
require_once dirname(__FILE__) . '/sfYamlDumper.php';
$yaml = new sfYamlDumper($indent);
return $yaml->dump($array, $inline, 0);
}
}
/**
* Wraps echo to automatically provide a newline.
*
* @param string $string The string to echo with new line
*/
function echoln($string) {
echo $string . "\n";
}

74
sfyaml/sfYamlDumper.php

@ -1,74 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once(dirname(__FILE__) . '/sfYamlInline.php');
/**
* sfYamlDumper dumps PHP variables to YAML strings.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $
*/
class sfYamlDumper
{
protected $indentation;
/**
* Set indentation on creation.
* @fork correction pour coincider avec le fonctionnement de symfony v4
* pas de risque car cette librairie n'évoluera plus
*
* @param integer $indent The amount of spaces to use for indentation of nested nodes.
*/
public function __construct($indentation = 2) {
if ($indentation < 1) {
$this->indentation = 2;
} else {
$this->indentation = $indentation;
}
}
/**
* Dumps a PHP value to YAML.
*
* @param mixed $input The PHP value
* @param integer $inline The level where you switch to inline YAML
* @param integer $indent The level o indentation (used internally)
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0) {
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
if ($inline <= 0 || !is_array($input) || empty($input)) {
$output .= $prefix . sfYamlInline::dump($input);
}
else {
$isAHash = array_keys($input) !== range(0, count($input) - 1);
foreach ($input as $key => $value) {
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
$output .= sprintf(
'%s%s%s%s',
$prefix,
$isAHash ? sfYamlInline::dump($key) . ':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation)
) . ($willBeInlined ? "\n" : '');
}
}
return $output;
}
}

409
sfyaml/sfYamlInline.php

@ -1,409 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/sfYaml.php';
/**
* sfYamlInline implements a YAML parser/dumper for the YAML inline syntax.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $
*/
class sfYamlInline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
/**
* Convert a YAML string to a PHP array.
*
* @param string $value A YAML string
*
* @return array A PHP array representing the YAML string
*/
public static function load($value) {
$value = trim($value);
if (0 == strlen($value)) {
return '';
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
switch ($value[0]) {
case '[':
$result = self::parseSequence($value);
break;
case '{':
$result = self::parseMapping($value);
break;
default:
$result = self::parseScalar($value);
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
*
* @return string The YAML string representing the PHP array
*/
public static function dump($value) {
if ('1.1' === sfYaml::getSpecVersion()) {
$trueValues = ['true', 'on', '+', 'yes', 'y'];
$falseValues = ['false', 'off', '-', 'no', 'n'];
}
else {
$trueValues = ['true'];
$falseValues = ['false'];
}
switch (true) {
case is_resource($value):
throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.');
case is_object($value):
return '!!php/object:' . serialize($value);
case is_array($value):
return self::dumpArray($value);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return is_string($value) ? "'$value'" : (int) $value;
case is_numeric($value):
return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
case false !== strpos($value, "\n") || false !== strpos($value, "\r"):
return sprintf('"%s"', str_replace(['"', "\n", "\r"], ['\\"', '\n', '\r'], $value));
case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value):
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
case '' == $value:
return "''";
case preg_match(self::getTimestampRegex(), $value):
return "'$value'";
case in_array(strtolower($value), $trueValues):
return "'$value'";
case in_array(strtolower($value), $falseValues):
return "'$value'";
case in_array(strtolower($value), ['null', '~']):
return "'$value'";
default:
return $value;
}
}
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
*
* @return string The YAML string representing the PHP array
*/
protected static function dumpArray($value) {
// array
$keys = array_keys($value);
if (
(1 == count($keys) && '0' == $keys[0])
||
(count($keys) > 1 && array_reduce($keys, function ($v, $w) {
return (int) $v + (int) $w;
}, 0) == count($keys) * (count($keys) - 1) / 2)
) {
$output = [];
foreach ($value as $val) {
$output[] = self::dump($val);
}
return sprintf('[%s]', implode(', ', $output));
}
// mapping
$output = [];
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
}
return sprintf('{ %s }', implode(', ', $output));
}
/**
* Parses a scalar to a YAML string.
*
* @param scalar $scalar
* @param string $delimiters
* @param array $stringDelimiter
* @param integer $i
* @param boolean $evaluate
*
* @return string A YAML string
*/
public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = ['"', "'"], &$i = 0, $evaluate = true) {
if (in_array($scalar[$i], $stringDelimiters)) {
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
}
else {
// "normal" string
if (!$delimiters) {
$output = substr($scalar, $i);
$i += strlen($output);
// remove comments
if (false !== $strpos = strpos($output, ' #')) {
$output = rtrim(substr($output, 0, $strpos));
}
}
elseif (preg_match('/^(.+?)(' . implode('|', $delimiters) . ')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += strlen($output);
}
else {
throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar));
}
$output = $evaluate ? self::evaluateScalar($output) : $output;
}
return $output;
}
/**
* Parses a quoted scalar to YAML.
*
* @param string $scalar
* @param integer $i
*
* @return string A YAML string
*/
protected static function parseQuotedScalar($scalar, &$i) {
if (!preg_match('/' . self::REGEX_QUOTED_STRING . '/Au', substr($scalar, $i), $match)) {
throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
if ('"' == $scalar[$i]) {
// evaluate the string
$output = str_replace(['\\"', '\\n', '\\r'], ['"', "\n", "\r"], $output);
if (strpos($output, '\\x') !== false) {
$output = preg_replace_callback(',\\\\x([0-9a-f]+),', function ($m) {
return chr(hexdec($m[1]));
}, $output);
}
}
else {
// unescape '
$output = str_replace('\'\'', '\'', $output);
}
$i += strlen($match[0]);
return $output;
}
/**
* Parses a sequence to a YAML string.
*
* @param string $sequence
* @param integer $i
*
* @return string A YAML string
*/
protected static function parseSequence($sequence, &$i = 0) {
$output = [];
$len = strlen($sequence);
$i += 1;
// [foo, bar, ...]
while ($i < $len) {
switch ($sequence[$i]) {
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = in_array($sequence[$i], ['"', "'"]);
$value = self::parseScalar($sequence, [',', ']'], ['"', "'"], $i);
if (!$isQuoted && false !== strpos($value, ': ')) {
// embedded mapping?
try {
$value = self::parseMapping('{' . $value . '}');
}
catch (InvalidArgumentException $e) {
// no, it's not
}
}
$output[] = $value;
--$i;
}
++$i;
}
throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence));
}
/**
* Parses a mapping to a YAML string.
*
* @param string $mapping
* @param integer $i
*
* @return string A YAML string
*/
protected static function parseMapping($mapping, &$i = 0) {
$output = [];
$len = strlen($mapping);
$i += 1;
// {foo: bar, bar:foo, ...}
while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
++$i;
continue 2;
case '}':
return $output;
}
// key
$key = self::parseScalar($mapping, [':', ' '], ['"', "'"], $i, false);
// value
$done = false;
while ($i < $len) {
switch ($mapping[$i]) {
case '[':
// nested sequence
$output[$key] = self::parseSequence($mapping, $i);
$done = true;
break;
case '{':
// nested mapping
$output[$key] = self::parseMapping($mapping, $i);
$done = true;
break;
case ':':
case ' ':
break;
default:
$output[$key] = self::parseScalar($mapping, [',', '}'], ['"', "'"], $i);
$done = true;
--$i;
}
++$i;
if ($done) {
continue 2;
}
}
}
throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
*
* @return string A YAML string
*/
protected static function evaluateScalar($scalar) {
$scalar = trim($scalar);
if ('1.1' === sfYaml::getSpecVersion()) {
$trueValues = ['true', 'on', '+', 'yes', 'y'];
$falseValues = ['false', 'off', '-', 'no', 'n'];
}
else {
$trueValues = ['true'];
$falseValues = ['false'];
}
switch (true) {
case 'null' == strtolower($scalar):
case '' == $scalar:
case '~' == $scalar:
return null;
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return intval(self::parseScalar(substr($scalar, 2)));
case 0 === strpos($scalar, '!!php/object:'):
return unserialize(substr($scalar, 13));
case ctype_digit($scalar):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case in_array(strtolower($scalar), $trueValues):
return true;
case in_array(strtolower($scalar), $falseValues):
return false;
case is_numeric($scalar):
return '0x' == $scalar[0] . $scalar[1] ? hexdec($scalar) : floatval($scalar);
case 0 == strcasecmp($scalar, '.inf'):
case 0 == strcasecmp($scalar, '.NaN'):
return -log(0);
case 0 == strcasecmp($scalar, '-.inf'):
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return floatval(str_replace(',', '', $scalar));
case preg_match(self::getTimestampRegex(), $scalar):
return strtotime($scalar);
default:
return (string) $scalar;
}
}
protected static function getTimestampRegex() {
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
}

536
sfyaml/sfYamlParser.php

@ -1,536 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once(dirname(__FILE__) . '/sfYamlInline.php');
if (!defined('PREG_BAD_UTF8_OFFSET_ERROR')) {
define('PREG_BAD_UTF8_OFFSET_ERROR', 5);
}
/**
* sfYamlParser parses YAML strings to convert them to PHP arrays.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $
*/
class sfYamlParser
{
protected
$offset = 0,
$lines = [],
$currentLineNb = -1,
$currentLine = '',
$refs = [];
/**
* Constructor
*
* @param integer $offset The offset of YAML document (used for line numbers in error messages)
*/
public function __construct($offset = 0) {
$this->offset = $offset;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
*
* @return mixed A PHP value
*
* @throws InvalidArgumentException If the YAML is not valid
*/
public function parse($value) {
$this->currentLineNb = -1;
$this->currentLine = '';
$this->lines = explode("\n", $this->cleanup($value));
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}
$data = [];
while ($this->moveToNextLine()) {
if ($this->isCurrentLineEmpty()) {
continue;
}
// tab?
if (preg_match('#^\t+#', $this->currentLine)) {
throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
$isRef = $isInPlace = $isProcessed = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock());
}
else {
if (
isset($values['leadspaces'])
&& ' ' == $values['leadspaces']
&& preg_match('#^(?P<key>' . sfYamlInline::REGEX_QUOTED_STRING . '|[^ \'"\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
) {
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$block = $values['value'];
if (!$this->isNextLineIndented()) {
$block .= "\n" . $this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
}
$data[] = $parser->parse($block);
}
else {
$data[] = $this->parseValue($values['value']);
}
}
}
elseif (preg_match('#^(?P<key>' . sfYamlInline::REGEX_QUOTED_STRING . '|[^ \'"].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
$key = sfYamlInline::parseScalar($values['key']);
if ('<<' === $key) {
if (isset($values['value']) && '*' === substr($values['value'], 0, 1)) {
$isInPlace = substr($values['value'], 1);
if (!array_key_exists($isInPlace, $this->refs)) {
throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
else {
if (isset($values['value']) && $values['value'] !== '') {
$value = $values['value'];
}
else {
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$parsed = $parser->parse($value);
$merged = [];
if (!is_array($parsed)) {
throw new InvalidArgumentException(sprintf('YAML merge keys used with a scalar value instead of an array at line %s (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
elseif (isset($parsed[0])) {
// Numeric array, merge individual elements
foreach (array_reverse($parsed) as $parsedItem) {
if (!is_array($parsedItem)) {
throw new InvalidArgumentException(sprintf('Merge items must be arrays at line %s (%s).', $this->getRealCurrentLineNb() + 1, $parsedItem));
}
$merged = array_merge($parsedItem, $merged);
}
}
else {
// Associative array, merge
$merged = array_merge($merged, $parsed);
}
$isProcessed = $merged;
}
}
elseif (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
if ($isProcessed) {
// Merge keys
$data = $isProcessed;
}
// hash
elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
// if next line is less indented or equal, then it means that the current value is null
if ($this->isNextLineIndented()) {
$data[$key] = null;
}
else {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$data[$key] = $parser->parse($this->getNextEmbedBlock());
}
}
else {
if ($isInPlace) {
$data = $this->refs[$isInPlace];
}
else {
$data[$key] = $this->parseValue($values['value']);
}
}
}
else {
// 1-liner followed by newline
if (2 == count($this->lines) && empty($this->lines[1])) {
$value = sfYamlInline::load($this->lines[0]);
if (is_array($value)) {
$first = reset($value);
if ('*' === substr($first, 0, 1)) {
$data = [];
foreach ($value as $alias) {
$data[] = $this->refs[substr($alias, 1)];
}
$value = $data;
}
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $value;
}
switch (preg_last_error()) {
case PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error on line';
break;
case PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached on line';
break;
case PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached on line';
break;
case PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data on line';
break;
case PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line';
break;
default:
$error = 'Unable to parse line';
}
throw new InvalidArgumentException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
if ($isRef) {
$this->refs[$isRef] = end($data);
}
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return empty($data) ? null : $data;
}
/**
* Returns the current line number (takes the offset into account).
*
* @return integer The current line number
*/
protected function getRealCurrentLineNb() {
return $this->currentLineNb + $this->offset;
}
/**
* Returns the current line indentation.
*
* @return integer The current line indentation
*/
protected function getCurrentLineIndentation() {
return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
}
/**
* Returns the next embed block of YAML.
*
* @param integer $indentation The indent level at which the block is to be read, or null for default
*
* @return string A YAML string
*/
protected function getNextEmbedBlock($indentation = null) {
$this->moveToNextLine();
if (null === $indentation) {
$newIndent = $this->getCurrentLineIndentation();
if (!$this->isCurrentLineEmpty() && 0 == $newIndent) {
throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
else {
$newIndent = $indentation;
}
$data = [substr($this->currentLine, $newIndent)];
while ($this->moveToNextLine()) {
if ($this->isCurrentLineEmpty()) {
if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
}
continue;
}
$indent = $this->getCurrentLineIndentation();
if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match)) {
// empty line
$data[] = $match['text'];
}
elseif ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
}
elseif (0 == $indent) {
$this->moveToPreviousLine();
break;
}
else {
throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
return implode("\n", $data);
}
/**
* Moves the parser to the next line.
*/
protected function moveToNextLine() {
if ($this->currentLineNb >= count($this->lines) - 1) {
return false;
}
$this->currentLine = $this->lines[++$this->currentLineNb];
return true;
}
/**
* Moves the parser to the previous line.
*/
protected function moveToPreviousLine() {
$this->currentLine = $this->lines[--$this->currentLineNb];
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
*
* @return mixed A PHP value
*/
protected function parseValue($value) {
if ('*' === substr($value, 0, 1)) {
if (false !== $pos = strpos($value, '#')) {
$value = substr($value, 1, $pos - 2);
}
else {
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs)) {
throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
}
return $this->refs[$value];
}
if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches)) {
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
}
else {
return sfYamlInline::load($value);
}
}
/**
* Parses a folded scalar.
*
* @param string $separator The separator that was used to begin this folded scalar (| or >)
* @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
* @param integer $indentation The indentation that was used to begin this folded scalar
*
* @return string The text value
*/
protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0) {
$separator = '|' == $separator ? "\n" : ' ';
$text = '';
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineBlank()) {
$text .= "\n";
$notEOF = $this->moveToNextLine();
}
if (!$notEOF) {
return '';
}
if (!preg_match('#^(?P<indent>' . ($indentation ? str_repeat(' ', $indentation) : ' +') . ')(?P<text>.*)$#u', $this->currentLine, $matches)) {
$this->moveToPreviousLine();
return '';
}
$textIndent = $matches['indent'];
$previousIndent = 0;
$text .= $matches['text'] . $separator;
while ($this->currentLineNb + 1 < count($this->lines)) {
$this->moveToNextLine();
if (preg_match('#^(?P<indent> {' . strlen($textIndent) . ',})(?P<text>.+)$#u', $this->currentLine, $matches)) {
if (' ' == $separator && $previousIndent != $matches['indent']) {
$text = substr($text, 0, -1) . "\n";
}
$previousIndent = $matches['indent'];
$text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)) . $matches['text'] . ($diff ? "\n" : $separator);
}
elseif (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches)) {
$text .= preg_replace('#^ {1,' . strlen($textIndent) . '}#', '', $matches['text']) . "\n";
}
else {
$this->moveToPreviousLine();
break;
}
}
if (' ' == $separator) {
// replace last separator by a newline
$text = preg_replace('/ (\n*)$/', "\n$1", $text);
}
switch ($indicator) {
case '':
$text = preg_replace('#\n+$#s', "\n", $text);
break;
case '+':
break;
case '-':
$text = preg_replace('#\n+$#s', '', $text);
break;
}
return $text;
}
/**
* Returns true if the next line is indented.
*
* @return Boolean Returns true if the next line is indented, false otherwise
*/
protected function isNextLineIndented() {
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineEmpty()) {
$notEOF = $this->moveToNextLine();
}
if (false === $notEOF) {
return false;
}
$ret = false;
if ($this->getCurrentLineIndentation() <= $currentIndentation) {
$ret = true;
}
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the current line is blank or if it is a comment line.
*
* @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
*/
protected function isCurrentLineEmpty() {
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}
/**
* Returns true if the current line is blank.
*
* @return Boolean Returns true if the current line is blank, false otherwise
*/
protected function isCurrentLineBlank() {
return '' == trim($this->currentLine, ' ');
}
/**
* Returns true if the current line is a comment line.
*
* @return Boolean Returns true if the current line is a comment line, false otherwise
*/
protected function isCurrentLineComment() {
//checking explicitly the first char of the trim is faster than loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
return $ltrimmedLine[0] === '#';
}
/**
* Cleanups a YAML string to be parsed.
*
* @param string $value The input YAML string
*
* @return string A cleaned up YAML string
*/
protected function cleanup($value) {
$value = str_replace(["\r\n", "\r"], "\n", $value);
if (!preg_match("#\n$#", $value)) {
$value .= "\n";
}
// strip YAML header
$count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count);
$this->offset += $count;
// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
if ($count == 1) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}
// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if ($count == 1) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
// remove end of the document marker (...)
$value = preg_replace('#\.\.\.\s*$#s', '', $value);
}
return $value;
}
}
Loading…
Cancel
Save