[ Index ]

PHP Cross Reference of phpBB-3.3.7-deutsch

title

Body

[close]

/vendor/symfony/config/Util/ -> XmlUtils.php (source)

   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  }


Generated: Thu Mar 24 21:31:15 2022 Cross-referenced by PHPXref 0.7.1