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

Serializer.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 10.83 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\Configurator\RendererGenerators\PHP;
009   
010  use DOMElement;
011  use DOMXPath;
012  use RuntimeException;
013  use s9e\TextFormatter\Configurator\Helpers\AVTHelper;
014  use s9e\TextFormatter\Configurator\Helpers\TemplateParser;
015   
016  class Serializer
017  {
018      /**
019      * @var XPathConvertor XPath-to-PHP convertor
020      */
021      public $convertor;
022   
023      /**
024      * @var array Value of the "void" attribute of all elements, using the element's "id" as key
025      */
026      protected $isVoid;
027   
028      /**
029      * @var DOMXPath
030      */
031      protected $xpath;
032   
033      /**
034      * Constructor
035      */
036      public function __construct()
037      {
038          $this->convertor = new XPathConvertor;
039      }
040   
041      /**
042      * Convert an XPath expression (used in a condition) into PHP code
043      *
044      * This method is similar to convertXPath() but it selectively replaces some simple conditions
045      * with the corresponding DOM method for performance reasons
046      *
047      * @param  string $expr XPath expression
048      * @return string       PHP code
049      */
050      public function convertCondition($expr)
051      {
052          return $this->convertor->convertCondition($expr);
053      }
054   
055      /**
056      * Convert an XPath expression (used as value) into PHP code
057      *
058      * @param  string $expr XPath expression
059      * @return string       PHP code
060      */
061      public function convertXPath($expr)
062      {
063          $php = $this->convertor->convertXPath($expr);
064          if (is_numeric($php))
065          {
066              $php = "'" . $php . "'";
067          }
068   
069          return $php;
070      }
071   
072      /**
073      * Serialize the internal representation of a template into PHP
074      *
075      * @param  DOMElement $ir Internal representation
076      * @return string
077      */
078      public function serialize(DOMElement $ir)
079      {
080          $this->xpath  = new DOMXPath($ir->ownerDocument);
081          $this->isVoid = [];
082          foreach ($this->xpath->query('//element') as $element)
083          {
084              $this->isVoid[$element->getAttribute('id')] = $element->getAttribute('void');
085          }
086   
087          return $this->serializeChildren($ir);
088      }
089   
090      /**
091      * Convert an attribute value template into PHP
092      *
093      * NOTE: escaping must be performed by the caller
094      *
095      * @link https://www.w3.org/TR/1999/REC-xslt-19991116#dt-attribute-value-template
096      *
097      * @param  string $attrValue Attribute value template
098      * @return string
099      */
100      protected function convertAttributeValueTemplate($attrValue)
101      {
102          $phpExpressions = [];
103          foreach (AVTHelper::parse($attrValue) as $token)
104          {
105              if ($token[0] === 'literal')
106              {
107                  $phpExpressions[] = var_export($token[1], true);
108              }
109              else
110              {
111                  $phpExpressions[] = $this->convertXPath($token[1]);
112              }
113          }
114   
115          return implode('.', $phpExpressions);
116      }
117   
118      /**
119      * Convert a dynamic xsl:attribute/xsl:element name into PHP
120      *
121      * @param  string $attrValue Attribute value template
122      * @return string
123      */
124      protected function convertDynamicNodeName(string $attrValue): string
125      {
126          if (strpos($attrValue, '{') === false)
127          {
128              return var_export(htmlspecialchars($attrValue, ENT_QUOTES), true);
129          }
130   
131          return 'htmlspecialchars(' . $this->convertAttributeValueTemplate($attrValue) . ',' . ENT_QUOTES . ')';
132      }
133   
134      /**
135      * Escape given literal
136      *
137      * @param  string $text    Literal
138      * @param  string $context Either "raw", "text" or "attribute"
139      * @return string          Escaped literal
140      */
141      protected function escapeLiteral($text, $context)
142      {
143          if ($context === 'raw')
144          {
145              return $text;
146          }
147   
148          $escapeMode = ($context === 'attribute') ? ENT_COMPAT : ENT_NOQUOTES;
149   
150          return htmlspecialchars($text, $escapeMode);
151      }
152   
153      /**
154      * Escape the output of given PHP expression
155      *
156      * @param  string $php     PHP expression
157      * @param  string $context Either "raw", "text" or "attribute"
158      * @return string          PHP expression, including escaping mechanism
159      */
160      protected function escapePHPOutput($php, $context)
161      {
162          if ($context === 'raw')
163          {
164              return $php;
165          }
166   
167          $escapeMode = ($context === 'attribute') ? ENT_COMPAT : ENT_NOQUOTES;
168   
169          return 'htmlspecialchars(' . $php . ',' . $escapeMode . ')';
170      }
171   
172      /**
173      * Test whether given switch has more than one non-default case
174      *
175      * @param  DOMElement $switch <switch/> node
176      * @return bool
177      */
178      protected function hasMultipleCases(DOMElement $switch)
179      {
180          return $this->xpath->evaluate('count(case[@test]) > 1', $switch);
181      }
182   
183      /**
184      * Test whether given attribute declaration is a minimizable boolean attribute
185      *
186      * @param  DOMElement $attribute <attribute/> node
187      * @param  string     $php       Attribute content, in PHP
188      * @return boolean
189      */
190      protected function isBooleanAttribute(DOMElement $attribute, string $php): bool
191      {
192          if ($attribute->getAttribute('boolean') !== 'yes')
193          {
194              return false;
195          }
196   
197          return ($php === '' || $php === "\$this->out.='" . $attribute->getAttribute('name') . "';");
198      }
199   
200      /**
201      * Serialize an <applyTemplates/> node
202      *
203      * @param  DOMElement $applyTemplates <applyTemplates/> node
204      * @return string
205      */
206      protected function serializeApplyTemplates(DOMElement $applyTemplates)
207      {
208          $php = '$this->at($node';
209          if ($applyTemplates->hasAttribute('select'))
210          {
211              $php .= ',' . var_export($applyTemplates->getAttribute('select'), true);
212          }
213          $php .= ');';
214   
215          return $php;
216      }
217   
218      /**
219      * Serialize an <attribute/> node
220      *
221      * @param  DOMElement $attribute <attribute/> node
222      * @return string
223      */
224      protected function serializeAttribute(DOMElement $attribute)
225      {
226          $attrName = $attribute->getAttribute('name');
227   
228          // PHP representation of this attribute's name
229          $phpAttrName = $this->convertDynamicNodeName($attrName);
230   
231          $php     = "\$this->out.=' '." . $phpAttrName;
232          $content = $this->serializeChildren($attribute);
233          if (!$this->isBooleanAttribute($attribute, $content))
234          {
235              $php .= ".'=\"';" . $content . "\$this->out.='\"'";
236          }
237          $php .= ';';
238   
239          return $php;
240      }
241   
242      /**
243      * Serialize all the children of given node into PHP
244      *
245      * @param  DOMElement $ir Internal representation
246      * @return string
247      */
248      protected function serializeChildren(DOMElement $ir)
249      {
250          $php = '';
251          foreach ($ir->childNodes as $node)
252          {
253              if ($node instanceof DOMElement)
254              {
255                  $methodName = 'serialize' . ucfirst($node->localName);
256                  $php .= $this->$methodName($node);
257              }
258          }
259   
260          return $php;
261      }
262   
263      /**
264      * Serialize a <closeTag/> node
265      *
266      * @param  DOMElement $closeTag <closeTag/> node
267      * @return string
268      */
269      protected function serializeCloseTag(DOMElement $closeTag)
270      {
271          $php = "\$this->out.='>';";
272          $id  = $closeTag->getAttribute('id');
273   
274          if ($closeTag->hasAttribute('set'))
275          {
276              $php .= '$t' . $id . '=1;';
277          }
278   
279          if ($closeTag->hasAttribute('check'))
280          {
281              $php = 'if(!isset($t' . $id . ')){' . $php . '}';
282          }
283   
284          if ($this->isVoid[$id] === 'maybe')
285          {
286              // Check at runtime whether this element is not void
287              $php .= 'if(!$v' . $id . '){';
288          }
289   
290          return $php;
291      }
292   
293      /**
294      * Serialize a <comment/> node
295      *
296      * @param  DOMElement $comment <comment/> node
297      * @return string
298      */
299      protected function serializeComment(DOMElement $comment)
300      {
301          return "\$this->out.='<!--';"
302               . $this->serializeChildren($comment)
303               . "\$this->out.='-->';";
304      }
305   
306      /**
307      * Serialize a <copyOfAttributes/> node
308      *
309      * @param  DOMElement $copyOfAttributes <copyOfAttributes/> node
310      * @return string
311      */
312      protected function serializeCopyOfAttributes(DOMElement $copyOfAttributes)
313      {
314          return 'foreach($node->attributes as $attribute)'
315               . '{'
316               . "\$this->out.=' ';"
317               . "\$this->out.=\$attribute->name;"
318               . "\$this->out.='=\"';"
319               . "\$this->out.=htmlspecialchars(\$attribute->value," . ENT_COMPAT . ");"
320               . "\$this->out.='\"';"
321               . '}';
322      }
323   
324      /**
325      * Serialize an <element/> node
326      *
327      * @param  DOMElement $element <element/> node
328      * @return string
329      */
330      protected function serializeElement(DOMElement $element)
331      {
332          $php     = '';
333          $elName  = $element->getAttribute('name');
334          $id      = $element->getAttribute('id');
335          $isVoid  = $element->getAttribute('void');
336   
337          // Test whether this element name is dynamic
338          $isDynamic = (bool) (strpos($elName, '{') !== false);
339   
340          // PHP representation of this element's name
341          $phpElName = $this->convertDynamicNodeName($elName);
342   
343          // If the element name is dynamic, we cache its name for convenience and performance
344          if ($isDynamic)
345          {
346              $varName = '$e' . $id;
347   
348              // Add the var declaration to the source
349              $php .= $varName . '=' . $phpElName . ';';
350   
351              // Replace the element name with the var
352              $phpElName = $varName;
353          }
354   
355          // Test whether this element is void if we need this information
356          if ($isVoid === 'maybe')
357          {
358              $php .= '$v' . $id . '=preg_match(' . var_export(TemplateParser::$voidRegexp, true) . ',' . $phpElName . ');';
359          }
360   
361          // Open the start tag
362          $php .= "\$this->out.='<'." . $phpElName . ';';
363   
364          // Serialize this element's content
365          $php .= $this->serializeChildren($element);
366   
367          // Close that element unless we know it's void
368          if ($isVoid !== 'yes')
369          {
370              $php .= "\$this->out.='</'." . $phpElName . ".'>';";
371          }
372   
373          // If this element was maybe void, serializeCloseTag() has put its content within an if
374          // block. We need to close that block
375          if ($isVoid === 'maybe')
376          {
377              $php .= '}';
378          }
379   
380          return $php;
381      }
382   
383      /**
384      * Serialize a <switch/> node that has a branch-key attribute
385      *
386      * @param  DOMElement $switch <switch/> node
387      * @return string
388      */
389      protected function serializeHash(DOMElement $switch)
390      {
391          $statements = [];
392          foreach ($this->xpath->query('case[@branch-values]', $switch) as $case)
393          {
394              foreach (unserialize($case->getAttribute('branch-values')) as $value)
395              {
396                  $statements[$value] = $this->serializeChildren($case);
397              }
398          }
399          if (!isset($case))
400          {
401              throw new RuntimeException;
402          }
403   
404          $defaultCase = $this->xpath->query('case[not(@branch-values)]', $switch)->item(0);
405          $defaultCode = ($defaultCase instanceof DOMElement) ? $this->serializeChildren($defaultCase) : '';
406          $expr        = $this->convertXPath($switch->getAttribute('branch-key'));
407   
408          return SwitchStatement::generate($expr, $statements, $defaultCode);
409      }
410   
411      /**
412      * Serialize an <output/> node
413      *
414      * @param  DOMElement $output <output/> node
415      * @return string
416      */
417      protected function serializeOutput(DOMElement $output)
418      {
419          $context = $output->getAttribute('escape');
420   
421          $php = '$this->out.=';
422          if ($output->getAttribute('type') === 'xpath')
423          {
424              $php .= $this->escapePHPOutput($this->convertXPath($output->textContent), $context);
425          }
426          else
427          {
428              $php .= var_export($this->escapeLiteral($output->textContent, $context), true);
429          }
430          $php .= ';';
431   
432          return $php;
433      }
434   
435      /**
436      * Serialize a <switch/> node
437      *
438      * @param  DOMElement $switch <switch/> node
439      * @return string
440      */
441      protected function serializeSwitch(DOMElement $switch)
442      {
443          // Use a specialized branch table if the minimum number of branches is reached
444          if ($switch->hasAttribute('branch-key') && $this->hasMultipleCases($switch))
445          {
446              return $this->serializeHash($switch);
447          }
448   
449          $php   = '';
450          $if    = 'if';
451          foreach ($this->xpath->query('case', $switch) as $case)
452          {
453              if ($case->hasAttribute('test'))
454              {
455                  $php .= $if . '(' . $this->convertCondition($case->getAttribute('test')) . ')';
456              }
457              else
458              {
459                  $php .= 'else';
460              }
461   
462              $php .= '{' . $this->serializeChildren($case) . '}';
463              $if   = 'elseif';
464          }
465   
466          return $php;
467      }
468  }