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