[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Symfony\Component\Config\Util; 13 14 use Symfony\Component\Config\Util\Exception\InvalidXmlException; 15 use Symfony\Component\Config\Util\Exception\XmlParsingException; 16 17 /** 18 * XMLUtils is a bunch of utility methods to XML operations. 19 * 20 * This class contains static methods only and is not meant to be instantiated. 21 * 22 * @author Fabien Potencier <fabien@symfony.com> 23 * @author Martin Hasoň <martin.hason@gmail.com> 24 * @author Ole Rößner <ole@roessner.it> 25 */ 26 class XmlUtils 27 { 28 /** 29 * This class should not be instantiated. 30 */ 31 private function __construct() 32 { 33 } 34 35 /** 36 * Parses an XML string. 37 * 38 * @param string $content An XML string 39 * @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation 40 * 41 * @return \DOMDocument 42 * 43 * @throws XmlParsingException When parsing of XML file returns error 44 * @throws InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself 45 * @throws \RuntimeException When DOM extension is missing 46 */ 47 public static function parse($content, $schemaOrCallable = null) 48 { 49 if (!\extension_loaded('dom')) { 50 throw new \RuntimeException('Extension DOM is required.'); 51 } 52 53 $internalErrors = libxml_use_internal_errors(true); 54 if (\LIBXML_VERSION < 20900) { 55 $disableEntities = libxml_disable_entity_loader(true); 56 } 57 libxml_clear_errors(); 58 59 $dom = new \DOMDocument(); 60 $dom->validateOnParse = true; 61 if (!$dom->loadXML($content, \LIBXML_NONET | (\defined('LIBXML_COMPACT') ? \LIBXML_COMPACT : 0))) { 62 if (\LIBXML_VERSION < 20900) { 63 libxml_disable_entity_loader($disableEntities); 64 } 65 66 throw new XmlParsingException(implode("\n", static::getXmlErrors($internalErrors))); 67 } 68 69 $dom->normalizeDocument(); 70 71 libxml_use_internal_errors($internalErrors); 72 if (\LIBXML_VERSION < 20900) { 73 libxml_disable_entity_loader($disableEntities); 74 } 75 76 foreach ($dom->childNodes as $child) { 77 if (\XML_DOCUMENT_TYPE_NODE === $child->nodeType) { 78 throw new XmlParsingException('Document types are not allowed.'); 79 } 80 } 81 82 if (null !== $schemaOrCallable) { 83 $internalErrors = libxml_use_internal_errors(true); 84 libxml_clear_errors(); 85 86 $e = null; 87 if (\is_callable($schemaOrCallable)) { 88 try { 89 $valid = \call_user_func($schemaOrCallable, $dom, $internalErrors); 90 } catch (\Exception $e) { 91 $valid = false; 92 } 93 } elseif (!\is_array($schemaOrCallable) && is_file((string) $schemaOrCallable)) { 94 $schemaSource = file_get_contents((string) $schemaOrCallable); 95 $valid = @$dom->schemaValidateSource($schemaSource); 96 } else { 97 libxml_use_internal_errors($internalErrors); 98 99 throw new XmlParsingException('The schemaOrCallable argument has to be a valid path to XSD file or callable.'); 100 } 101 102 if (!$valid) { 103 $messages = static::getXmlErrors($internalErrors); 104 if (empty($messages)) { 105 throw new InvalidXmlException('The XML is not valid.', 0, $e); 106 } 107 throw new XmlParsingException(implode("\n", $messages), 0, $e); 108 } 109 } 110 111 libxml_clear_errors(); 112 libxml_use_internal_errors($internalErrors); 113 114 return $dom; 115 } 116 117 /** 118 * Loads an XML file. 119 * 120 * @param string $file An XML file path 121 * @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation 122 * 123 * @return \DOMDocument 124 * 125 * @throws \InvalidArgumentException When loading of XML file returns error 126 * @throws XmlParsingException When XML parsing returns any errors 127 * @throws \RuntimeException When DOM extension is missing 128 */ 129 public static function loadFile($file, $schemaOrCallable = null) 130 { 131 if (!is_file($file)) { 132 throw new \InvalidArgumentException(sprintf('Resource "%s" is not a file.', $file)); 133 } 134 135 if (!is_readable($file)) { 136 throw new \InvalidArgumentException(sprintf('File "%s" is not readable.', $file)); 137 } 138 139 $content = @file_get_contents($file); 140 141 if ('' === trim($content)) { 142 throw new \InvalidArgumentException(sprintf('File "%s" does not contain valid XML, it is empty.', $file)); 143 } 144 145 try { 146 return static::parse($content, $schemaOrCallable); 147 } catch (InvalidXmlException $e) { 148 throw new XmlParsingException(sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious()); 149 } 150 } 151 152 /** 153 * Converts a \DOMElement object to a PHP array. 154 * 155 * The following rules applies during the conversion: 156 * 157 * * Each tag is converted to a key value or an array 158 * if there is more than one "value" 159 * 160 * * The content of a tag is set under a "value" key (<foo>bar</foo>) 161 * if the tag also has some nested tags 162 * 163 * * The attributes are converted to keys (<foo foo="bar"/>) 164 * 165 * * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>) 166 * 167 * @param \DOMElement $element A \DOMElement instance 168 * @param bool $checkPrefix Check prefix in an element or an attribute name 169 * 170 * @return mixed 171 */ 172 public static function convertDomElementToArray(\DOMElement $element, $checkPrefix = true) 173 { 174 $prefix = (string) $element->prefix; 175 $empty = true; 176 $config = []; 177 foreach ($element->attributes as $name => $node) { 178 if ($checkPrefix && !\in_array((string) $node->prefix, ['', $prefix], true)) { 179 continue; 180 } 181 $config[$name] = static::phpize($node->value); 182 $empty = false; 183 } 184 185 $nodeValue = false; 186 foreach ($element->childNodes as $node) { 187 if ($node instanceof \DOMText) { 188 if ('' !== trim($node->nodeValue)) { 189 $nodeValue = trim($node->nodeValue); 190 $empty = false; 191 } 192 } elseif ($checkPrefix && $prefix != (string) $node->prefix) { 193 continue; 194 } elseif (!$node instanceof \DOMComment) { 195 $value = static::convertDomElementToArray($node, $checkPrefix); 196 197 $key = $node->localName; 198 if (isset($config[$key])) { 199 if (!\is_array($config[$key]) || !\is_int(key($config[$key]))) { 200 $config[$key] = [$config[$key]]; 201 } 202 $config[$key][] = $value; 203 } else { 204 $config[$key] = $value; 205 } 206 207 $empty = false; 208 } 209 } 210 211 if (false !== $nodeValue) { 212 $value = static::phpize($nodeValue); 213 if (\count($config)) { 214 $config['value'] = $value; 215 } else { 216 $config = $value; 217 } 218 } 219 220 return !$empty ? $config : null; 221 } 222 223 /** 224 * Converts an xml value to a PHP type. 225 * 226 * @param mixed $value 227 * 228 * @return mixed 229 */ 230 public static function phpize($value) 231 { 232 $value = (string) $value; 233 $lowercaseValue = strtolower($value); 234 235 switch (true) { 236 case 'null' === $lowercaseValue: 237 return null; 238 case ctype_digit($value): 239 $raw = $value; 240 $cast = (int) $value; 241 242 return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw); 243 case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)): 244 $raw = $value; 245 $cast = (int) $value; 246 247 return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw); 248 case 'true' === $lowercaseValue: 249 return true; 250 case 'false' === $lowercaseValue: 251 return false; 252 case isset($value[1]) && '0b' == $value[0].$value[1] && preg_match('/^0b[01]*$/', $value): 253 return bindec($value); 254 case is_numeric($value): 255 return '0x' === $value[0].$value[1] ? hexdec($value) : (float) $value; 256 case preg_match('/^0x[0-9a-f]++$/i', $value): 257 return hexdec($value); 258 case preg_match('/^[+-]?[0-9]+(\.[0-9]+)?$/', $value): 259 return (float) $value; 260 default: 261 return $value; 262 } 263 } 264 265 protected static function getXmlErrors($internalErrors) 266 { 267 $errors = []; 268 foreach (libxml_get_errors() as $error) { 269 $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)', 270 \LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR', 271 $error->code, 272 trim($error->message), 273 $error->file ?: 'n/a', 274 $error->line, 275 $error->column 276 ); 277 } 278 279 libxml_clear_errors(); 280 libxml_use_internal_errors($internalErrors); 281 282 return $errors; 283 } 284 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |