Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
XmlUtils.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Component\Config\Util;
013
014 use Symfony\Component\Config\Util\Exception\InvalidXmlException;
015 use Symfony\Component\Config\Util\Exception\XmlParsingException;
016
017 /**
018 * XMLUtils is a bunch of utility methods to XML operations.
019 *
020 * This class contains static methods only and is not meant to be instantiated.
021 *
022 * @author Fabien Potencier <fabien@symfony.com>
023 * @author Martin Hasoň <martin.hason@gmail.com>
024 * @author Ole Rößner <ole@roessner.it>
025 */
026 class XmlUtils
027 {
028 /**
029 * This class should not be instantiated.
030 */
031 private function __construct()
032 {
033 }
034
035 /**
036 * Parses an XML string.
037 *
038 * @param string $content An XML string
039 * @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation
040 *
041 * @return \DOMDocument
042 *
043 * @throws XmlParsingException When parsing of XML file returns error
044 * @throws InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself
045 * @throws \RuntimeException When DOM extension is missing
046 */
047 public static function parse($content, $schemaOrCallable = null)
048 {
049 if (!\extension_loaded('dom')) {
050 throw new \RuntimeException('Extension DOM is required.');
051 }
052
053 $internalErrors = libxml_use_internal_errors(true);
054 if (\LIBXML_VERSION < 20900) {
055 $disableEntities = libxml_disable_entity_loader(true);
056 }
057 libxml_clear_errors();
058
059 $dom = new \DOMDocument();
060 $dom->validateOnParse = true;
061 if (!$dom->loadXML($content, \LIBXML_NONET | (\defined('LIBXML_COMPACT') ? \LIBXML_COMPACT : 0))) {
062 if (\LIBXML_VERSION < 20900) {
063 libxml_disable_entity_loader($disableEntities);
064 }
065
066 throw new XmlParsingException(implode("\n", static::getXmlErrors($internalErrors)));
067 }
068
069 $dom->normalizeDocument();
070
071 libxml_use_internal_errors($internalErrors);
072 if (\LIBXML_VERSION < 20900) {
073 libxml_disable_entity_loader($disableEntities);
074 }
075
076 foreach ($dom->childNodes as $child) {
077 if (\XML_DOCUMENT_TYPE_NODE === $child->nodeType) {
078 throw new XmlParsingException('Document types are not allowed.');
079 }
080 }
081
082 if (null !== $schemaOrCallable) {
083 $internalErrors = libxml_use_internal_errors(true);
084 libxml_clear_errors();
085
086 $e = null;
087 if (\is_callable($schemaOrCallable)) {
088 try {
089 $valid = \call_user_func($schemaOrCallable, $dom, $internalErrors);
090 } catch (\Exception $e) {
091 $valid = false;
092 }
093 } elseif (!\is_array($schemaOrCallable) && is_file((string) $schemaOrCallable)) {
094 $schemaSource = file_get_contents((string) $schemaOrCallable);
095 $valid = @$dom->schemaValidateSource($schemaSource);
096 } else {
097 libxml_use_internal_errors($internalErrors);
098
099 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 }
285