PageRenderTime 67ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/vendor_full/symfony/src/Symfony/Component/Yaml/Inline.php

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