phpBB
Statistics
| Revision:

root / branches / phpBB-3_0_0 / phpBB / includes / functions_template.php

History | View | Annotate | Download (22.6 kB)

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