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

lexer.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 10.31 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\template\twig;
015   
016  class lexer extends \Twig\Lexer
017  {
018      public function tokenize(\Twig\Source $source)
019      {
020          $code = $source->getCode();
021          $filename = $source->getName();
022   
023          // Our phpBB tags
024          // Commented out tokens are handled separately from the main replace
025          $phpbb_tags = array(
026              /*'BEGIN',
027              'BEGINELSE',
028              'END',
029              'IF',
030              'ELSE',
031              'ELSEIF',
032              'ENDIF',
033              'DEFINE',
034              'UNDEFINE',*/
035              'ENDDEFINE',
036              'INCLUDE',
037              'INCLUDEPHP',
038              'INCLUDEJS',
039              'INCLUDECSS',
040              'PHP',
041              'ENDPHP',
042              'EVENT',
043          );
044   
045          // Twig tag masks
046          $twig_tags = array(
047              'autoescape',
048              'endautoescape',
049              'if',
050              'elseif',
051              'else',
052              'endif',
053              'block',
054              'endblock',
055              'use',
056              'extends',
057              'embed',
058              'filter',
059              'endfilter',
060              'flush',
061              'for',
062              'endfor',
063              'macro',
064              'endmacro',
065              'import',
066              'from',
067              'sandbox',
068              'endsandbox',
069              'set',
070              'endset',
071              'spaceless',
072              'endspaceless',
073              'verbatim',
074              'endverbatim',
075              'apply',
076              'endapply',
077          );
078   
079          // Fix tokens that may have inline variables (e.g. <!-- DEFINE $TEST = '{FOO}')
080          $code = $this->strip_surrounding_quotes(array(
081              'INCLUDE',
082              'INCLUDEPHP',
083              'INCLUDEJS',
084              'INCLUDECSS',
085          ), $code);
086          $code = $this->fix_inline_variable_tokens(array(
087              'DEFINE \$[a-zA-Z0-9_]+ =',
088              'INCLUDE',
089              'INCLUDEPHP',
090              'INCLUDEJS',
091              'INCLUDECSS',
092          ), $code);
093          $code = $this->add_surrounding_quotes(array(
094              'INCLUDE',
095              'INCLUDEPHP',
096              'INCLUDEJS',
097              'INCLUDECSS',
098          ), $code);
099   
100          // Fix our BEGIN statements
101          $code = $this->fix_begin_tokens($code);
102   
103          // Fix our IF tokens
104          $code = $this->fix_if_tokens($code);
105   
106          // Fix our DEFINE tokens
107          $code = $this->fix_define_tokens($code);
108   
109          // Replace all of our starting tokens, <!-- TOKEN --> with Twig style, {% TOKEN %}
110          // This also strips outer parenthesis, <!-- IF (blah) --> becomes <!-- IF blah -->
111          $code = preg_replace('#<!-- (' . implode('|', $phpbb_tags) . ')(?: (.*?) ?)?-->#', '{% $1 $2 %}', $code);
112   
113          // Replace all of our twig masks with Twig code (e.g. <!-- BLOCK .+ --> with {% block $1 %})
114          $code = $this->replace_twig_tag_masks($code, $twig_tags);
115   
116          // Replace all of our language variables, {L_VARNAME}, with Twig style, {{ lang('NAME') }}
117          // Appends any filters after lang()
118          $code = preg_replace('#{L_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2 }}', $code);
119   
120          // Replace all of our escaped language variables, {LA_VARNAME}, with Twig style, {{ lang('NAME')|escape('js') }}
121          // Appends any filters after lang(), but before escape('js')
122          $code = preg_replace('#{LA_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2|escape(\'js\') }}', $code);
123   
124          // Replace all of our variables, {VARNAME}, with Twig style, {{ VARNAME }}
125          // Appends any filters
126          $code = preg_replace('#{([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ $1$2 }}', $code);
127   
128          // Tokenize \Twig\Source instance
129          return parent::tokenize(new \Twig\Source($code, $filename));
130      }
131   
132      /**
133      * Strip surrounding quotes
134      *
135      * First step to fix tokens that may have inline variables
136      * E.g. <!-- INCLUDE '{TEST}.html' to <!-- INCLUDE {TEST}.html
137      *
138      * @param array $tokens array of tokens to search for (imploded to a regular expression)
139      * @param string $code
140      * @return string
141      */
142      protected function strip_surrounding_quotes($tokens, $code)
143      {
144          // Remove matching quotes at the beginning/end if a statement;
145          // E.g. 'asdf'"' -> asdf'"
146          // E.g. "asdf'"" -> asdf'"
147          // E.g. 'asdf'" -> 'asdf'"
148          return preg_replace('#<!-- (' . implode('|', $tokens) . ') (([\'"])?(.*?)\1) -->#', '<!-- $1 $2 -->', $code);
149      }
150   
151      /**
152      * Fix tokens that may have inline variables
153      *
154      * Second step to fix tokens that may have inline variables
155      * E.g. <!-- INCLUDE '{TEST}.html' to <!-- INCLUDE ' ~ {TEST} ~ '.html
156      *
157      * @param array $tokens array of tokens to search for (imploded to a regular expression)
158      * @param string $code
159      * @return string
160      */
161      protected function fix_inline_variable_tokens($tokens, $code)
162      {
163          $callback = function($matches)
164          {
165              // Replace template variables with start/end to parse variables (' ~ TEST ~ '.html)
166              $matches[2] = preg_replace('#{([a-zA-Z0-9_\.$]+)}#', "'~ \$1 ~'", $matches[2]);
167   
168              return "<!-- {$matches[1]} {$matches[2]} -->";
169          };
170   
171          return preg_replace_callback('#<!-- (' . implode('|', $tokens) . ') (.+?) -->#', $callback, $code);
172      }
173   
174      /**
175      * Add surrounding quotes
176      *
177      * Last step to fix tokens that may have inline variables
178      * E.g. <!-- INCLUDE '{TEST}.html' to <!-- INCLUDE '' ~ {TEST} ~ '.html'
179      *
180      * @param array $tokens array of tokens to search for (imploded to a regular expression)
181      * @param string $code
182      * @return string
183      */
184      protected function add_surrounding_quotes($tokens, $code)
185      {
186          return preg_replace('#<!-- (' . implode('|', $tokens) . ') (.+?) -->#', '<!-- $1 \'$2\' -->', $code);
187      }
188   
189      /**
190      * Fix begin tokens (convert our BEGIN to Twig for)
191      *
192      * Not meant to be used outside of this context, public because the anonymous function calls this
193      *
194      * @param string $code
195      * @param array $parent_nodes (used in recursion)
196      * @return string
197      */
198      public function fix_begin_tokens($code, $parent_nodes = array())
199      {
200          // PHP 5.3 cannot use $this in an anonymous function, so use this as a work-around
201          $parent_class = $this;
202          $callback = function ($matches) use ($parent_class, $parent_nodes)
203          {
204              $hard_parents = explode('.', $matches[1]);
205              array_pop($hard_parents); // ends with .
206              if ($hard_parents)
207              {
208                  $parent_nodes = array_merge($hard_parents, $parent_nodes);
209              }
210   
211              $name = $matches[2];
212              $subset = trim(substr($matches[3], 1, -1)); // Remove parenthesis
213              $body = $matches[4];
214   
215              // Replace <!-- BEGINELSE -->
216              $body = str_replace('<!-- BEGINELSE -->', '{% else %}', $body);
217   
218              // Is the designer wanting to call another loop in a loop?
219              // <!-- BEGIN loop -->
220              // <!-- BEGIN !loop2 -->
221              // <!-- END !loop2 -->
222              // <!-- END loop -->
223              // 'loop2' is actually on the same nesting level as 'loop' you assign
224              // variables to it with template->assign_block_vars('loop2', array(...))
225              if (strpos($name, '!') === 0)
226              {
227                  // Count the number if ! occurrences
228                  $count = substr_count($name, '!');
229                  for ($i = 0; $i < $count; $i++)
230                  {
231                      array_pop($parent_nodes);
232                      $name = substr($name, 1);
233                  }
234              }
235   
236              // Remove all parent nodes, e.g. foo, bar from foo.bar.foobar.VAR
237              foreach ($parent_nodes as $node)
238              {
239                  $body = preg_replace('#([^a-zA-Z0-9_])' . $node . '\.([a-zA-Z0-9_]+)\.#', '$1$2.', $body);
240              }
241   
242              // Add current node to list of parent nodes for child nodes
243              $parent_nodes[] = $name;
244   
245              // Recursive...fix any child nodes
246              $body = $parent_class->fix_begin_tokens($body, $parent_nodes);
247   
248              // Need the parent variable name
249              array_pop($parent_nodes);
250              $parent = (!empty($parent_nodes)) ? end($parent_nodes) . '.' : '';
251   
252              if ($subset !== '')
253              {
254                  $subset = '|subset(' . $subset . ')';
255              }
256   
257              $parent = ($parent) ?: 'loops.';
258              // Turn into a Twig for loop
259              return "{% for {$name} in {$parent}{$name}{$subset} %}{$body}{% endfor %}";
260          };
261   
262          return preg_replace_callback('#<!-- BEGIN ((?:[a-zA-Z0-9_]+\.)*)([!a-zA-Z0-9_]+)(\([0-9,\-]+\))? -->(.+?)<!-- END \1\2 -->#s', $callback, $code);
263      }
264   
265      /**
266      * Fix IF statements
267      *
268      * @param string $code
269      * @return string
270      */
271      protected function fix_if_tokens($code)
272      {
273          // Replace ELSE IF with ELSEIF
274          $code = preg_replace('#<!-- ELSE IF (.+?) -->#', '<!-- ELSEIF $1 -->', $code);
275   
276          // Replace our "div by" with Twig's divisibleby (Twig does not like test names with spaces)
277          $code = preg_replace('# div by ([0-9]+)#', ' divisibleby($1)', $code);
278   
279          $callback = function($matches)
280          {
281              $inner = $matches[2];
282              // Replace $TEST with definition.TEST
283              $inner = preg_replace('#(\s\(*!?)\$([a-zA-Z_0-9]+)#', '$1definition.$2', $inner);
284   
285              // Replace .foo with loops.foo|length
286              $inner = preg_replace('#(\s\(*!?)\.([a-zA-Z_0-9]+)([^a-zA-Z_0-9\.])#', '$1loops.$2|length$3', $inner);
287   
288              // Replace .foo.bar with foo.bar|length
289              $inner = preg_replace('#(\s\(*!?)\.([a-zA-Z_0-9\.]+)([^a-zA-Z_0-9\.])#', '$1$2|length$3', $inner);
290   
291              return "<!-- {$matches[1]}IF{$inner}-->";
292          };
293   
294          return preg_replace_callback('#<!-- (ELSE)?IF((.*?) (?:\(*!?[\$|\.]([^\s]+)(.*?))?)-->#', $callback, $code);
295      }
296   
297      /**
298      * Fix DEFINE statements and {$VARNAME} variables
299      *
300      * @param string $code
301      * @return string
302      */
303      protected function fix_define_tokens($code)
304      {
305          /**
306          * Changing $VARNAME to definition.varname because set is only local
307          * context (e.g. DEFINE $TEST will only make $TEST available in current
308          * template and any child templates, but not any parent templates).
309          *
310          * DEFINE handles setting it properly to definition in its node, but the
311          * variables reading FROM it need to be altered to definition.VARNAME
312          *
313          * Setting up definition as a class in the array passed to Twig
314          * ($context) makes set definition.TEST available in the global context
315          */
316   
317          // Replace <!-- DEFINE $NAME with {% DEFINE definition.NAME
318          $code = preg_replace('#<!-- DEFINE \$(.*?) -->#', '{% DEFINE $1 %}', $code);
319   
320          // Changing UNDEFINE NAME to DEFINE NAME = null to save from creating an extra token parser/node
321          $code = preg_replace('#<!-- UNDEFINE \$(.*?)-->#', '{% DEFINE $1= null %}', $code);
322   
323          // Replace all of our variables, {$VARNAME}, with Twig style, {{ definition.VARNAME }}
324          $code = preg_replace('#{\$([a-zA-Z0-9_\.]+)}#', '{{ definition.$1 }}', $code);
325   
326          // Replace all of our variables, ~ $VARNAME ~, with Twig style, ~ definition.VARNAME ~
327          $code = preg_replace('#~ \$([a-zA-Z0-9_\.]+) ~#', '~ definition.$1 ~', $code);
328   
329          return $code;
330      }
331   
332      /**
333      * Replace Twig tag masks with Twig tag calls
334      *
335      * E.g. <!-- BLOCK foo --> with {% block foo %}
336      *
337      * @param string $code
338      * @param array $twig_tags All tags we want to create a mask for
339      * @return string
340      */
341      protected function replace_twig_tag_masks($code, $twig_tags)
342      {
343          $callback = function ($matches)
344          {
345              $matches[1] = strtolower($matches[1]);
346   
347              return "{% {$matches[1]}{$matches[2]}%}";
348          };
349   
350          foreach ($twig_tags as &$tag)
351          {
352              $tag = strtoupper($tag);
353          }
354   
355          // twig_tags is an array of the twig tags, which are all lowercase, but we use all uppercase tags
356          $code = preg_replace_callback('#<!-- (' . implode('|', $twig_tags) . ')(.*?)-->#',$callback, $code);
357   
358          return $code;
359      }
360  }
361