PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/nguyennamtien/TaskBoxx
PHP | 403 lines | 264 code | 40 blank | 99 comment | 43 complexity | 29e940eacf44d2f84380b7384af1c0ac MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. * (c) Fabien Potencier <fabien@symfony.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@symfony.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 Escaper::requiresDoubleQuoting($value):
  81. return Escaper::escapeWithDoubleQuotes($value);
  82. case Escaper::requiresSingleQuoting($value):
  83. return Escaper::escapeWithSingleQuotes($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 private 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 $stringDelimiters
  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 private 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. $unescaper = new Unescaper();
  179. if ('"' == $scalar[$i]) {
  180. $output = $unescaper->unescapeDoubleQuotedString($output);
  181. } else {
  182. $output = $unescaper->unescapeSingleQuotedString($output);
  183. }
  184. $i += strlen($match[0]);
  185. return $output;
  186. }
  187. /**
  188. * Parses a sequence to a YAML string.
  189. *
  190. * @param string $sequence
  191. * @param integer $i
  192. *
  193. * @return string A YAML string
  194. *
  195. * @throws ParserException When malformed inline YAML string is parsed
  196. */
  197. static private function parseSequence($sequence, &$i = 0)
  198. {
  199. $output = array();
  200. $len = strlen($sequence);
  201. $i += 1;
  202. // [foo, bar, ...]
  203. while ($i < $len) {
  204. switch ($sequence[$i]) {
  205. case '[':
  206. // nested sequence
  207. $output[] = self::parseSequence($sequence, $i);
  208. break;
  209. case '{':
  210. // nested mapping
  211. $output[] = self::parseMapping($sequence, $i);
  212. break;
  213. case ']':
  214. return $output;
  215. case ',':
  216. case ' ':
  217. break;
  218. default:
  219. $isQuoted = in_array($sequence[$i], array('"', "'"));
  220. $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
  221. if (!$isQuoted && false !== strpos($value, ': ')) {
  222. // embedded mapping?
  223. try {
  224. $value = self::parseMapping('{'.$value.'}');
  225. } catch (\InvalidArgumentException $e) {
  226. // no, it's not
  227. }
  228. }
  229. $output[] = $value;
  230. --$i;
  231. }
  232. ++$i;
  233. }
  234. throw new ParserException(sprintf('Malformed inline YAML string %s', $sequence));
  235. }
  236. /**
  237. * Parses a mapping to a YAML string.
  238. *
  239. * @param string $mapping
  240. * @param integer $i
  241. *
  242. * @return string A YAML string
  243. *
  244. * @throws ParserException When malformed inline YAML string is parsed
  245. */
  246. static private function parseMapping($mapping, &$i = 0)
  247. {
  248. $output = array();
  249. $len = strlen($mapping);
  250. $i += 1;
  251. // {foo: bar, bar:foo, ...}
  252. while ($i < $len) {
  253. switch ($mapping[$i]) {
  254. case ' ':
  255. case ',':
  256. ++$i;
  257. continue 2;
  258. case '}':
  259. return $output;
  260. }
  261. // key
  262. $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
  263. // value
  264. $done = false;
  265. while ($i < $len) {
  266. switch ($mapping[$i]) {
  267. case '[':
  268. // nested sequence
  269. $output[$key] = self::parseSequence($mapping, $i);
  270. $done = true;
  271. break;
  272. case '{':
  273. // nested mapping
  274. $output[$key] = self::parseMapping($mapping, $i);
  275. $done = true;
  276. break;
  277. case ':':
  278. case ' ':
  279. break;
  280. default:
  281. $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
  282. $done = true;
  283. --$i;
  284. }
  285. ++$i;
  286. if ($done) {
  287. continue 2;
  288. }
  289. }
  290. }
  291. throw new ParserException(sprintf('Malformed inline YAML string %s', $mapping));
  292. }
  293. /**
  294. * Evaluates scalars and replaces magic values.
  295. *
  296. * @param string $scalar
  297. *
  298. * @return string A YAML string
  299. */
  300. static private function evaluateScalar($scalar)
  301. {
  302. $scalar = trim($scalar);
  303. $trueValues = '1.1' == Yaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true');
  304. $falseValues = '1.1' == Yaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false');
  305. switch (true) {
  306. case 'null' == strtolower($scalar):
  307. case '' == $scalar:
  308. case '~' == $scalar:
  309. return null;
  310. case 0 === strpos($scalar, '!str'):
  311. return (string) substr($scalar, 5);
  312. case 0 === strpos($scalar, '! '):
  313. return intval(self::parseScalar(substr($scalar, 2)));
  314. case 0 === strpos($scalar, '!!php/object:'):
  315. return unserialize(substr($scalar, 13));
  316. case ctype_digit($scalar):
  317. $raw = $scalar;
  318. $cast = intval($scalar);
  319. return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
  320. case in_array(strtolower($scalar), $trueValues):
  321. return true;
  322. case in_array(strtolower($scalar), $falseValues):
  323. return false;
  324. case is_numeric($scalar):
  325. return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
  326. case 0 == strcasecmp($scalar, '.inf'):
  327. case 0 == strcasecmp($scalar, '.NaN'):
  328. return -log(0);
  329. case 0 == strcasecmp($scalar, '-.inf'):
  330. return log(0);
  331. case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
  332. return floatval(str_replace(',', '', $scalar));
  333. case preg_match(self::getTimestampRegex(), $scalar):
  334. return strtotime($scalar);
  335. default:
  336. return (string) $scalar;
  337. }
  338. }
  339. /**
  340. * Gets a regex that matches an unix timestamp
  341. *
  342. * @return string The regular expression
  343. */
  344. static private function getTimestampRegex()
  345. {
  346. return <<<EOF
  347. ~^
  348. (?P<year>[0-9][0-9][0-9][0-9])
  349. -(?P<month>[0-9][0-9]?)
  350. -(?P<day>[0-9][0-9]?)
  351. (?:(?:[Tt]|[ \t]+)
  352. (?P<hour>[0-9][0-9]?)
  353. :(?P<minute>[0-9][0-9])
  354. :(?P<second>[0-9][0-9])
  355. (?:\.(?P<fraction>[0-9]*))?
  356. (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
  357. (?::(?P<tz_minute>[0-9][0-9]))?))?)?
  358. $~x
  359. EOF;
  360. }
  361. }