PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Zend/Config/Yaml.php

https://gitlab.com/LisovyiEvhenii/ismextensions
PHP | 415 lines | 214 code | 43 blank | 158 comment | 40 complexity | d559550b7de8c77f03a6d8c5ab1af715 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Config
  17. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id$
  20. */
  21. /**
  22. * @see Zend_Config
  23. */
  24. #require_once 'Zend/Config.php';
  25. /**
  26. * YAML Adapter for Zend_Config
  27. *
  28. * @category Zend
  29. * @package Zend_Config
  30. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. */
  33. class Zend_Config_Yaml extends Zend_Config
  34. {
  35. /**
  36. * Attribute name that indicates what section a config extends from
  37. */
  38. const EXTENDS_NAME = "_extends";
  39. /**
  40. * Whether to skip extends or not
  41. *
  42. * @var boolean
  43. */
  44. protected $_skipExtends = false;
  45. /**
  46. * What to call when we need to decode some YAML?
  47. *
  48. * @var callable
  49. */
  50. protected $_yamlDecoder = array(__CLASS__, 'decode');
  51. /**
  52. * Whether or not to ignore constants in parsed YAML
  53. * @var bool
  54. */
  55. protected static $_ignoreConstants = false;
  56. /**
  57. * Indicate whether parser should ignore constants or not
  58. *
  59. * @param bool $flag
  60. * @return void
  61. */
  62. public static function setIgnoreConstants($flag)
  63. {
  64. self::$_ignoreConstants = (bool) $flag;
  65. }
  66. /**
  67. * Whether parser should ignore constants or not
  68. *
  69. * @return bool
  70. */
  71. public static function ignoreConstants()
  72. {
  73. return self::$_ignoreConstants;
  74. }
  75. /**
  76. * Get callback for decoding YAML
  77. *
  78. * @return callable
  79. */
  80. public function getYamlDecoder()
  81. {
  82. return $this->_yamlDecoder;
  83. }
  84. /**
  85. * Set callback for decoding YAML
  86. *
  87. * @param callable $yamlDecoder the decoder to set
  88. * @return Zend_Config_Yaml
  89. */
  90. public function setYamlDecoder($yamlDecoder)
  91. {
  92. if (!is_callable($yamlDecoder)) {
  93. #require_once 'Zend/Config/Exception.php';
  94. throw new Zend_Config_Exception('Invalid parameter to setYamlDecoder() - must be callable');
  95. }
  96. $this->_yamlDecoder = $yamlDecoder;
  97. return $this;
  98. }
  99. /**
  100. * Loads the section $section from the config file encoded as YAML
  101. *
  102. * Sections are defined as properties of the main object
  103. *
  104. * In order to extend another section, a section defines the "_extends"
  105. * property having a value of the section name from which the extending
  106. * section inherits values.
  107. *
  108. * Note that the keys in $section will override any keys of the same
  109. * name in the sections that have been included via "_extends".
  110. *
  111. * Options may include:
  112. * - allow_modifications: whether or not the config object is mutable
  113. * - skip_extends: whether or not to skip processing of parent configuration
  114. * - yaml_decoder: a callback to use to decode the Yaml source
  115. *
  116. * @param string $yaml YAML file to process
  117. * @param mixed $section Section to process
  118. * @param array|boolean $options
  119. */
  120. public function __construct($yaml, $section = null, $options = false)
  121. {
  122. if (empty($yaml)) {
  123. #require_once 'Zend/Config/Exception.php';
  124. throw new Zend_Config_Exception('Filename is not set');
  125. }
  126. $ignoreConstants = $staticIgnoreConstants = self::ignoreConstants();
  127. $allowModifications = false;
  128. if (is_bool($options)) {
  129. $allowModifications = $options;
  130. } elseif (is_array($options)) {
  131. foreach ($options as $key => $value) {
  132. switch (strtolower($key)) {
  133. case 'allow_modifications':
  134. case 'allowmodifications':
  135. $allowModifications = (bool) $value;
  136. break;
  137. case 'skip_extends':
  138. case 'skipextends':
  139. $this->_skipExtends = (bool) $value;
  140. break;
  141. case 'ignore_constants':
  142. case 'ignoreconstants':
  143. $ignoreConstants = (bool) $value;
  144. break;
  145. case 'yaml_decoder':
  146. case 'yamldecoder':
  147. $this->setYamlDecoder($value);
  148. break;
  149. default:
  150. break;
  151. }
  152. }
  153. }
  154. // Suppress warnings and errors while loading file
  155. set_error_handler(array($this, '_loadFileErrorHandler'));
  156. $yaml = file_get_contents($yaml);
  157. restore_error_handler();
  158. // Check if there was a error while loading file
  159. if ($this->_loadFileErrorStr !== null) {
  160. #require_once 'Zend/Config/Exception.php';
  161. throw new Zend_Config_Exception($this->_loadFileErrorStr);
  162. }
  163. // Override static value for ignore_constants if provided in $options
  164. self::setIgnoreConstants($ignoreConstants);
  165. // Parse YAML
  166. $config = call_user_func($this->getYamlDecoder(), $yaml);
  167. // Reset original static state of ignore_constants
  168. self::setIgnoreConstants($staticIgnoreConstants);
  169. if (null === $config) {
  170. // decode failed
  171. #require_once 'Zend/Config/Exception.php';
  172. throw new Zend_Config_Exception("Error parsing YAML data");
  173. }
  174. if (null === $section) {
  175. $dataArray = array();
  176. foreach ($config as $sectionName => $sectionData) {
  177. $dataArray[$sectionName] = $this->_processExtends($config, $sectionName);
  178. }
  179. parent::__construct($dataArray, $allowModifications);
  180. } elseif (is_array($section)) {
  181. $dataArray = array();
  182. foreach ($section as $sectionName) {
  183. if (!isset($config[$sectionName])) {
  184. #require_once 'Zend/Config/Exception.php';
  185. throw new Zend_Config_Exception(sprintf(
  186. 'Section "%s" cannot be found',
  187. implode(' ', (array)$section)
  188. ));
  189. }
  190. $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray);
  191. }
  192. parent::__construct($dataArray, $allowModifications);
  193. } else {
  194. if (!isset($config[$section])) {
  195. #require_once 'Zend/Config/Exception.php';
  196. throw new Zend_Config_Exception(sprintf(
  197. 'Section "%s" cannot be found',
  198. implode(' ', (array)$section)
  199. ));
  200. }
  201. $dataArray = $this->_processExtends($config, $section);
  202. if (!is_array($dataArray)) {
  203. // Section in the yaml data contains just one top level string
  204. $dataArray = array($section => $dataArray);
  205. }
  206. parent::__construct($dataArray, $allowModifications);
  207. }
  208. $this->_loadedSection = $section;
  209. }
  210. /**
  211. * Helper function to process each element in the section and handle
  212. * the "_extends" inheritance attribute.
  213. *
  214. * @param array $data Data array to process
  215. * @param string $section Section to process
  216. * @param array $config Configuration which was parsed yet
  217. * @return array
  218. * @throws Zend_Config_Exception When $section cannot be found
  219. */
  220. protected function _processExtends(array $data, $section, array $config = array())
  221. {
  222. if (!isset($data[$section])) {
  223. #require_once 'Zend/Config/Exception.php';
  224. throw new Zend_Config_Exception(sprintf('Section "%s" cannot be found', $section));
  225. }
  226. $thisSection = $data[$section];
  227. if (is_array($thisSection) && isset($thisSection[self::EXTENDS_NAME])) {
  228. $this->_assertValidExtend($section, $thisSection[self::EXTENDS_NAME]);
  229. if (!$this->_skipExtends) {
  230. $config = $this->_processExtends($data, $thisSection[self::EXTENDS_NAME], $config);
  231. }
  232. unset($thisSection[self::EXTENDS_NAME]);
  233. }
  234. $config = $this->_arrayMergeRecursive($config, $thisSection);
  235. return $config;
  236. }
  237. /**
  238. * Very dumb YAML parser
  239. *
  240. * Until we have Zend_Yaml...
  241. *
  242. * @param string $yaml YAML source
  243. * @return array Decoded data
  244. */
  245. public static function decode($yaml)
  246. {
  247. $lines = explode("\n", $yaml);
  248. reset($lines);
  249. return self::_decodeYaml(0, $lines);
  250. }
  251. /**
  252. * Service function to decode YAML
  253. *
  254. * @param int $currentIndent Current indent level
  255. * @param array $lines YAML lines
  256. * @return array|string
  257. */
  258. protected static function _decodeYaml($currentIndent, &$lines)
  259. {
  260. $config = array();
  261. $inIndent = false;
  262. while (list($n, $line) = each($lines)) {
  263. $lineno = $n + 1;
  264. $line = rtrim(preg_replace("/#.*$/", "", $line));
  265. if (strlen($line) == 0) {
  266. continue;
  267. }
  268. $indent = strspn($line, " ");
  269. // line without the spaces
  270. $line = trim($line);
  271. if (strlen($line) == 0) {
  272. continue;
  273. }
  274. if ($indent < $currentIndent) {
  275. // this level is done
  276. prev($lines);
  277. return $config;
  278. }
  279. if (!$inIndent) {
  280. $currentIndent = $indent;
  281. $inIndent = true;
  282. }
  283. if (preg_match("/(?!-)([\w\-]+):\s*(.*)/", $line, $m)) {
  284. // key: value
  285. if (strlen($m[2])) {
  286. // simple key: value
  287. $value = preg_replace("/#.*$/", "", $m[2]);
  288. $value = self::_parseValue($value);
  289. } else {
  290. // key: and then values on new lines
  291. $value = self::_decodeYaml($currentIndent + 1, $lines);
  292. if (is_array($value) && !count($value)) {
  293. $value = "";
  294. }
  295. }
  296. $config[$m[1]] = $value;
  297. } elseif ($line[0] == "-") {
  298. // item in the list:
  299. // - FOO
  300. if (strlen($line) > 2) {
  301. $value = substr($line, 2);
  302. $config[] = self::_parseValue($value);
  303. } else {
  304. $config[] = self::_decodeYaml($currentIndent + 1, $lines);
  305. }
  306. } else {
  307. #require_once 'Zend/Config/Exception.php';
  308. throw new Zend_Config_Exception(sprintf(
  309. 'Error parsing YAML at line %d - unsupported syntax: "%s"',
  310. $lineno, $line
  311. ));
  312. }
  313. }
  314. return $config;
  315. }
  316. /**
  317. * Parse values
  318. *
  319. * @param string $value
  320. * @return string
  321. */
  322. protected static function _parseValue($value)
  323. {
  324. $value = trim($value);
  325. // remove quotes from string.
  326. if ('"' == $value['0']) {
  327. if ('"' == $value[count($value) -1]) {
  328. $value = substr($value, 1, -1);
  329. }
  330. } elseif ('\'' == $value['0'] && '\'' == $value[count($value) -1]) {
  331. $value = strtr($value, array("''" => "'", "'" => ''));
  332. }
  333. // Check for booleans and constants
  334. if (preg_match('/^(t(rue)?|on|y(es)?)$/i', $value)) {
  335. $value = true;
  336. } elseif (preg_match('/^(f(alse)?|off|n(o)?)$/i', $value)) {
  337. $value = false;
  338. } elseif (strcasecmp($value, 'null') === 0) {
  339. $value = null;
  340. } elseif (!self::$_ignoreConstants) {
  341. // test for constants
  342. $value = self::_replaceConstants($value);
  343. }
  344. return $value;
  345. }
  346. /**
  347. * Replace any constants referenced in a string with their values
  348. *
  349. * @param string $value
  350. * @return string
  351. */
  352. protected static function _replaceConstants($value)
  353. {
  354. foreach (self::_getConstants() as $constant) {
  355. if (strstr($value, $constant)) {
  356. $value = str_replace($constant, constant($constant), $value);
  357. }
  358. }
  359. return $value;
  360. }
  361. /**
  362. * Get (reverse) sorted list of defined constant names
  363. *
  364. * @return array
  365. */
  366. protected static function _getConstants()
  367. {
  368. $constants = array_keys(get_defined_constants());
  369. rsort($constants, SORT_STRING);
  370. return $constants;
  371. }
  372. }