[ Index ]

PHP Cross Reference of phpBB-3.3.7-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Configurator/Helpers/ -> TemplateLoader.php (source)

   1  <?php
   2  
   3  /**
   4  * @package   s9e\TextFormatter
   5  * @copyright Copyright (c) 2010-2021 The s9e authors
   6  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
   7  */
   8  namespace s9e\TextFormatter\Configurator\Helpers;
   9  
  10  use DOMDocument;
  11  use DOMElement;
  12  use DOMXPath;
  13  use RuntimeException;
  14  
  15  abstract class TemplateLoader
  16  {
  17      /**
  18      * XSL namespace
  19      */
  20      const XMLNS_XSL = 'http://www.w3.org/1999/XSL/Transform';
  21  
  22      /**
  23      * Get the XML content of an element
  24      *
  25      * @private
  26      *
  27      * @param  DOMElement $element
  28      * @return string
  29      */
  30  	public static function innerXML(DOMElement $element)
  31      {
  32          // Serialize the XML then remove the outer element
  33          $xml = $element->ownerDocument->saveXML($element);
  34          $pos = 1 + strpos($xml, '>');
  35          $len = strrpos($xml, '<') - $pos;
  36  
  37          // If the template is empty, return an empty string
  38          return ($len < 1) ? '' : substr($xml, $pos, $len);
  39      }
  40  
  41      /**
  42      * Load a template as an xsl:template node
  43      *
  44      * Will attempt to load it as XML first, then as HTML as a fallback. Either way, an xsl:template
  45      * node is returned
  46      *
  47      * @param  string      $template
  48      * @return DOMDocument
  49      */
  50  	public static function load($template)
  51      {
  52          $dom = self::loadAsXML($template) ?: self::loadAsXML(self::fixEntities($template));
  53          if ($dom)
  54          {
  55              return $dom;
  56          }
  57  
  58          // If the template contains an XSL element, abort now. Otherwise, try reparsing it as HTML
  59          if (strpos($template, '<xsl:') !== false)
  60          {
  61              $error = libxml_get_last_error();
  62  
  63              throw new RuntimeException('Invalid XSL: ' . $error->message);
  64          }
  65  
  66          return self::loadAsHTML($template);
  67      }
  68  
  69      /**
  70      * Serialize a loaded template back into a string
  71      *
  72      * NOTE: removes the root node created by load()
  73      *
  74      * @param  DOMDocument $dom
  75      * @return string
  76      */
  77  	public static function save(DOMDocument $dom)
  78      {
  79          $xml = self::innerXML($dom->documentElement);
  80          if (strpos($xml, 'xmlns:xsl') !== false)
  81          {
  82              $xml = preg_replace('((<[^>]+?) xmlns:xsl="' . self::XMLNS_XSL . '")', '$1', $xml);
  83          }
  84  
  85          return $xml;
  86      }
  87  
  88      /**
  89      * Replace HTML entities and unescaped ampersands in given template
  90      *
  91      * @param  string $template
  92      * @return string
  93      */
  94  	protected static function fixEntities($template)
  95      {
  96          $template = self::replaceEntities($template);
  97          $template = preg_replace('(&(?!quot;|amp;|apos;|lt;|gt;|#\\d+;|#x[A-Fa-f0-9]+;))', '&amp;', $template);
  98  
  99          return $template;
 100      }
 101  
 102      /**
 103      * Load given HTML template in a DOM document
 104      *
 105      * @param  string      $template Original template
 106      * @return DOMDocument
 107      */
 108  	protected static function loadAsHTML($template)
 109      {
 110          $template = self::replaceCDATA($template);
 111          $template = self::replaceEntities($template);
 112  
 113          $dom  = new DOMDocument;
 114          $html = '<?xml version="1.0" encoding="utf-8" ?><html><body><div>' . $template . '</div></body></html>';
 115  
 116          $useErrors = libxml_use_internal_errors(true);
 117          $dom->loadHTML($html, LIBXML_NSCLEAN);
 118          self::removeInvalidAttributes($dom);
 119          libxml_use_internal_errors($useErrors);
 120  
 121          // Now dump the thing as XML then reload it with the proper root element
 122          $xml = '<?xml version="1.0" encoding="utf-8" ?><xsl:template xmlns:xsl="' . self::XMLNS_XSL . '">' . self::innerXML($dom->documentElement->firstChild->firstChild) . '</xsl:template>';
 123  
 124          $useErrors = libxml_use_internal_errors(true);
 125          $dom->loadXML($xml, LIBXML_NSCLEAN);
 126          libxml_use_internal_errors($useErrors);
 127  
 128          return $dom;
 129      }
 130  
 131      /**
 132      * Load given XSL template in a DOM document
 133      *
 134      * @param  string           $template Original template
 135      * @return bool|DOMDocument           DOMDocument on success, FALSE otherwise
 136      */
 137  	protected static function loadAsXML($template)
 138      {
 139          $xml = '<?xml version="1.0" encoding="utf-8" ?><xsl:template xmlns:xsl="' . self::XMLNS_XSL . '">' . $template . '</xsl:template>';
 140  
 141          $useErrors = libxml_use_internal_errors(true);
 142          $dom       = new DOMDocument;
 143          $success   = $dom->loadXML($xml, LIBXML_NOCDATA | LIBXML_NSCLEAN);
 144          self::removeInvalidAttributes($dom);
 145          libxml_use_internal_errors($useErrors);
 146  
 147          return ($success) ? $dom : false;
 148      }
 149  
 150      /**
 151      * Remove attributes with an invalid name from given DOM document
 152      *
 153      * @param  DOMDocument $dom
 154      * @return void
 155      */
 156  	protected static function removeInvalidAttributes(DOMDocument $dom)
 157      {
 158          $xpath = new DOMXPath($dom);
 159          foreach ($xpath->query('//@*') as $attribute)
 160          {
 161              if (!preg_match('(^(?:[-\\w]+:)?(?!\\d)[-\\w]+$)D', $attribute->nodeName))
 162              {
 163                  $attribute->parentNode->removeAttributeNode($attribute);
 164              }
 165          }
 166      }
 167  
 168      /**
 169      * Replace CDATA sections in given template
 170      *
 171      * @param  string $template Original template
 172      * @return string           Modified template
 173      */
 174  	protected static function replaceCDATA($template)
 175      {
 176          return preg_replace_callback(
 177              '(<!\\[CDATA\\[(.*?)\\]\\]>)',
 178              function ($m)
 179              {
 180                  return htmlspecialchars($m[1]);
 181              },
 182              $template
 183          );
 184      }
 185  
 186      /**
 187      * Replace known HTML entities
 188      *
 189      * @param  string $template
 190      * @return string
 191      */
 192  	protected static function replaceEntities(string $template): string
 193      {
 194          return preg_replace_callback(
 195              '(&(?!quot;|amp;|apos;|lt;|gt;)\\w+;)',
 196              function ($m)
 197              {
 198                  return html_entity_decode($m[0], ENT_HTML5 | ENT_NOQUOTES, 'UTF-8');
 199              },
 200              str_replace('&AMP;', '&amp;', $template)
 201          );
 202      }
 203  }


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