[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * @package s9e\TextFormatter 5 * @copyright Copyright (c) 2010-2019 The s9e Authors 6 * @license http://www.opensource.org/licenses/mit-license.php The MIT License 7 */ 8 namespace s9e\TextFormatter\Plugins\Preg; 9 use DOMAttr; 10 use DOMText; 11 use DOMXPath; 12 use Exception; 13 use InvalidArgumentException; 14 use s9e\TextFormatter\Configurator\Helpers\RegexpParser; 15 use s9e\TextFormatter\Configurator\Helpers\TemplateHelper; 16 use s9e\TextFormatter\Configurator\Items\Regexp; 17 use s9e\TextFormatter\Configurator\Items\Tag; 18 use s9e\TextFormatter\Configurator\JavaScript\RegexpConvertor; 19 use s9e\TextFormatter\Configurator\Validators\TagName; 20 use s9e\TextFormatter\Plugins\ConfiguratorBase; 21 class Configurator extends ConfiguratorBase 22 { 23 protected $captures; 24 protected $collection = []; 25 protected $delimiter; 26 protected $modifiers; 27 protected $references; 28 protected $referencesRegexp = '((?<!\\\\)(?:\\\\\\\\)*\\K(?:[$\\\\]\\d+|\\$\\{\\d+\\}))S'; 29 public function asConfig() 30 { 31 if (!\count($this->collection)) 32 return; 33 $pregs = []; 34 foreach ($this->collection as $_ca164be8) 35 { 36 list($tagName, $regexp, $passthroughIdx) = $_ca164be8; 37 $captures = RegexpParser::getCaptureNames($regexp); 38 $pregs[] = [$tagName, new Regexp($regexp, \true), $passthroughIdx, $captures]; 39 } 40 return ['generics' => $pregs]; 41 } 42 public function getJSHints() 43 { 44 $hasPassthrough = \false; 45 foreach ($this->collection as $_ca164be8) 46 { 47 list($tagName, $regexp, $passthroughIdx) = $_ca164be8; 48 if ($passthroughIdx) 49 { 50 $hasPassthrough = \true; 51 break; 52 } 53 } 54 return ['PREG_HAS_PASSTHROUGH' => $hasPassthrough]; 55 } 56 public function match($regexp, $tagName) 57 { 58 $tagName = TagName::normalize($tagName); 59 $passthroughIdx = 0; 60 $this->parseRegexp($regexp); 61 foreach ($this->captures as $i => $capture) 62 { 63 if (!$this->isCatchAll($capture['expr'])) 64 continue; 65 $passthroughIdx = $i; 66 } 67 $this->collection[] = [$tagName, $regexp, $passthroughIdx]; 68 } 69 public function replace($regexp, $template, $tagName = \null) 70 { 71 if (!isset($tagName)) 72 $tagName = 'PREG_' . \strtoupper(\dechex(\crc32($regexp))); 73 $this->parseRegexp($regexp); 74 $this->parseTemplate($template); 75 $passthroughIdx = $this->getPassthroughCapture(); 76 if ($passthroughIdx) 77 $this->captures[$passthroughIdx]['passthrough'] = \true; 78 $regexp = $this->fixUnnamedCaptures($regexp); 79 $template = $this->convertTemplate($template, $passthroughIdx); 80 $this->collection[] = [$tagName, $regexp, $passthroughIdx]; 81 return $this->createTag($tagName, $template); 82 } 83 protected function addAttribute(Tag $tag, $attrName) 84 { 85 $isUrl = \false; 86 $exprs = []; 87 foreach ($this->captures as $key => $capture) 88 { 89 if ($capture['name'] !== $attrName) 90 continue; 91 $exprs[] = $capture['expr']; 92 if (isset($this->references['asUrl'][$key])) 93 $isUrl = \true; 94 } 95 $exprs = \array_unique($exprs); 96 $regexp = $this->delimiter . '^'; 97 $regexp .= (\count($exprs) === 1) ? $exprs[0] : '(?:' . \implode('|', $exprs) . ')'; 98 $regexp .= '$' . $this->delimiter . 'D' . $this->modifiers; 99 $attribute = $tag->attributes->add($attrName); 100 $filter = $this->configurator->attributeFilters['#regexp']; 101 $filter->setRegexp($regexp); 102 $attribute->filterChain[] = $filter; 103 if ($isUrl) 104 { 105 $filter = $this->configurator->attributeFilters['#url']; 106 $attribute->filterChain[] = $filter; 107 } 108 } 109 protected function convertTemplate($template, $passthroughIdx) 110 { 111 $template = TemplateHelper::replaceTokens( 112 $template, 113 $this->referencesRegexp, 114 function ($m, $node) use ($passthroughIdx) 115 { 116 $key = (int) \trim($m[0], '\\${}'); 117 if ($key === 0) 118 return ['expression', '.']; 119 if ($key === $passthroughIdx && $node instanceof DOMText) 120 return ['passthrough']; 121 if (isset($this->captures[$key]['name'])) 122 return ['expression', '@' . $this->captures[$key]['name']]; 123 return ['literal', '']; 124 } 125 ); 126 $template = TemplateHelper::replaceTokens( 127 $template, 128 '(\\\\+[0-9${\\\\])', 129 function ($m) 130 { 131 return ['literal', \stripslashes($m[0])]; 132 } 133 ); 134 return $template; 135 } 136 protected function createTag($tagName, $template) 137 { 138 $tag = new Tag; 139 foreach ($this->captures as $key => $capture) 140 { 141 if (!isset($capture['name'])) 142 continue; 143 $attrName = $capture['name']; 144 if (isset($tag->attributes[$attrName])) 145 continue; 146 $this->addAttribute($tag, $attrName); 147 } 148 $tag->template = $template; 149 $this->configurator->templateNormalizer->normalizeTag($tag); 150 $this->configurator->templateChecker->checkTag($tag); 151 return $this->configurator->tags->add($tagName, $tag); 152 } 153 protected function fixUnnamedCaptures($regexp) 154 { 155 $keys = []; 156 foreach ($this->references['anywhere'] as $key) 157 { 158 $capture = $this->captures[$key]; 159 if (!$key || isset($capture['name'])) 160 continue; 161 if (isset($this->references['asUrl'][$key]) || !isset($capture['passthrough'])) 162 $keys[] = $key; 163 } 164 \rsort($keys); 165 foreach ($keys as $key) 166 { 167 $name = '_' . $key; 168 $pos = $this->captures[$key]['pos']; 169 $regexp = \substr_replace($regexp, "?'" . $name . "'", 2 + $pos, 0); 170 $this->captures[$key]['name'] = $name; 171 } 172 return $regexp; 173 } 174 protected function getPassthroughCapture() 175 { 176 $passthrough = 0; 177 foreach ($this->references['inText'] as $key) 178 { 179 if (!$this->isCatchAll($this->captures[$key]['expr'])) 180 continue; 181 if ($passthrough) 182 { 183 $passthrough = 0; 184 break; 185 } 186 $passthrough = (int) $key; 187 } 188 return $passthrough; 189 } 190 protected function getRegexpInfo($regexp) 191 { 192 if (@\preg_match_all($regexp, '') === \false) 193 throw new InvalidArgumentException('Invalid regexp'); 194 return RegexpParser::parse($regexp); 195 } 196 protected function isCatchAll($expr) 197 { 198 return (bool) \preg_match('(^\\.[*+]\\??$)D', $expr); 199 } 200 protected function parseRegexp($regexp) 201 { 202 $this->captures = [['name' => \null, 'expr' => \null]]; 203 $regexpInfo = $this->getRegexpInfo($regexp); 204 $this->delimiter = $regexpInfo['delimiter']; 205 $this->modifiers = \str_replace('D', '', $regexpInfo['modifiers']); 206 foreach ($regexpInfo['tokens'] as $token) 207 { 208 if ($token['type'] !== 'capturingSubpatternStart') 209 continue; 210 $this->captures[] = [ 211 'pos' => $token['pos'], 212 'name' => (isset($token['name'])) ? $token['name'] : \null, 213 'expr' => $token['content'] 214 ]; 215 } 216 } 217 protected function parseTemplate($template) 218 { 219 $this->references = [ 220 'anywhere' => [], 221 'asUrl' => [], 222 'inText' => [] 223 ]; 224 \preg_match_all($this->referencesRegexp, $template, $matches); 225 foreach ($matches[0] as $match) 226 { 227 $key = \trim($match, '\\${}'); 228 $this->references['anywhere'][$key] = $key; 229 } 230 $dom = TemplateHelper::loadTemplate($template); 231 $xpath = new DOMXPath($dom); 232 foreach ($xpath->query('//text()') as $node) 233 { 234 \preg_match_all($this->referencesRegexp, $node->textContent, $matches); 235 foreach ($matches[0] as $match) 236 { 237 $key = \trim($match, '\\${}'); 238 $this->references['inText'][$key] = $key; 239 } 240 } 241 foreach (TemplateHelper::getURLNodes($dom) as $node) 242 if ($node instanceof DOMAttr 243 && \preg_match('(^(?:[$\\\\]\\d+|\\$\\{\\d+\\}))', \trim($node->value), $m)) 244 { 245 $key = \trim($m[0], '\\${}'); 246 $this->references['asUrl'][$key] = $key; 247 } 248 $this->removeUnknownReferences(); 249 } 250 protected function removeUnknownReferences() 251 { 252 foreach ($this->references as &$references) 253 $references = \array_intersect_key($references, $this->captures); 254 } 255 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |