[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package s9e\TextFormatter 5 * @copyright Copyright (c) 2010-2022 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]+;))', '&', $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('&', '&', $template) 201 ); 202 } 203 }
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 |