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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Configurator.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 9.99 KiB


001  <?php
002   
003  /**
004  * @package   s9e\TextFormatter
005  * @copyright Copyright (c) 2010-2022 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\TextFormatter\Plugins\HTMLElements;
009   
010  use InvalidArgumentException;
011  use RuntimeException;
012  use s9e\TextFormatter\Configurator\Helpers\RegexpBuilder;
013  use s9e\TextFormatter\Configurator\Items\Tag;
014  use s9e\TextFormatter\Configurator\Items\UnsafeTemplate;
015  use s9e\TextFormatter\Configurator\JavaScript\Dictionary;
016  use s9e\TextFormatter\Configurator\Validators\AttributeName;
017  use s9e\TextFormatter\Configurator\Validators\TagName;
018  use s9e\TextFormatter\Plugins\ConfiguratorBase;
019   
020  class Configurator extends ConfiguratorBase
021  {
022      /**
023      * @var array 2D array using HTML element names as keys, each value being an associative array
024      *            using HTML attribute names as keys and their alias as values. A special empty entry
025      *            is used to store the HTML element's alias
026      */
027      protected $aliases = [];
028   
029      /**
030      * @var array  Default filter of a few known attributes
031      *
032      * It doesn't make much sense to try to declare every known HTML attribute here. Validation is
033      * not the purpose of this plugin. It does make sense however to declare URL attributes as such,
034      * so that they are subject to our constraints (disallowed hosts, etc...)
035      *
036      * @see scripts/patchHTMLElementConfigurator.php
037      */
038      protected $attributeFilters = [
039          'action'     => '#url',
040          'cite'       => '#url',
041          'data'       => '#url',
042          'formaction' => '#url',
043          'href'       => '#url',
044          'icon'       => '#url',
045          'itemtype'   => '#url',
046          'longdesc'   => '#url',
047          'manifest'   => '#url',
048          'ping'       => '#url',
049          'poster'     => '#url',
050          'src'        => '#url'
051      ];
052   
053      /**
054      * @var array  Hash of allowed HTML elements. Element names are lowercased and used as keys for
055      *             this array
056      */
057      protected $elements = [];
058   
059      /**
060      * @var string Namespace prefix of the tags produced by this plugin's parser
061      */
062      protected $prefix = 'html';
063   
064      /**
065      * {@inheritdoc}
066      */
067      protected $quickMatch = '<';
068   
069      /**
070      * @var array  Blacklist of elements that are considered unsafe
071      */
072      protected $unsafeElements = [
073          'base',
074          'embed',
075          'frame',
076          'iframe',
077          'meta',
078          'object',
079          'script'
080      ];
081   
082      /**
083      * @var array  Blacklist of attributes that are considered unsafe, in addition of any attribute
084      *             whose name starts with "on" such as "onmouseover"
085      */
086      protected $unsafeAttributes = [
087          'style',
088          'target'
089      ];
090   
091      /**
092      * Alias the HTML attribute of given HTML element to a given attribute name
093      *
094      * NOTE: will *not* create the target attribute
095      *
096      * @param  string $elName   Name of the HTML element
097      * @param  string $attrName Name of the HTML attribute
098      * @param  string $alias    Alias
099      * @return void
100      */
101      public function aliasAttribute($elName, $attrName, $alias)
102      {
103          $elName   = $this->normalizeElementName($elName);
104          $attrName = $this->normalizeAttributeName($attrName);
105   
106          $this->aliases[$elName][$attrName] = AttributeName::normalize($alias);
107      }
108   
109      /**
110      * Alias an HTML element to a given tag name
111      *
112      * NOTE: will *not* create the target tag
113      *
114      * @param  string $elName  Name of the HTML element
115      * @param  string $tagName Name of the tag
116      * @return void
117      */
118      public function aliasElement($elName, $tagName)
119      {
120          $elName = $this->normalizeElementName($elName);
121   
122          $this->aliases[$elName][''] = TagName::normalize($tagName);
123      }
124   
125      /**
126      * Allow an HTML element to be used
127      *
128      * @param  string $elName Name of the element
129      * @return Tag            Tag that represents this element
130      */
131      public function allowElement($elName)
132      {
133          return $this->allowElementWithSafety($elName, false);
134      }
135   
136      /**
137      * Allow an unsafe HTML element to be used
138      *
139      * @param  string $elName Name of the element
140      * @return Tag            Tag that represents this element
141      */
142      public function allowUnsafeElement($elName)
143      {
144          return $this->allowElementWithSafety($elName, true);
145      }
146   
147      /**
148      * Allow a (potentially unsafe) HTML element to be used
149      *
150      * @param  string $elName      Name of the element
151      * @param  bool   $allowUnsafe Whether to allow unsafe elements
152      * @return Tag                 Tag that represents this element
153      */
154      protected function allowElementWithSafety($elName, $allowUnsafe)
155      {
156          $elName  = $this->normalizeElementName($elName);
157          $tagName = $this->prefix . ':' . $elName;
158   
159          if (!$allowUnsafe && in_array($elName, $this->unsafeElements))
160          {
161              throw new RuntimeException("'" . $elName . "' elements are unsafe and are disabled by default. Please use " . __CLASS__ . '::allowUnsafeElement() to bypass this security measure');
162          }
163   
164          // Retrieve or create the tag
165          $tag = ($this->configurator->tags->exists($tagName))
166               ? $this->configurator->tags->get($tagName)
167               : $this->configurator->tags->add($tagName);
168   
169          // Rebuild this tag's template
170          $this->rebuildTemplate($tag, $elName, $allowUnsafe);
171   
172          // Record the element name
173          $this->elements[$elName] = 1;
174   
175          return $tag;
176      }
177   
178      /**
179      * Allow an attribute to be used in an HTML element
180      *
181      * @param  string $elName   Name of the element
182      * @param  string $attrName Name of the attribute
183      * @return \s9e\Configurator\Items\Attribute
184      */
185      public function allowAttribute($elName, $attrName)
186      {
187          return $this->allowAttributeWithSafety($elName, $attrName, false);
188      }
189   
190      /**
191      * Allow an unsafe attribute to be used in an HTML element
192      *
193      * @param  string $elName   Name of the element
194      * @param  string $attrName Name of the attribute
195      * @return \s9e\Configurator\Items\Attribute
196      */
197      public function allowUnsafeAttribute($elName, $attrName)
198      {
199          return $this->allowAttributeWithSafety($elName, $attrName, true);
200      }
201   
202      /**
203      * Allow a (potentially unsafe) attribute to be used in an HTML element
204      *
205      * @param  string $elName   Name of the element
206      * @param  string $attrName Name of the attribute
207      * @param  bool   $allowUnsafe
208      * @return \s9e\Configurator\Items\Attribute
209      */
210      protected function allowAttributeWithSafety($elName, $attrName, $allowUnsafe)
211      {
212          $elName   = $this->normalizeElementName($elName);
213          $attrName = $this->normalizeAttributeName($attrName);
214          $tagName  = $this->prefix . ':' . $elName;
215   
216          if (!isset($this->elements[$elName]))
217          {
218              throw new RuntimeException("Element '" . $elName . "' has not been allowed");
219          }
220   
221          if (!$allowUnsafe)
222          {
223              if (substr($attrName, 0, 2) === 'on'
224               || in_array($attrName, $this->unsafeAttributes))
225              {
226                  throw new RuntimeException("'" . $attrName . "' attributes are unsafe and are disabled by default. Please use " . __CLASS__ . '::allowUnsafeAttribute() to bypass this security measure');
227              }
228          }
229   
230          $tag = $this->configurator->tags->get($tagName);
231          if (!isset($tag->attributes[$attrName]))
232          {
233              $attribute = $tag->attributes->add($attrName);
234              $attribute->required = false;
235   
236              if (isset($this->attributeFilters[$attrName]))
237              {
238                  $filterName = $this->attributeFilters[$attrName];
239                  $filter = $this->configurator->attributeFilters->get($filterName);
240   
241                  $attribute->filterChain->append($filter);
242              }
243          }
244   
245          // Rebuild this tag's template
246          $this->rebuildTemplate($tag, $elName, $allowUnsafe);
247   
248          return $tag->attributes[$attrName];
249      }
250   
251      /**
252      * Validate and normalize an element name
253      *
254      * Accepts any name that would be valid, regardless of whether this element exists in HTML5.
255      * Might be slightly off as the HTML5 specs don't seem to require it to start with a letter but
256      * our implementation does.
257      *
258      * @link http://dev.w3.org/html5/spec/syntax.html#syntax-tag-name
259      *
260      * @param  string $elName Original element name
261      * @return string         Normalized element name, in lowercase
262      */
263      protected function normalizeElementName($elName)
264      {
265          if (!preg_match('#^[a-z][a-z0-9]*$#Di', $elName))
266          {
267              throw new InvalidArgumentException("Invalid element name '" . $elName . "'");
268          }
269   
270          return strtolower($elName);
271      }
272   
273      /**
274      * Validate and normalize an attribute name
275      *
276      * More restrictive than the specs but allows all HTML5 attributes and more.
277      *
278      * @param  string $attrName Original attribute name
279      * @return string           Normalized attribute name, in lowercase
280      */
281      protected function normalizeAttributeName($attrName)
282      {
283          if (!preg_match('#^[a-z][-\\w]*$#Di', $attrName))
284          {
285              throw new InvalidArgumentException("Invalid attribute name '" . $attrName . "'");
286          }
287   
288          return strtolower($attrName);
289      }
290   
291      /**
292      * Rebuild a tag's template
293      *
294      * @param  Tag    $tag         Source tag
295      * @param  string $elName      Name of the HTML element created by the template
296      * @param  bool   $allowUnsafe Whether to allow unsafe markup
297      * @return void
298      */
299      protected function rebuildTemplate(Tag $tag, $elName, $allowUnsafe)
300      {
301          $template = '<' . $elName . '>';
302          foreach ($tag->attributes as $attrName => $attribute)
303          {
304              $template .= '<xsl:copy-of select="@' . $attrName . '"/>';
305          }
306          $template .= '<xsl:apply-templates/></' . $elName . '>';
307   
308          if ($allowUnsafe)
309          {
310              $template = new UnsafeTemplate($template);
311          }
312   
313          $tag->setTemplate($template);
314      }
315   
316      /**
317      * Generate this plugin's config
318      *
319      * @return array|null
320      */
321      public function asConfig()
322      {
323          if (empty($this->elements) && empty($this->aliases))
324          {
325              return;
326          }
327   
328          /**
329          * Regexp used to match an attributes definition (name + value if applicable)
330          *
331          * @link http://dev.w3.org/html5/spec/syntax.html#attributes-0
332          */
333          $attrRegexp = '[a-z][-a-z0-9]*(?>\\s*=\\s*(?>"[^"]*"|\'[^\']*\'|[^\\s"\'=<>`]+))?';
334          $tagRegexp  = RegexpBuilder::fromList(array_merge(
335              array_keys($this->aliases),
336              array_keys($this->elements)
337          ));
338   
339          $endTagRegexp   = '/(' . $tagRegexp . ')';
340          $startTagRegexp = '(' . $tagRegexp . ')((?>\\s+' . $attrRegexp . ')*+)\\s*/?';
341   
342          $regexp = '#<(?>' . $endTagRegexp . '|' . $startTagRegexp . ')\\s*>#i';
343   
344          $config = [
345              'quickMatch' => $this->quickMatch,
346              'prefix'     => $this->prefix,
347              'regexp'     => $regexp
348          ];
349   
350          if (!empty($this->aliases))
351          {
352              // Preserve the aliases array's keys in JavaScript
353              $config['aliases'] = new Dictionary;
354              foreach ($this->aliases as $elName => $aliases)
355              {
356                  $config['aliases'][$elName] = new Dictionary($aliases);
357              }
358          }
359   
360          return $config;
361      }
362   
363      /**
364      * {@inheritdoc}
365      */
366      public function getJSHints()
367      {
368          return ['HTMLELEMENTS_HAS_ALIASES' => (int) !empty($this->aliases)];
369      }
370  }