443
by dcoles
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0 |
1 |
<?php
|
2 |
/**
|
|
3 |
*
|
|
4 |
* @package phpBB3
|
|
5 |
* @version $Id: functions_template.php,v 1.47 2007/10/05 14:30:10 acydburn Exp $
|
|
6 |
* @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
|
|
7 |
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
|
|
8 |
*
|
|
9 |
*/
|
|
10 |
||
11 |
/**
|
|
12 |
* @ignore
|
|
13 |
*/
|
|
14 |
if (!defined('IN_PHPBB')) |
|
15 |
{
|
|
16 |
exit; |
|
17 |
}
|
|
18 |
||
19 |
/**
|
|
20 |
* Extension of template class - Functions needed for compiling templates only.
|
|
21 |
*
|
|
22 |
* psoTFX, phpBB Development Team - Completion of file caching, decompilation
|
|
23 |
* routines and implementation of conditionals/keywords and associated changes
|
|
24 |
*
|
|
25 |
* The interface was inspired by PHPLib templates, and the template file (formats are
|
|
26 |
* quite similar)
|
|
27 |
*
|
|
28 |
* The keyword/conditional implementation is currently based on sections of code from
|
|
29 |
* the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released
|
|
30 |
* (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code
|
|
31 |
* derived from an LGPL application may be relicenced under the GPL, this applies
|
|
32 |
* to this source
|
|
33 |
*
|
|
34 |
* DEFINE directive inspired by a request by Cyberalien
|
|
35 |
*
|
|
36 |
* @package phpBB3
|
|
37 |
*/
|
|
38 |
class template_compile |
|
39 |
{
|
|
40 |
var $template; |
|
41 |
||
42 |
// Various storage arrays
|
|
43 |
var $block_names = array(); |
|
44 |
var $block_else_level = array(); |
|
45 |
||
46 |
/**
|
|
47 |
* constuctor
|
|
48 |
*/
|
|
49 |
function template_compile(&$template) |
|
50 |
{
|
|
51 |
$this->template = &$template; |
|
52 |
}
|
|
53 |
||
54 |
/**
|
|
55 |
* Load template source from file
|
|
56 |
* @access private
|
|
57 |
*/
|
|
58 |
function _tpl_load_file($handle, $store_in_db = false) |
|
59 |
{
|
|
60 |
// Try and open template for read
|
|
61 |
if (!file_exists($this->template->files[$handle])) |
|
62 |
{
|
|
63 |
trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); |
|
64 |
}
|
|
65 |
||
66 |
$this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle]))); |
|
67 |
||
68 |
// Actually compile the code now.
|
|
69 |
$this->compile_write($handle, $this->template->compiled_code[$handle]); |
|
70 |
||
71 |
// Store in database if required...
|
|
72 |
if ($store_in_db) |
|
73 |
{
|
|
74 |
global $db, $user; |
|
75 |
||
76 |
$sql_ary = array( |
|
77 |
'template_id' => $user->theme['template_id'], |
|
78 |
'template_filename' => $this->template->filename[$handle], |
|
79 |
'template_included' => '', |
|
80 |
'template_mtime' => time(), |
|
81 |
'template_data' => trim(@file_get_contents($this->template->files[$handle])), |
|
82 |
);
|
|
83 |
||
84 |
$sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); |
|
85 |
$db->sql_query($sql); |
|
86 |
}
|
|
87 |
}
|
|
88 |
||
89 |
/**
|
|
90 |
* Remove any PHP tags that do not belong, these regular expressions are derived from
|
|
91 |
* the ones that exist in zend_language_scanner.l
|
|
92 |
* @access private
|
|
93 |
*/
|
|
94 |
function remove_php_tags(&$code) |
|
95 |
{
|
|
96 |
// This matches the information gathered from the internal PHP lexer
|
|
97 |
$match = array( |
|
98 |
'#<([\?%])=?.*?\1>#s', |
|
99 |
'#<script\s+language\s*=\s*(["\']?)php\1\s*>.*?</script\s*>#s', |
|
100 |
'#<\?php(?:\r\n?|[ \n\t]).*?\?>#s'
|
|
101 |
);
|
|
102 |
||
103 |
$code = preg_replace($match, '', $code); |
|
104 |
}
|
|
105 |
||
106 |
/**
|
|
107 |
* The all seeing all doing compile method. Parts are inspired by or directly from Smarty
|
|
108 |
* @access private
|
|
109 |
*/
|
|
110 |
function compile($code, $no_echo = false, $echo_var = '') |
|
111 |
{
|
|
112 |
global $config; |
|
113 |
||
114 |
if ($echo_var) |
|
115 |
{
|
|
116 |
global $$echo_var; |
|
117 |
}
|
|
118 |
||
119 |
// Remove any "loose" php ... we want to give admins the ability
|
|
120 |
// to switch on/off PHP for a given template. Allowing unchecked
|
|
121 |
// php is a no-no. There is a potential issue here in that non-php
|
|
122 |
// content may be removed ... however designers should use entities
|
|
123 |
// if they wish to display < and >
|
|
124 |
$this->remove_php_tags($code); |
|
125 |
||
126 |
// Pull out all block/statement level elements and separate plain text
|
|
127 |
preg_match_all('#<!-- PHP -->(.*?)<!-- ENDPHP -->#s', $code, $matches); |
|
128 |
$php_blocks = $matches[1]; |
|
129 |
$code = preg_replace('#<!-- PHP -->.*?<!-- ENDPHP -->#s', '<!-- PHP -->', $code); |
|
130 |
||
131 |
preg_match_all('#<!-- INCLUDE ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches); |
|
132 |
$include_blocks = $matches[1]; |
|
133 |
$code = preg_replace('#<!-- INCLUDE [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDE -->', $code); |
|
134 |
||
135 |
preg_match_all('#<!-- INCLUDEPHP ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches); |
|
136 |
$includephp_blocks = $matches[1]; |
|
137 |
$code = preg_replace('#<!-- INCLUDEPHP [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDEPHP -->', $code); |
|
138 |
||
139 |
preg_match_all('#<!-- ([^<].*?) (.*?)? ?-->#', $code, $blocks, PREG_SET_ORDER); |
|
140 |
||
141 |
$text_blocks = preg_split('#<!-- [^<].*? (?:.*?)? ?-->#', $code); |
|
142 |
||
143 |
for ($i = 0, $j = sizeof($text_blocks); $i < $j; $i++) |
|
144 |
{
|
|
145 |
$this->compile_var_tags($text_blocks[$i]); |
|
146 |
}
|
|
147 |
$compile_blocks = array(); |
|
148 |
||
149 |
for ($curr_tb = 0, $tb_size = sizeof($blocks); $curr_tb < $tb_size; $curr_tb++) |
|
150 |
{
|
|
151 |
$block_val = &$blocks[$curr_tb]; |
|
152 |
||
153 |
switch ($block_val[1]) |
|
154 |
{
|
|
155 |
case 'BEGIN': |
|
156 |
$this->block_else_level[] = false; |
|
157 |
$compile_blocks[] = '<?php ' . $this->compile_tag_block($block_val[2]) . ' ?>'; |
|
158 |
break; |
|
159 |
||
160 |
case 'BEGINELSE': |
|
161 |
$this->block_else_level[sizeof($this->block_else_level) - 1] = true; |
|
162 |
$compile_blocks[] = '<?php }} else { ?>'; |
|
163 |
break; |
|
164 |
||
165 |
case 'END': |
|
166 |
array_pop($this->block_names); |
|
167 |
$compile_blocks[] = '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>'; |
|
168 |
break; |
|
169 |
||
170 |
case 'IF': |
|
171 |
$compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], false) . ' ?>'; |
|
172 |
break; |
|
173 |
||
174 |
case 'ELSE': |
|
175 |
$compile_blocks[] = '<?php } else { ?>'; |
|
176 |
break; |
|
177 |
||
178 |
case 'ELSEIF': |
|
179 |
$compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], true) . ' ?>'; |
|
180 |
break; |
|
181 |
||
182 |
case 'ENDIF': |
|
183 |
$compile_blocks[] = '<?php } ?>'; |
|
184 |
break; |
|
185 |
||
186 |
case 'DEFINE': |
|
187 |
$compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], true) . ' ?>'; |
|
188 |
break; |
|
189 |
||
190 |
case 'UNDEFINE': |
|
191 |
$compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], false) . ' ?>'; |
|
192 |
break; |
|
193 |
||
194 |
case 'INCLUDE': |
|
195 |
$temp = array_shift($include_blocks); |
|
196 |
$compile_blocks[] = '<?php ' . $this->compile_tag_include($temp) . ' ?>'; |
|
197 |
$this->template->_tpl_include($temp, false); |
|
198 |
break; |
|
199 |
||
200 |
case 'INCLUDEPHP': |
|
201 |
$compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : ''; |
|
202 |
break; |
|
203 |
||
204 |
case 'PHP': |
|
205 |
$compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . array_shift($php_blocks) . ' ?>' : ''; |
|
206 |
break; |
|
207 |
||
208 |
default: |
|
209 |
$this->compile_var_tags($block_val[0]); |
|
210 |
$trim_check = trim($block_val[0]); |
|
211 |
$compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : ''); |
|
212 |
break; |
|
213 |
}
|
|
214 |
}
|
|
215 |
||
216 |
$template_php = ''; |
|
217 |
for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++) |
|
218 |
{
|
|
219 |
$trim_check_text = trim($text_blocks[$i]); |
|
220 |
$template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : ''); |
|
221 |
}
|
|
222 |
||
223 |
// There will be a number of occasions where we switch into and out of
|
|
224 |
// PHP mode instantaneously. Rather than "burden" the parser with this
|
|
225 |
// we'll strip out such occurences, minimising such switching
|
|
226 |
$template_php = str_replace(' ?><?php ', ' ', $template_php); |
|
227 |
||
228 |
return (!$no_echo) ? $template_php : "\$$echo_var .= '" . $template_php . "'"; |
|
229 |
}
|
|
230 |
||
231 |
/**
|
|
232 |
* Compile variables
|
|
233 |
* @access private
|
|
234 |
*/
|
|
235 |
function compile_var_tags(&$text_blocks) |
|
236 |
{
|
|
237 |
// change template varrefs into PHP varrefs
|
|
238 |
$varrefs = array(); |
|
239 |
||
240 |
// This one will handle varrefs WITH namespaces
|
|
241 |
preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER); |
|
242 |
||
243 |
foreach ($varrefs as $var_val) |
|
244 |
{
|
|
245 |
$namespace = $var_val[1]; |
|
246 |
$varname = $var_val[3]; |
|
247 |
$new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); |
|
248 |
||
249 |
$text_blocks = str_replace($var_val[0], $new, $text_blocks); |
|
250 |
}
|
|
251 |
||
252 |
// This will handle the remaining root-level varrefs
|
|
253 |
// transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array
|
|
254 |
if (strpos($text_blocks, '{L_') !== false) |
|
255 |
{
|
|
256 |
$text_blocks = preg_replace('#\{L_([a-z0-9\-_]*)\}#is', "<?php echo ((isset(\$this->_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks); |
|
257 |
}
|
|
258 |
||
259 |
// Handle addslashed language variables prefixed with LA_
|
|
260 |
// If a template variable already exist, it will be used in favor of it...
|
|
261 |
if (strpos($text_blocks, '{LA_') !== false) |
|
262 |
{
|
|
263 |
$text_blocks = preg_replace('#\{LA_([a-z0-9\-_]*)\}#is', "<?php echo ((isset(\$this->_rootref['LA_\\1'])) ? \$this->_rootref['LA_\\1'] : ((isset(\$this->_rootref['L_\\1'])) ? addslashes(\$this->_rootref['L_\\1']) : ((isset(\$user->lang['\\1'])) ? addslashes(\$user->lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks); |
|
264 |
}
|
|
265 |
||
266 |
// Handle remaining varrefs
|
|
267 |
$text_blocks = preg_replace('#\{([a-z0-9\-_]*)\}#is', "<?php echo (isset(\$this->_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks); |
|
268 |
$text_blocks = preg_replace('#\{\$([a-z0-9\-_]*)\}#is', "<?php echo (isset(\$this->_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks); |
|
269 |
||
270 |
return; |
|
271 |
}
|
|
272 |
||
273 |
/**
|
|
274 |
* Compile blocks
|
|
275 |
* @access private
|
|
276 |
*/
|
|
277 |
function compile_tag_block($tag_args) |
|
278 |
{
|
|
279 |
$no_nesting = false; |
|
280 |
||
281 |
// Is the designer wanting to call another loop in a loop?
|
|
282 |
if (strpos($tag_args, '!') === 0) |
|
283 |
{
|
|
284 |
// Count the number if ! occurrences (not allowed in vars)
|
|
285 |
$no_nesting = substr_count($tag_args, '!'); |
|
286 |
$tag_args = substr($tag_args, $no_nesting); |
|
287 |
}
|
|
288 |
||
289 |
// Allow for control of looping (indexes start from zero):
|
|
290 |
// foo(2) : Will start the loop on the 3rd entry
|
|
291 |
// foo(-2) : Will start the loop two entries from the end
|
|
292 |
// foo(3,4) : Will start the loop on the fourth entry and end it on the fifth
|
|
293 |
// foo(3,-4) : Will start the loop on the fourth entry and end it four from last
|
|
294 |
if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) |
|
295 |
{
|
|
296 |
$tag_args = $match[1]; |
|
297 |
||
298 |
if ($match[2] < 0) |
|
299 |
{
|
|
300 |
$loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; |
|
301 |
}
|
|
302 |
else
|
|
303 |
{
|
|
304 |
$loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; |
|
305 |
}
|
|
306 |
||
307 |
if (strlen($match[3]) < 1 || $match[3] == -1) |
|
308 |
{
|
|
309 |
$loop_end = '$_' . $tag_args . '_count'; |
|
310 |
}
|
|
311 |
else if ($match[3] >= 0) |
|
312 |
{
|
|
313 |
$loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; |
|
314 |
}
|
|
315 |
else //if ($match[3] < -1) |
|
316 |
{
|
|
317 |
$loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); |
|
318 |
}
|
|
319 |
}
|
|
320 |
else
|
|
321 |
{
|
|
322 |
$loop_start = 0; |
|
323 |
$loop_end = '$_' . $tag_args . '_count'; |
|
324 |
}
|
|
325 |
||
326 |
$tag_template_php = ''; |
|
327 |
array_push($this->block_names, $tag_args); |
|
328 |
||
329 |
if ($no_nesting !== false) |
|
330 |
{
|
|
331 |
// We need to implode $no_nesting times from the end...
|
|
332 |
$block = array_slice($this->block_names, -$no_nesting); |
|
333 |
}
|
|
334 |
else
|
|
335 |
{
|
|
336 |
$block = $this->block_names; |
|
337 |
}
|
|
338 |
||
339 |
if (sizeof($block) < 2) |
|
340 |
{
|
|
341 |
// Block is not nested.
|
|
342 |
$tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;"; |
|
343 |
$varref = "\$this->_tpldata['$tag_args']"; |
|
344 |
}
|
|
345 |
else
|
|
346 |
{
|
|
347 |
// This block is nested.
|
|
348 |
// Generate a namespace string for this block.
|
|
349 |
$namespace = implode('.', $block); |
|
350 |
||
351 |
// Get a reference to the data array for this block that depends on the
|
|
352 |
// current indices of all parent blocks.
|
|
353 |
$varref = $this->generate_block_data_ref($namespace, false); |
|
354 |
||
355 |
// Create the for loop code to iterate over this block.
|
|
356 |
$tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; |
|
357 |
}
|
|
358 |
||
359 |
$tag_template_php .= 'if ($_' . $tag_args . '_count) {'; |
|
360 |
||
361 |
/**
|
|
362 |
* The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory
|
|
363 |
* <code>
|
|
364 |
* if (!$offset)
|
|
365 |
* {
|
|
366 |
* $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){';
|
|
367 |
* }
|
|
368 |
* </code>
|
|
369 |
*/
|
|
370 |
||
371 |
$tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; |
|
372 |
$tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];'; |
|
373 |
||
374 |
return $tag_template_php; |
|
375 |
}
|
|
376 |
||
377 |
/**
|
|
378 |
* Compile IF tags - much of this is from Smarty with
|
|
379 |
* some adaptions for our block level methods
|
|
380 |
* @access private
|
|
381 |
*/
|
|
382 |
function compile_tag_if($tag_args, $elseif) |
|
383 |
{
|
|
384 |
// Tokenize args for 'if' tag.
|
|
385 |
preg_match_all('/(?: |
|
386 |
"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
|
|
387 |
\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
|
|
388 |
[(),] |
|
|
389 |
[^\s(),]+)/x', $tag_args, $match); |
|
390 |
||
391 |
$tokens = $match[0]; |
|
392 |
$is_arg_stack = array(); |
|
393 |
||
394 |
for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) |
|
395 |
{
|
|
396 |
$token = &$tokens[$i]; |
|
397 |
||
398 |
switch ($token) |
|
399 |
{
|
|
400 |
case '!==': |
|
401 |
case '===': |
|
402 |
case '<<': |
|
403 |
case '>>': |
|
404 |
case '|': |
|
405 |
case '^': |
|
406 |
case '&': |
|
407 |
case '~': |
|
408 |
case ')': |
|
409 |
case ',': |
|
410 |
case '+': |
|
411 |
case '-': |
|
412 |
case '*': |
|
413 |
case '/': |
|
414 |
case '@': |
|
415 |
break; |
|
416 |
||
417 |
case '==': |
|
418 |
case 'eq': |
|
419 |
$token = '=='; |
|
420 |
break; |
|
421 |
||
422 |
case '!=': |
|
423 |
case '<>': |
|
424 |
case 'ne': |
|
425 |
case 'neq': |
|
426 |
$token = '!='; |
|
427 |
break; |
|
428 |
||
429 |
case '<': |
|
430 |
case 'lt': |
|
431 |
$token = '<'; |
|
432 |
break; |
|
433 |
||
434 |
case '<=': |
|
435 |
case 'le': |
|
436 |
case 'lte': |
|
437 |
$token = '<='; |
|
438 |
break; |
|
439 |
||
440 |
case '>': |
|
441 |
case 'gt': |
|
442 |
$token = '>'; |
|
443 |
break; |
|
444 |
||
445 |
case '>=': |
|
446 |
case 'ge': |
|
447 |
case 'gte': |
|
448 |
$token = '>='; |
|
449 |
break; |
|
450 |
||
451 |
case '&&': |
|
452 |
case 'and': |
|
453 |
$token = '&&'; |
|
454 |
break; |
|
455 |
||
456 |
case '||': |
|
457 |
case 'or': |
|
458 |
$token = '||'; |
|
459 |
break; |
|
460 |
||
461 |
case '!': |
|
462 |
case 'not': |
|
463 |
$token = '!'; |
|
464 |
break; |
|
465 |
||
466 |
case '%': |
|
467 |
case 'mod': |
|
468 |
$token = '%'; |
|
469 |
break; |
|
470 |
||
471 |
case '(': |
|
472 |
array_push($is_arg_stack, $i); |
|
473 |
break; |
|
474 |
||
475 |
case 'is': |
|
476 |
$is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; |
|
477 |
$is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); |
|
478 |
||
479 |
$new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); |
|
480 |
||
481 |
array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); |
|
482 |
||
483 |
$i = $is_arg_start; |
|
484 |
||
485 |
// no break
|
|
486 |
||
487 |
default: |
|
488 |
if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) |
|
489 |
{
|
|
490 |
$token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']' : (($varrefs[2]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$this->_rootref[\'' . $varrefs[3] . '\']'); |
|
491 |
}
|
|
492 |
else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs)) |
|
493 |
{
|
|
494 |
// Allow checking if loops are set with .loopname
|
|
495 |
// It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example
|
|
496 |
$blocks = explode('.', $varrefs[1]); |
|
497 |
||
498 |
// If the block is nested, we have a reference that we can grab.
|
|
499 |
// If the block is not nested, we just go and grab the block from _tpldata
|
|
500 |
if (sizeof($blocks) > 1) |
|
501 |
{
|
|
502 |
$block = array_pop($blocks); |
|
503 |
$namespace = implode('.', $blocks); |
|
504 |
$varref = $this->generate_block_data_ref($namespace, true); |
|
505 |
||
506 |
// Add the block reference for the last child.
|
|
507 |
$varref .= "['" . $block . "']"; |
|
508 |
}
|
|
509 |
else
|
|
510 |
{
|
|
511 |
$varref = '$this->_tpldata'; |
|
512 |
||
513 |
// Add the block reference for the last child.
|
|
514 |
$varref .= "['" . $blocks[0] . "']"; |
|
515 |
}
|
|
516 |
$token = "sizeof($varref)"; |
|
517 |
}
|
|
518 |
||
519 |
break; |
|
520 |
}
|
|
521 |
}
|
|
522 |
||
523 |
return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { '); |
|
524 |
}
|
|
525 |
||
526 |
/**
|
|
527 |
* Compile DEFINE tags
|
|
528 |
* @access private
|
|
529 |
*/
|
|
530 |
function compile_tag_define($tag_args, $op) |
|
531 |
{
|
|
532 |
preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match); |
|
533 |
||
534 |
if (empty($match[2]) || (!isset($match[4]) && $op)) |
|
535 |
{
|
|
536 |
return ''; |
|
537 |
}
|
|
538 |
||
539 |
if (!$op) |
|
540 |
{
|
|
541 |
return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; |
|
542 |
}
|
|
543 |
||
544 |
// Are we a string?
|
|
545 |
if ($match[3] && $match[5]) |
|
546 |
{
|
|
547 |
$match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]); |
|
548 |
||
549 |
// Compile reference, we allow template variables in defines...
|
|
550 |
$match[4] = $this->compile($match[4]); |
|
551 |
||
552 |
// Now replace the php code
|
|
553 |
$match[4] = "'" . str_replace(array('<?php echo ', '; ?>'), array("' . ", " . '"), $match[4]) . "'"; |
|
554 |
}
|
|
555 |
else
|
|
556 |
{
|
|
557 |
preg_match('#true|false|\.#i', $match[4], $type); |
|
558 |
||
559 |
switch (strtolower($type[0])) |
|
560 |
{
|
|
561 |
case 'true': |
|
562 |
case 'false': |
|
563 |
$match[4] = strtoupper($match[4]); |
|
564 |
break; |
|
565 |
||
566 |
case '.': |
|
567 |
$match[4] = doubleval($match[4]); |
|
568 |
break; |
|
569 |
||
570 |
default: |
|
571 |
$match[4] = intval($match[4]); |
|
572 |
break; |
|
573 |
}
|
|
574 |
}
|
|
575 |
||
576 |
return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';'; |
|
577 |
}
|
|
578 |
||
579 |
/**
|
|
580 |
* Compile INCLUDE tag
|
|
581 |
* @access private
|
|
582 |
*/
|
|
583 |
function compile_tag_include($tag_args) |
|
584 |
{
|
|
585 |
return "\$this->_tpl_include('$tag_args');"; |
|
586 |
}
|
|
587 |
||
588 |
/**
|
|
589 |
* Compile INCLUDE_PHP tag
|
|
590 |
* @access private
|
|
591 |
*/
|
|
592 |
function compile_tag_include_php($tag_args) |
|
593 |
{
|
|
594 |
return "include('" . $tag_args . "');"; |
|
595 |
}
|
|
596 |
||
597 |
/**
|
|
598 |
* parse expression
|
|
599 |
* This is from Smarty
|
|
600 |
* @access private
|
|
601 |
*/
|
|
602 |
function _parse_is_expr($is_arg, $tokens) |
|
603 |
{
|
|
604 |
$expr_end = 0; |
|
605 |
$negate_expr = false; |
|
606 |
||
607 |
if (($first_token = array_shift($tokens)) == 'not') |
|
608 |
{
|
|
609 |
$negate_expr = true; |
|
610 |
$expr_type = array_shift($tokens); |
|
611 |
}
|
|
612 |
else
|
|
613 |
{
|
|
614 |
$expr_type = $first_token; |
|
615 |
}
|
|
616 |
||
617 |
switch ($expr_type) |
|
618 |
{
|
|
619 |
case 'even': |
|
620 |
if (@$tokens[$expr_end] == 'by') |
|
621 |
{
|
|
622 |
$expr_end++; |
|
623 |
$expr_arg = $tokens[$expr_end++]; |
|
624 |
$expr = "!(($is_arg / $expr_arg) % $expr_arg)"; |
|
625 |
}
|
|
626 |
else
|
|
627 |
{
|
|
628 |
$expr = "!($is_arg & 1)"; |
|
629 |
}
|
|
630 |
break; |
|
631 |
||
632 |
case 'odd': |
|
633 |
if (@$tokens[$expr_end] == 'by') |
|
634 |
{
|
|
635 |
$expr_end++; |
|
636 |
$expr_arg = $tokens[$expr_end++]; |
|
637 |
$expr = "(($is_arg / $expr_arg) % $expr_arg)"; |
|
638 |
}
|
|
639 |
else
|
|
640 |
{
|
|
641 |
$expr = "($is_arg & 1)"; |
|
642 |
}
|
|
643 |
break; |
|
644 |
||
645 |
case 'div': |
|
646 |
if (@$tokens[$expr_end] == 'by') |
|
647 |
{
|
|
648 |
$expr_end++; |
|
649 |
$expr_arg = $tokens[$expr_end++]; |
|
650 |
$expr = "!($is_arg % $expr_arg)"; |
|
651 |
}
|
|
652 |
break; |
|
653 |
}
|
|
654 |
||
655 |
if ($negate_expr) |
|
656 |
{
|
|
657 |
$expr = "!($expr)"; |
|
658 |
}
|
|
659 |
||
660 |
array_splice($tokens, 0, $expr_end, $expr); |
|
661 |
||
662 |
return $tokens; |
|
663 |
}
|
|
664 |
||
665 |
/**
|
|
666 |
* Generates a reference to the given variable inside the given (possibly nested)
|
|
667 |
* block namespace. This is a string of the form:
|
|
668 |
* ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
|
|
669 |
* It's ready to be inserted into an "echo" line in one of the templates.
|
|
670 |
* NOTE: expects a trailing "." on the namespace.
|
|
671 |
* @access private
|
|
672 |
*/
|
|
673 |
function generate_block_varref($namespace, $varname, $echo = true, $defop = false) |
|
674 |
{
|
|
675 |
// Strip the trailing period.
|
|
676 |
$namespace = substr($namespace, 0, -1); |
|
677 |
||
678 |
// Get a reference to the data block for this namespace.
|
|
679 |
$varref = $this->generate_block_data_ref($namespace, true, $defop); |
|
680 |
// Prepend the necessary code to stick this in an echo line.
|
|
681 |
||
682 |
// Append the variable reference.
|
|
683 |
$varref .= "['$varname']"; |
|
684 |
$varref = ($echo) ? "<?php echo $varref; ?>" : ((isset($varref)) ? $varref : ''); |
|
685 |
||
686 |
return $varref; |
|
687 |
}
|
|
688 |
||
689 |
/**
|
|
690 |
* Generates a reference to the array of data values for the given
|
|
691 |
* (possibly nested) block namespace. This is a string of the form:
|
|
692 |
* $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
|
|
693 |
*
|
|
694 |
* If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
|
|
695 |
* NOTE: does not expect a trailing "." on the blockname.
|
|
696 |
* @access private
|
|
697 |
*/
|
|
698 |
function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) |
|
699 |
{
|
|
700 |
// Get an array of the blocks involved.
|
|
701 |
$blocks = explode('.', $blockname); |
|
702 |
$blockcount = sizeof($blocks) - 1; |
|
703 |
||
704 |
// DEFINE is not an element of any referenced variable, we must use _tpldata to access it
|
|
705 |
if ($defop) |
|
706 |
{
|
|
707 |
$varref = '$this->_tpldata[\'DEFINE\']'; |
|
708 |
// Build up the string with everything but the last child.
|
|
709 |
for ($i = 0; $i < $blockcount; $i++) |
|
710 |
{
|
|
711 |
$varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; |
|
712 |
}
|
|
713 |
// Add the block reference for the last child.
|
|
714 |
$varref .= "['" . $blocks[$blockcount] . "']"; |
|
715 |
// Add the iterator for the last child if requried.
|
|
716 |
if ($include_last_iterator) |
|
717 |
{
|
|
718 |
$varref .= '[$_' . $blocks[$blockcount] . '_i]'; |
|
719 |
}
|
|
720 |
return $varref; |
|
721 |
}
|
|
722 |
else if ($include_last_iterator) |
|
723 |
{
|
|
724 |
return '$_'. $blocks[$blockcount] . '_val'; |
|
725 |
}
|
|
726 |
else
|
|
727 |
{
|
|
728 |
return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; |
|
729 |
}
|
|
730 |
}
|
|
731 |
||
732 |
/**
|
|
733 |
* Write compiled file to cache directory
|
|
734 |
* @access private
|
|
735 |
*/
|
|
736 |
function compile_write($handle, $data) |
|
737 |
{
|
|
738 |
global $phpEx; |
|
739 |
||
740 |
$filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx; |
|
741 |
||
742 |
if ($fp = @fopen($filename, 'wb')) |
|
743 |
{
|
|
744 |
@flock($fp, LOCK_EX); |
|
745 |
@fwrite ($fp, $data); |
|
746 |
@flock($fp, LOCK_UN); |
|
747 |
@fclose($fp); |
|
748 |
||
749 |
@chmod($filename, 0666); |
|
750 |
}
|
|
751 |
||
752 |
return; |
|
753 |
}
|
|
754 |
}
|
|
755 |
||
756 |
?>
|