File indexing completed on 2025-01-19 05:20:59
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Config 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @see Zend_Config 0024 */ 0025 // require_once 'Zend/Config.php'; 0026 0027 /** @see Zend_Xml_Security */ 0028 // require_once 'Zend/Xml/Security.php'; 0029 0030 /** @see Zend_Xml_Exception */ 0031 // require_once 'Zend/Xml/Exception.php'; 0032 0033 /** 0034 * XML Adapter for Zend_Config 0035 * 0036 * @category Zend 0037 * @package Zend_Config 0038 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0039 * @license http://framework.zend.com/license/new-bsd New BSD License 0040 */ 0041 class Zend_Config_Xml extends Zend_Config 0042 { 0043 /** 0044 * XML namespace for ZF-related tags and attributes 0045 */ 0046 const XML_NAMESPACE = 'http://framework.zend.com/xml/zend-config-xml/1.0/'; 0047 0048 /** 0049 * Whether to skip extends or not 0050 * 0051 * @var boolean 0052 */ 0053 protected $_skipExtends = false; 0054 0055 /** 0056 * Loads the section $section from the config file (or string $xml for 0057 * access facilitated by nested object properties. 0058 * 0059 * Sections are defined in the XML as children of the root element. 0060 * 0061 * In order to extend another section, a section defines the "extends" 0062 * attribute having a value of the section name from which the extending 0063 * section inherits values. 0064 * 0065 * Note that the keys in $section will override any keys of the same 0066 * name in the sections that have been included via "extends". 0067 * 0068 * The $options parameter may be provided as either a boolean or an array. 0069 * If provided as a boolean, this sets the $allowModifications option of 0070 * Zend_Config. If provided as an array, there are two configuration 0071 * directives that may be set. For example: 0072 * 0073 * $options = array( 0074 * 'allowModifications' => false, 0075 * 'skipExtends' => false 0076 * ); 0077 * 0078 * @param string $xml XML file or string to process 0079 * @param mixed $section Section to process 0080 * @param array|boolean $options 0081 * @throws Zend_Config_Exception When xml is not set or cannot be loaded 0082 * @throws Zend_Config_Exception When section $sectionName cannot be found in $xml 0083 */ 0084 public function __construct($xml, $section = null, $options = false) 0085 { 0086 if (empty($xml)) { 0087 // require_once 'Zend/Config/Exception.php'; 0088 throw new Zend_Config_Exception('Filename is not set'); 0089 } 0090 0091 $allowModifications = false; 0092 if (is_bool($options)) { 0093 $allowModifications = $options; 0094 } elseif (is_array($options)) { 0095 if (isset($options['allowModifications'])) { 0096 $allowModifications = (bool) $options['allowModifications']; 0097 } 0098 if (isset($options['skipExtends'])) { 0099 $this->_skipExtends = (bool) $options['skipExtends']; 0100 } 0101 } 0102 0103 set_error_handler(array($this, '_loadFileErrorHandler')); // Warnings and errors are suppressed 0104 if (strstr($xml, '<?xml')) { 0105 $config = Zend_Xml_Security::scan($xml); 0106 } else { 0107 try { 0108 if (!$config = Zend_Xml_Security::scanFile($xml)) { 0109 // require_once 'Zend/Config/Exception.php'; 0110 throw new Zend_Config_Exception( 0111 "Error failed to load $xml file" 0112 ); 0113 } 0114 } catch (Zend_Xml_Exception $e) { 0115 // require_once 'Zend/Config/Exception.php'; 0116 throw new Zend_Config_Exception( 0117 $e->getMessage() 0118 ); 0119 } 0120 } 0121 0122 restore_error_handler(); 0123 // Check if there was a error while loading file 0124 if ($this->_loadFileErrorStr !== null) { 0125 // require_once 'Zend/Config/Exception.php'; 0126 throw new Zend_Config_Exception($this->_loadFileErrorStr); 0127 } 0128 0129 if ($section === null) { 0130 $dataArray = array(); 0131 foreach ($config as $sectionName => $sectionData) { 0132 $dataArray[$sectionName] = $this->_processExtends($config, $sectionName); 0133 } 0134 0135 parent::__construct($dataArray, $allowModifications); 0136 } else if (is_array($section)) { 0137 $dataArray = array(); 0138 foreach ($section as $sectionName) { 0139 if (!isset($config->$sectionName)) { 0140 // require_once 'Zend/Config/Exception.php'; 0141 throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $xml"); 0142 } 0143 0144 $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray); 0145 } 0146 0147 parent::__construct($dataArray, $allowModifications); 0148 } else { 0149 if (!isset($config->$section)) { 0150 // require_once 'Zend/Config/Exception.php'; 0151 throw new Zend_Config_Exception("Section '$section' cannot be found in $xml"); 0152 } 0153 0154 $dataArray = $this->_processExtends($config, $section); 0155 if (!is_array($dataArray)) { 0156 // Section in the XML file contains just one top level string 0157 $dataArray = array($section => $dataArray); 0158 } 0159 0160 parent::__construct($dataArray, $allowModifications); 0161 } 0162 0163 $this->_loadedSection = $section; 0164 } 0165 0166 /** 0167 * Helper function to process each element in the section and handle 0168 * the "extends" inheritance attribute. 0169 * 0170 * @param SimpleXMLElement $element XML Element to process 0171 * @param string $section Section to process 0172 * @param array $config Configuration which was parsed yet 0173 * @throws Zend_Config_Exception When $section cannot be found 0174 * @return array 0175 */ 0176 protected function _processExtends(SimpleXMLElement $element, $section, array $config = array()) 0177 { 0178 if (!isset($element->$section)) { 0179 // require_once 'Zend/Config/Exception.php'; 0180 throw new Zend_Config_Exception("Section '$section' cannot be found"); 0181 } 0182 0183 $thisSection = $element->$section; 0184 $nsAttributes = $thisSection->attributes(self::XML_NAMESPACE); 0185 0186 if (isset($thisSection['extends']) || isset($nsAttributes['extends'])) { 0187 $extendedSection = (string) (isset($nsAttributes['extends']) ? $nsAttributes['extends'] : $thisSection['extends']); 0188 $this->_assertValidExtend($section, $extendedSection); 0189 0190 if (!$this->_skipExtends) { 0191 $config = $this->_processExtends($element, $extendedSection, $config); 0192 } 0193 } 0194 0195 $config = $this->_arrayMergeRecursive($config, $this->_toArray($thisSection)); 0196 0197 return $config; 0198 } 0199 0200 /** 0201 * Returns a string or an associative and possibly multidimensional array from 0202 * a SimpleXMLElement. 0203 * 0204 * @param SimpleXMLElement $xmlObject Convert a SimpleXMLElement into an array 0205 * @return array|string 0206 */ 0207 protected function _toArray(SimpleXMLElement $xmlObject) 0208 { 0209 $config = array(); 0210 $nsAttributes = $xmlObject->attributes(self::XML_NAMESPACE); 0211 0212 // Search for parent node values 0213 if (count($xmlObject->attributes()) > 0) { 0214 foreach ($xmlObject->attributes() as $key => $value) { 0215 if ($key === 'extends') { 0216 continue; 0217 } 0218 0219 $value = (string) $value; 0220 0221 if (array_key_exists($key, $config)) { 0222 if (!is_array($config[$key])) { 0223 $config[$key] = array($config[$key]); 0224 } 0225 0226 $config[$key][] = $value; 0227 } else { 0228 $config[$key] = $value; 0229 } 0230 } 0231 } 0232 0233 // Search for local 'const' nodes and replace them 0234 if (count($xmlObject->children(self::XML_NAMESPACE)) > 0) { 0235 if (count($xmlObject->children()) > 0) { 0236 // require_once 'Zend/Config/Exception.php'; 0237 throw new Zend_Config_Exception("A node with a 'const' childnode may not have any other children"); 0238 } 0239 0240 $dom = dom_import_simplexml($xmlObject); 0241 $namespaceChildNodes = array(); 0242 0243 // We have to store them in an array, as replacing nodes will 0244 // confuse the DOMNodeList later 0245 foreach ($dom->childNodes as $node) { 0246 if ($node instanceof DOMElement && $node->namespaceURI === self::XML_NAMESPACE) { 0247 $namespaceChildNodes[] = $node; 0248 } 0249 } 0250 0251 foreach ($namespaceChildNodes as $node) { 0252 switch ($node->localName) { 0253 case 'const': 0254 if (!$node->hasAttributeNS(self::XML_NAMESPACE, 'name')) { 0255 // require_once 'Zend/Config/Exception.php'; 0256 throw new Zend_Config_Exception("Misssing 'name' attribute in 'const' node"); 0257 } 0258 0259 $constantName = $node->getAttributeNS(self::XML_NAMESPACE, 'name'); 0260 0261 if (!defined($constantName)) { 0262 // require_once 'Zend/Config/Exception.php'; 0263 throw new Zend_Config_Exception("Constant with name '$constantName' was not defined"); 0264 } 0265 0266 $constantValue = constant($constantName); 0267 0268 $dom->replaceChild($dom->ownerDocument->createTextNode($constantValue), $node); 0269 break; 0270 0271 default: 0272 // require_once 'Zend/Config/Exception.php'; 0273 throw new Zend_Config_Exception("Unknown node with name '$node->localName' found"); 0274 } 0275 } 0276 0277 return (string) simplexml_import_dom($dom); 0278 } 0279 0280 // Search for children 0281 if (count($xmlObject->children()) > 0) { 0282 foreach ($xmlObject->children() as $key => $value) { 0283 if (count($value->children()) > 0 || count($value->children(self::XML_NAMESPACE)) > 0) { 0284 $value = $this->_toArray($value); 0285 } else if (count($value->attributes()) > 0) { 0286 $attributes = $value->attributes(); 0287 if (isset($attributes['value'])) { 0288 $value = (string) $attributes['value']; 0289 } else { 0290 $value = $this->_toArray($value); 0291 } 0292 } else { 0293 $value = (string) $value; 0294 } 0295 0296 if (array_key_exists($key, $config)) { 0297 if (!is_array($config[$key]) || !array_key_exists(0, $config[$key])) { 0298 $config[$key] = array($config[$key]); 0299 } 0300 0301 $config[$key][] = $value; 0302 } else { 0303 $config[$key] = $value; 0304 } 0305 } 0306 } else if (!isset($xmlObject['extends']) && !isset($nsAttributes['extends']) && (count($config) === 0)) { 0307 // Object has no children nor attributes and doesn't use the extends 0308 // attribute: it's a string 0309 $config = (string) $xmlObject; 0310 } 0311 0312 return $config; 0313 } 0314 }