1 |
cvsjoko |
1.1 |
<?php |
2 |
|
|
|
3 |
joko |
1.3 |
/** |
4 |
cvsjoko |
1.1 |
* Project: Smarty: the PHP compiling template engine |
5 |
|
|
* File: Smarty_Compiler.class.php |
6 |
|
|
* |
7 |
|
|
* This library is free software; you can redistribute it and/or |
8 |
|
|
* modify it under the terms of the GNU Lesser General Public |
9 |
|
|
* License as published by the Free Software Foundation; either |
10 |
|
|
* version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
* |
12 |
|
|
* This library is distributed in the hope that it will be useful, |
13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 |
|
|
* Lesser General Public License for more details. |
16 |
|
|
* |
17 |
|
|
* You should have received a copy of the GNU Lesser General Public |
18 |
|
|
* License along with this library; if not, write to the Free Software |
19 |
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
|
|
* |
21 |
joko |
1.3 |
* @link http://smarty.php.net/ |
22 |
|
|
* @author Monte Ohrt <monte@ispi.net> |
23 |
|
|
* @author Andrei Zmievski <andrei@php.net> |
24 |
|
|
* @version 2.6.3 |
25 |
|
|
* @copyright 2001-2004 ispi of Lincoln, Inc. |
26 |
|
|
* @package Smarty |
27 |
cvsjoko |
1.1 |
*/ |
28 |
|
|
|
29 |
joko |
1.3 |
/* $Id: Smarty_Compiler.class.php,v 1.321 2004/05/21 14:11:41 messju Exp $ */ |
30 |
|
|
|
31 |
|
|
/** |
32 |
|
|
* Template compiling class |
33 |
|
|
* @package Smarty |
34 |
|
|
*/ |
35 |
cvsjoko |
1.1 |
class Smarty_Compiler extends Smarty { |
36 |
|
|
|
37 |
|
|
// internal vars |
38 |
joko |
1.3 |
/**#@+ |
39 |
|
|
* @access private |
40 |
|
|
*/ |
41 |
|
|
var $_folded_blocks = array(); // keeps folded template blocks |
42 |
cvsjoko |
1.1 |
var $_current_file = null; // the current template being compiled |
43 |
|
|
var $_current_line_no = 1; // line number for error messages |
44 |
|
|
var $_capture_stack = array(); // keeps track of nested capture buffers |
45 |
|
|
var $_plugin_info = array(); // keeps track of plugins to load |
46 |
|
|
var $_init_smarty_vars = false; |
47 |
joko |
1.3 |
var $_permitted_tokens = array('true','false','yes','no','on','off','null'); |
48 |
|
|
var $_db_qstr_regexp = null; // regexps are setup in the constructor |
49 |
|
|
var $_si_qstr_regexp = null; |
50 |
|
|
var $_qstr_regexp = null; |
51 |
|
|
var $_func_regexp = null; |
52 |
|
|
var $_var_bracket_regexp = null; |
53 |
|
|
var $_dvar_guts_regexp = null; |
54 |
|
|
var $_dvar_regexp = null; |
55 |
|
|
var $_cvar_regexp = null; |
56 |
|
|
var $_svar_regexp = null; |
57 |
|
|
var $_avar_regexp = null; |
58 |
|
|
var $_mod_regexp = null; |
59 |
|
|
var $_var_regexp = null; |
60 |
|
|
var $_parenth_param_regexp = null; |
61 |
|
|
var $_func_call_regexp = null; |
62 |
|
|
var $_obj_ext_regexp = null; |
63 |
|
|
var $_obj_start_regexp = null; |
64 |
|
|
var $_obj_params_regexp = null; |
65 |
|
|
var $_obj_call_regexp = null; |
66 |
|
|
var $_cacheable_state = 0; |
67 |
|
|
var $_cache_attrs_count = 0; |
68 |
|
|
var $_nocache_count = 0; |
69 |
|
|
var $_cache_serial = null; |
70 |
|
|
var $_cache_include = null; |
71 |
|
|
|
72 |
|
|
var $_strip_depth = 0; |
73 |
|
|
var $_additional_newline = "\n"; |
74 |
|
|
|
75 |
|
|
/**#@-*/ |
76 |
|
|
/** |
77 |
|
|
* The class constructor. |
78 |
|
|
*/ |
79 |
|
|
function Smarty_Compiler() |
80 |
|
|
{ |
81 |
|
|
// matches double quoted strings: |
82 |
|
|
// "foobar" |
83 |
|
|
// "foo\"bar" |
84 |
|
|
$this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; |
85 |
|
|
|
86 |
|
|
// matches single quoted strings: |
87 |
|
|
// 'foobar' |
88 |
|
|
// 'foo\'bar' |
89 |
|
|
$this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; |
90 |
|
|
|
91 |
|
|
// matches single or double quoted strings |
92 |
|
|
$this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; |
93 |
|
|
|
94 |
|
|
// matches bracket portion of vars |
95 |
|
|
// [0] |
96 |
|
|
// [foo] |
97 |
|
|
// [$bar] |
98 |
|
|
$this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; |
99 |
|
|
|
100 |
|
|
// matches numerical constants |
101 |
|
|
// 30 |
102 |
|
|
// -12 |
103 |
|
|
// 13.22 |
104 |
|
|
$this->_num_const_regexp = '\-?\d+(?:\.\d+)?'; |
105 |
|
|
|
106 |
|
|
// matches $ vars (not objects): |
107 |
|
|
// $foo |
108 |
|
|
// $foo.bar |
109 |
|
|
// $foo.bar.foobar |
110 |
|
|
// $foo[0] |
111 |
|
|
// $foo[$bar] |
112 |
|
|
// $foo[5][blah] |
113 |
|
|
// $foo[5].bar[$foobar][4] |
114 |
|
|
$this->_dvar_math_regexp = '[\+\-\*\/\%]'; |
115 |
|
|
$this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; |
116 |
|
|
$this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp |
117 |
|
|
. ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; |
118 |
|
|
$this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; |
119 |
|
|
|
120 |
|
|
// matches config vars: |
121 |
|
|
// #foo# |
122 |
|
|
// #foobar123_foo# |
123 |
|
|
$this->_cvar_regexp = '\#\w+\#'; |
124 |
|
|
|
125 |
|
|
// matches section vars: |
126 |
|
|
// %foo.bar% |
127 |
|
|
$this->_svar_regexp = '\%\w+\.\w+\%'; |
128 |
|
|
|
129 |
|
|
// matches all valid variables (no quotes, no modifiers) |
130 |
|
|
$this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' |
131 |
|
|
. $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; |
132 |
|
|
|
133 |
|
|
// matches valid variable syntax: |
134 |
|
|
// $foo |
135 |
|
|
// $foo |
136 |
|
|
// #foo# |
137 |
|
|
// #foo# |
138 |
|
|
// "text" |
139 |
|
|
// "text" |
140 |
|
|
$this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_num_const_regexp . '|' . $this->_qstr_regexp . ')'; |
141 |
|
|
|
142 |
|
|
// matches valid object call (no objects allowed in parameters): |
143 |
|
|
// $foo->bar |
144 |
|
|
// $foo->bar() |
145 |
|
|
// $foo->bar("text") |
146 |
|
|
// $foo->bar($foo, $bar, "text") |
147 |
|
|
// $foo->bar($foo, "foo") |
148 |
|
|
// $foo->bar->foo() |
149 |
|
|
// $foo->bar->foo->bar() |
150 |
|
|
$this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; |
151 |
|
|
$this->_obj_params_regexp = '\((?:\w+|' |
152 |
|
|
. $this->_var_regexp . '(?:\s*,\s*(?:(?:\w+|' |
153 |
|
|
. $this->_var_regexp . ')))*)?\)'; |
154 |
|
|
$this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; |
155 |
|
|
$this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?)'; |
156 |
|
|
|
157 |
|
|
// matches valid modifier syntax: |
158 |
|
|
// |foo |
159 |
|
|
// |@foo |
160 |
|
|
// |foo:"bar" |
161 |
|
|
// |foo:$bar |
162 |
|
|
// |foo:"bar":$foobar |
163 |
|
|
// |foo|bar |
164 |
|
|
// |foo:$foo->bar |
165 |
|
|
$this->_mod_regexp = '(?:\|@?\w+(?::(?>-?\w+|' |
166 |
|
|
. $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; |
167 |
|
|
|
168 |
|
|
// matches valid function name: |
169 |
|
|
// foo123 |
170 |
|
|
// _foo_bar |
171 |
|
|
$this->_func_regexp = '[a-zA-Z_]\w*'; |
172 |
|
|
|
173 |
|
|
// matches valid registered object: |
174 |
|
|
// foo->bar |
175 |
|
|
$this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; |
176 |
|
|
|
177 |
|
|
// matches valid parameter values: |
178 |
|
|
// true |
179 |
|
|
// $foo |
180 |
|
|
// $foo|bar |
181 |
|
|
// #foo# |
182 |
|
|
// #foo#|bar |
183 |
|
|
// "text" |
184 |
|
|
// "text"|bar |
185 |
|
|
// $foo->bar |
186 |
|
|
$this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' |
187 |
|
|
. $this->_var_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; |
188 |
|
|
|
189 |
|
|
// matches valid parenthesised function parameters: |
190 |
|
|
// |
191 |
|
|
// "text" |
192 |
|
|
// $foo, $bar, "text" |
193 |
|
|
// $foo|bar, "foo"|bar, $foo->bar($foo)|bar |
194 |
|
|
$this->_parenth_param_regexp = '(?:\((?:\w+|' |
195 |
|
|
. $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' |
196 |
|
|
. $this->_param_regexp . ')))*)?\))'; |
197 |
|
|
|
198 |
|
|
// matches valid function call: |
199 |
|
|
// foo() |
200 |
|
|
// foo_bar($foo) |
201 |
|
|
// _foo_bar($foo,"bar") |
202 |
|
|
// foo123($foo,$foo->bar(),"foo") |
203 |
|
|
$this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' |
204 |
|
|
. $this->_parenth_param_regexp . '))'; |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
/** |
208 |
|
|
* compile a resource |
209 |
|
|
* |
210 |
|
|
* sets $compiled_content to the compiled source |
211 |
|
|
* @param string $resource_name |
212 |
|
|
* @param string $source_content |
213 |
|
|
* @param string $compiled_content |
214 |
|
|
* @return true |
215 |
|
|
*/ |
216 |
|
|
function _compile_file($resource_name, $source_content, &$compiled_content) |
217 |
|
|
{ |
218 |
cvsjoko |
1.1 |
|
219 |
|
|
if ($this->security) { |
220 |
|
|
// do not allow php syntax to be executed unless specified |
221 |
|
|
if ($this->php_handling == SMARTY_PHP_ALLOW && |
222 |
|
|
!$this->security_settings['PHP_HANDLING']) { |
223 |
|
|
$this->php_handling = SMARTY_PHP_PASSTHRU; |
224 |
|
|
} |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
$this->_load_filters(); |
228 |
|
|
|
229 |
joko |
1.3 |
$this->_current_file = $resource_name; |
230 |
cvsjoko |
1.1 |
$this->_current_line_no = 1; |
231 |
|
|
$ldq = preg_quote($this->left_delimiter, '!'); |
232 |
|
|
$rdq = preg_quote($this->right_delimiter, '!'); |
233 |
|
|
|
234 |
|
|
// run template source through prefilter functions |
235 |
|
|
if (count($this->_plugins['prefilter']) > 0) { |
236 |
|
|
foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { |
237 |
|
|
if ($prefilter === false) continue; |
238 |
joko |
1.3 |
if ($prefilter[3] || is_callable($prefilter[0])) { |
239 |
|
|
$source_content = call_user_func_array($prefilter[0], |
240 |
|
|
array($source_content, &$this)); |
241 |
cvsjoko |
1.1 |
$this->_plugins['prefilter'][$filter_name][3] = true; |
242 |
|
|
} else { |
243 |
joko |
1.3 |
$this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); |
244 |
cvsjoko |
1.1 |
} |
245 |
|
|
} |
246 |
|
|
} |
247 |
|
|
|
248 |
joko |
1.3 |
/* fetch all special blocks */ |
249 |
|
|
$search = "!{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s"; |
250 |
cvsjoko |
1.1 |
|
251 |
joko |
1.3 |
preg_match_all($search, $source_content, $match, PREG_SET_ORDER); |
252 |
|
|
$this->_folded_blocks = $match; |
253 |
|
|
reset($this->_folded_blocks); |
254 |
|
|
|
255 |
|
|
/* replace special blocks by "{php}" */ |
256 |
|
|
$source_content = preg_replace($search.'e', "'" |
257 |
|
|
. $this->_quote_replace($this->left_delimiter) . 'php' |
258 |
|
|
. "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" |
259 |
|
|
. $this->_quote_replace($this->right_delimiter) |
260 |
|
|
. "'" |
261 |
|
|
, $source_content); |
262 |
cvsjoko |
1.1 |
|
263 |
|
|
/* Gather all template tags. */ |
264 |
joko |
1.3 |
preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $source_content, $_match); |
265 |
|
|
$template_tags = $_match[1]; |
266 |
cvsjoko |
1.1 |
/* Split content by template tags to obtain non-template content. */ |
267 |
joko |
1.3 |
$text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $source_content); |
268 |
cvsjoko |
1.1 |
|
269 |
|
|
/* loop through text blocks */ |
270 |
|
|
for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { |
271 |
joko |
1.3 |
/* match anything resembling php tags */ |
272 |
|
|
if (preg_match_all('!(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)!is', $text_blocks[$curr_tb], $sp_match)) { |
273 |
|
|
/* replace tags with placeholders to prevent recursive replacements */ |
274 |
|
|
$sp_match[1] = array_unique($sp_match[1]); |
275 |
|
|
usort($sp_match[1], '_smarty_sort_length'); |
276 |
|
|
for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { |
277 |
|
|
$text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); |
278 |
|
|
} |
279 |
|
|
/* process each one */ |
280 |
|
|
for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { |
281 |
|
|
if ($this->php_handling == SMARTY_PHP_PASSTHRU) { |
282 |
|
|
/* echo php contents */ |
283 |
|
|
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]); |
284 |
|
|
} else if ($this->php_handling == SMARTY_PHP_QUOTE) { |
285 |
|
|
/* quote php tags */ |
286 |
|
|
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); |
287 |
|
|
} else if ($this->php_handling == SMARTY_PHP_REMOVE) { |
288 |
|
|
/* remove php tags */ |
289 |
|
|
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); |
290 |
|
|
} else { |
291 |
|
|
/* SMARTY_PHP_ALLOW, but echo non php starting tags */ |
292 |
|
|
$sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]); |
293 |
|
|
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); |
294 |
|
|
} |
295 |
cvsjoko |
1.1 |
} |
296 |
|
|
} |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
/* Compile the template tags into PHP code. */ |
300 |
|
|
$compiled_tags = array(); |
301 |
|
|
for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { |
302 |
|
|
$this->_current_line_no += substr_count($text_blocks[$i], "\n"); |
303 |
|
|
$compiled_tags[] = $this->_compile_tag($template_tags[$i]); |
304 |
|
|
$this->_current_line_no += substr_count($template_tags[$i], "\n"); |
305 |
|
|
} |
306 |
joko |
1.3 |
if (count($this->_tag_stack)>0) { |
307 |
|
|
list($_open_tag, $_line_no) = end($this->_tag_stack); |
308 |
|
|
$this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); |
309 |
|
|
return; |
310 |
|
|
} |
311 |
cvsjoko |
1.1 |
|
312 |
joko |
1.3 |
$compiled_content = ''; |
313 |
cvsjoko |
1.1 |
|
314 |
|
|
/* Interleave the compiled contents and text blocks to get the final result. */ |
315 |
|
|
for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { |
316 |
joko |
1.3 |
if ($compiled_tags[$i] == '') { |
317 |
|
|
// tag result empty, remove first newline from following text block |
318 |
|
|
$text_blocks[$i+1] = preg_replace('!^(\r\n|\r|\n)!', '', $text_blocks[$i+1]); |
319 |
|
|
} |
320 |
|
|
$compiled_content .= $text_blocks[$i].$compiled_tags[$i]; |
321 |
cvsjoko |
1.1 |
} |
322 |
joko |
1.3 |
$compiled_content .= $text_blocks[$i]; |
323 |
cvsjoko |
1.1 |
|
324 |
|
|
/* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */ |
325 |
joko |
1.3 |
if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_content, $_match)) { |
326 |
|
|
$strip_tags = $_match[0]; |
327 |
cvsjoko |
1.1 |
$strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags); |
328 |
|
|
$strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified); |
329 |
|
|
for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++) |
330 |
joko |
1.3 |
$compiled_content = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", |
331 |
|
|
$this->_quote_replace($strip_tags_modified[$i]), |
332 |
|
|
$compiled_content, 1); |
333 |
cvsjoko |
1.1 |
} |
334 |
|
|
|
335 |
|
|
// remove \n from the end of the file, if any |
336 |
joko |
1.3 |
if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) { |
337 |
|
|
$compiled_content = substr($compiled_content, 0, -1); |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
if (!empty($this->_cache_serial)) { |
341 |
|
|
$compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; |
342 |
cvsjoko |
1.1 |
} |
343 |
|
|
|
344 |
joko |
1.3 |
// remove unnecessary close/open tags |
345 |
|
|
$compiled_content = preg_replace('!\?>\n?<\?php!', '', $compiled_content); |
346 |
|
|
|
347 |
cvsjoko |
1.1 |
// run compiled template through postfilter functions |
348 |
|
|
if (count($this->_plugins['postfilter']) > 0) { |
349 |
|
|
foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { |
350 |
|
|
if ($postfilter === false) continue; |
351 |
joko |
1.3 |
if ($postfilter[3] || is_callable($postfilter[0])) { |
352 |
|
|
$compiled_content = call_user_func_array($postfilter[0], |
353 |
|
|
array($compiled_content, &$this)); |
354 |
cvsjoko |
1.1 |
$this->_plugins['postfilter'][$filter_name][3] = true; |
355 |
|
|
} else { |
356 |
joko |
1.3 |
$this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); |
357 |
cvsjoko |
1.1 |
} |
358 |
|
|
} |
359 |
|
|
} |
360 |
|
|
|
361 |
|
|
// put header at the top of the compiled template |
362 |
|
|
$template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; |
363 |
joko |
1.3 |
$template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; |
364 |
cvsjoko |
1.1 |
|
365 |
|
|
/* Emit code to load needed plugins. */ |
366 |
joko |
1.3 |
$this->_plugins_code = ''; |
367 |
cvsjoko |
1.1 |
if (count($this->_plugin_info)) { |
368 |
joko |
1.3 |
$_plugins_params = "array('plugins' => array("; |
369 |
cvsjoko |
1.1 |
foreach ($this->_plugin_info as $plugin_type => $plugins) { |
370 |
|
|
foreach ($plugins as $plugin_name => $plugin_info) { |
371 |
joko |
1.3 |
$_plugins_params .= "array('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], "; |
372 |
|
|
$_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; |
373 |
cvsjoko |
1.1 |
} |
374 |
|
|
} |
375 |
joko |
1.3 |
$_plugins_params .= '))'; |
376 |
|
|
$plugins_code = "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n"; |
377 |
cvsjoko |
1.1 |
$template_header .= $plugins_code; |
378 |
|
|
$this->_plugin_info = array(); |
379 |
joko |
1.3 |
$this->_plugins_code = $plugins_code; |
380 |
cvsjoko |
1.1 |
} |
381 |
|
|
|
382 |
|
|
if ($this->_init_smarty_vars) { |
383 |
joko |
1.3 |
$template_header .= "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n"; |
384 |
cvsjoko |
1.1 |
$this->_init_smarty_vars = false; |
385 |
|
|
} |
386 |
|
|
|
387 |
joko |
1.3 |
$compiled_content = $template_header . $compiled_content; |
388 |
cvsjoko |
1.1 |
return true; |
389 |
|
|
} |
390 |
|
|
|
391 |
joko |
1.3 |
/** |
392 |
|
|
* Compile a template tag |
393 |
|
|
* |
394 |
|
|
* @param string $template_tag |
395 |
|
|
* @return string |
396 |
|
|
*/ |
397 |
cvsjoko |
1.1 |
function _compile_tag($template_tag) |
398 |
|
|
{ |
399 |
|
|
/* Matched comment. */ |
400 |
|
|
if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*') |
401 |
|
|
return ''; |
402 |
|
|
|
403 |
joko |
1.3 |
/* Split tag into two three parts: command, command modifiers and the arguments. */ |
404 |
|
|
if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp |
405 |
|
|
. '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) |
406 |
|
|
(?:\s+(.*))?$ |
407 |
|
|
/xs', $template_tag, $match)) { |
408 |
|
|
$this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); |
409 |
|
|
} |
410 |
cvsjoko |
1.1 |
|
411 |
|
|
$tag_command = $match[1]; |
412 |
joko |
1.3 |
$tag_modifier = isset($match[2]) ? $match[2] : null; |
413 |
|
|
$tag_args = isset($match[3]) ? $match[3] : null; |
414 |
|
|
|
415 |
|
|
if (preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$!', $tag_command)) { |
416 |
|
|
/* tag name is a variable or object */ |
417 |
|
|
$_return = $this->_parse_var_props($tag_command . $tag_modifier, $this->_parse_attrs($tag_args)); |
418 |
|
|
if(isset($_tag_attrs['assign'])) { |
419 |
|
|
return "<?php \$this->assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>\n"; |
420 |
|
|
} else { |
421 |
|
|
return "<?php echo $_return; ?>" . $this->_additional_newline; |
422 |
|
|
} |
423 |
|
|
} |
424 |
cvsjoko |
1.1 |
|
425 |
joko |
1.3 |
/* If the tag name is a registered object, we process it. */ |
426 |
|
|
if (preg_match('!^\/?' . $this->_reg_obj_regexp . '$!', $tag_command)) { |
427 |
|
|
return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); |
428 |
cvsjoko |
1.1 |
} |
429 |
|
|
|
430 |
|
|
switch ($tag_command) { |
431 |
|
|
case 'include': |
432 |
|
|
return $this->_compile_include_tag($tag_args); |
433 |
|
|
|
434 |
|
|
case 'include_php': |
435 |
|
|
return $this->_compile_include_php_tag($tag_args); |
436 |
|
|
|
437 |
|
|
case 'if': |
438 |
joko |
1.3 |
$this->_push_tag('if'); |
439 |
cvsjoko |
1.1 |
return $this->_compile_if_tag($tag_args); |
440 |
|
|
|
441 |
|
|
case 'else': |
442 |
joko |
1.3 |
list($_open_tag) = end($this->_tag_stack); |
443 |
|
|
if ($_open_tag != 'if' && $_open_tag != 'elseif') |
444 |
|
|
$this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); |
445 |
|
|
else |
446 |
|
|
$this->_push_tag('else'); |
447 |
cvsjoko |
1.1 |
return '<?php else: ?>'; |
448 |
|
|
|
449 |
|
|
case 'elseif': |
450 |
joko |
1.3 |
list($_open_tag) = end($this->_tag_stack); |
451 |
|
|
if ($_open_tag != 'if' && $_open_tag != 'elseif') |
452 |
|
|
$this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); |
453 |
|
|
if ($_open_tag == 'if') |
454 |
|
|
$this->_push_tag('elseif'); |
455 |
cvsjoko |
1.1 |
return $this->_compile_if_tag($tag_args, true); |
456 |
|
|
|
457 |
|
|
case '/if': |
458 |
joko |
1.3 |
$this->_pop_tag('if'); |
459 |
cvsjoko |
1.1 |
return '<?php endif; ?>'; |
460 |
|
|
|
461 |
|
|
case 'capture': |
462 |
|
|
return $this->_compile_capture_tag(true, $tag_args); |
463 |
|
|
|
464 |
|
|
case '/capture': |
465 |
|
|
return $this->_compile_capture_tag(false); |
466 |
|
|
|
467 |
|
|
case 'ldelim': |
468 |
|
|
return $this->left_delimiter; |
469 |
|
|
|
470 |
|
|
case 'rdelim': |
471 |
|
|
return $this->right_delimiter; |
472 |
|
|
|
473 |
|
|
case 'section': |
474 |
joko |
1.3 |
$this->_push_tag('section'); |
475 |
cvsjoko |
1.1 |
return $this->_compile_section_start($tag_args); |
476 |
|
|
|
477 |
|
|
case 'sectionelse': |
478 |
joko |
1.3 |
$this->_push_tag('sectionelse'); |
479 |
cvsjoko |
1.1 |
return "<?php endfor; else: ?>"; |
480 |
joko |
1.3 |
break; |
481 |
cvsjoko |
1.1 |
|
482 |
|
|
case '/section': |
483 |
joko |
1.3 |
$_open_tag = $this->_pop_tag('section'); |
484 |
|
|
if ($_open_tag == 'sectionelse') |
485 |
cvsjoko |
1.1 |
return "<?php endif; ?>"; |
486 |
|
|
else |
487 |
|
|
return "<?php endfor; endif; ?>"; |
488 |
|
|
|
489 |
|
|
case 'foreach': |
490 |
joko |
1.3 |
$this->_push_tag('foreach'); |
491 |
cvsjoko |
1.1 |
return $this->_compile_foreach_start($tag_args); |
492 |
|
|
break; |
493 |
|
|
|
494 |
|
|
case 'foreachelse': |
495 |
joko |
1.3 |
$this->_push_tag('foreachelse'); |
496 |
|
|
return "<?php endforeach; unset(\$_from); else: ?>"; |
497 |
cvsjoko |
1.1 |
|
498 |
|
|
case '/foreach': |
499 |
joko |
1.3 |
$_open_tag = $this->_pop_tag('foreach'); |
500 |
|
|
if ($_open_tag == 'foreachelse') |
501 |
cvsjoko |
1.1 |
return "<?php endif; ?>"; |
502 |
|
|
else |
503 |
joko |
1.3 |
return "<?php endforeach; unset(\$_from); endif; ?>"; |
504 |
|
|
break; |
505 |
cvsjoko |
1.1 |
|
506 |
|
|
case 'strip': |
507 |
|
|
case '/strip': |
508 |
joko |
1.3 |
if ($tag_command{0}=='/') { |
509 |
|
|
$this->_pop_tag('strip'); |
510 |
|
|
if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ |
511 |
|
|
$this->_additional_newline = "\n"; |
512 |
|
|
return $this->left_delimiter.$tag_command.$this->right_delimiter; |
513 |
|
|
} |
514 |
|
|
} else { |
515 |
|
|
$this->_push_tag('strip'); |
516 |
|
|
if ($this->_strip_depth++==0) { /* outermost opening {strip} */ |
517 |
|
|
$this->_additional_newline = ""; |
518 |
|
|
return $this->left_delimiter.$tag_command.$this->right_delimiter; |
519 |
|
|
} |
520 |
|
|
} |
521 |
|
|
return ''; |
522 |
cvsjoko |
1.1 |
|
523 |
|
|
case 'php': |
524 |
joko |
1.3 |
/* handle folded tags replaced by {php} */ |
525 |
|
|
list(, $block) = each($this->_folded_blocks); |
526 |
|
|
$this->_current_line_no += substr_count($block[0], "\n"); |
527 |
|
|
/* the number of matched elements in the regexp in _compile_file() |
528 |
|
|
determins the type of folded tag that was found */ |
529 |
|
|
switch (count($block)) { |
530 |
|
|
case 2: /* comment */ |
531 |
|
|
return ''; |
532 |
|
|
|
533 |
|
|
case 3: /* literal */ |
534 |
|
|
return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; |
535 |
|
|
|
536 |
|
|
case 4: /* php */ |
537 |
|
|
if ($this->security && !$this->security_settings['PHP_TAGS']) { |
538 |
|
|
$this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); |
539 |
|
|
return; |
540 |
|
|
} |
541 |
|
|
return '<?php ' . $block[3] .' ?>'; |
542 |
|
|
} |
543 |
|
|
break; |
544 |
cvsjoko |
1.1 |
|
545 |
|
|
case 'insert': |
546 |
|
|
return $this->_compile_insert_tag($tag_args); |
547 |
|
|
|
548 |
|
|
default: |
549 |
|
|
if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { |
550 |
|
|
return $output; |
551 |
joko |
1.3 |
} else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { |
552 |
cvsjoko |
1.1 |
return $output; |
553 |
joko |
1.3 |
} else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { |
554 |
|
|
return $output; |
555 |
cvsjoko |
1.1 |
} else { |
556 |
joko |
1.3 |
$this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); |
557 |
cvsjoko |
1.1 |
} |
558 |
joko |
1.3 |
|
559 |
cvsjoko |
1.1 |
} |
560 |
|
|
} |
561 |
|
|
|
562 |
|
|
|
563 |
joko |
1.3 |
/** |
564 |
|
|
* compile the custom compiler tag |
565 |
|
|
* |
566 |
|
|
* sets $output to the compiled custom compiler tag |
567 |
|
|
* @param string $tag_command |
568 |
|
|
* @param string $tag_args |
569 |
|
|
* @param string $output |
570 |
|
|
* @return boolean |
571 |
|
|
*/ |
572 |
cvsjoko |
1.1 |
function _compile_compiler_tag($tag_command, $tag_args, &$output) |
573 |
|
|
{ |
574 |
|
|
$found = false; |
575 |
|
|
$have_function = true; |
576 |
|
|
|
577 |
|
|
/* |
578 |
|
|
* First we check if the compiler function has already been registered |
579 |
|
|
* or loaded from a plugin file. |
580 |
|
|
*/ |
581 |
|
|
if (isset($this->_plugins['compiler'][$tag_command])) { |
582 |
|
|
$found = true; |
583 |
|
|
$plugin_func = $this->_plugins['compiler'][$tag_command][0]; |
584 |
joko |
1.3 |
if (!is_callable($plugin_func)) { |
585 |
cvsjoko |
1.1 |
$message = "compiler function '$tag_command' is not implemented"; |
586 |
|
|
$have_function = false; |
587 |
|
|
} |
588 |
|
|
} |
589 |
|
|
/* |
590 |
|
|
* Otherwise we need to load plugin file and look for the function |
591 |
|
|
* inside it. |
592 |
|
|
*/ |
593 |
|
|
else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { |
594 |
|
|
$found = true; |
595 |
|
|
|
596 |
|
|
include_once $plugin_file; |
597 |
|
|
|
598 |
|
|
$plugin_func = 'smarty_compiler_' . $tag_command; |
599 |
joko |
1.3 |
if (!is_callable($plugin_func)) { |
600 |
cvsjoko |
1.1 |
$message = "plugin function $plugin_func() not found in $plugin_file\n"; |
601 |
|
|
$have_function = false; |
602 |
|
|
} else { |
603 |
joko |
1.3 |
$this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); |
604 |
cvsjoko |
1.1 |
} |
605 |
|
|
} |
606 |
|
|
|
607 |
|
|
/* |
608 |
|
|
* True return value means that we either found a plugin or a |
609 |
|
|
* dynamically registered function. False means that we didn't and the |
610 |
|
|
* compiler should now emit code to load custom function plugin for this |
611 |
|
|
* tag. |
612 |
|
|
*/ |
613 |
|
|
if ($found) { |
614 |
|
|
if ($have_function) { |
615 |
joko |
1.3 |
$output = call_user_func_array($plugin_func, array($tag_args, &$this)); |
616 |
|
|
if($output != '') { |
617 |
|
|
$output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command) |
618 |
|
|
. $output |
619 |
|
|
. $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; |
620 |
|
|
} |
621 |
cvsjoko |
1.1 |
} else { |
622 |
joko |
1.3 |
$this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); |
623 |
cvsjoko |
1.1 |
} |
624 |
|
|
return true; |
625 |
|
|
} else { |
626 |
|
|
return false; |
627 |
|
|
} |
628 |
|
|
} |
629 |
|
|
|
630 |
|
|
|
631 |
joko |
1.3 |
/** |
632 |
|
|
* compile block function tag |
633 |
|
|
* |
634 |
|
|
* sets $output to compiled block function tag |
635 |
|
|
* @param string $tag_command |
636 |
|
|
* @param string $tag_args |
637 |
|
|
* @param string $tag_modifier |
638 |
|
|
* @param string $output |
639 |
|
|
* @return boolean |
640 |
|
|
*/ |
641 |
|
|
function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) |
642 |
cvsjoko |
1.1 |
{ |
643 |
|
|
if ($tag_command{0} == '/') { |
644 |
|
|
$start_tag = false; |
645 |
|
|
$tag_command = substr($tag_command, 1); |
646 |
|
|
} else |
647 |
|
|
$start_tag = true; |
648 |
|
|
|
649 |
|
|
$found = false; |
650 |
|
|
$have_function = true; |
651 |
|
|
|
652 |
|
|
/* |
653 |
|
|
* First we check if the block function has already been registered |
654 |
|
|
* or loaded from a plugin file. |
655 |
|
|
*/ |
656 |
|
|
if (isset($this->_plugins['block'][$tag_command])) { |
657 |
|
|
$found = true; |
658 |
|
|
$plugin_func = $this->_plugins['block'][$tag_command][0]; |
659 |
joko |
1.3 |
if (!is_callable($plugin_func)) { |
660 |
cvsjoko |
1.1 |
$message = "block function '$tag_command' is not implemented"; |
661 |
|
|
$have_function = false; |
662 |
|
|
} |
663 |
|
|
} |
664 |
|
|
/* |
665 |
|
|
* Otherwise we need to load plugin file and look for the function |
666 |
|
|
* inside it. |
667 |
|
|
*/ |
668 |
|
|
else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { |
669 |
|
|
$found = true; |
670 |
|
|
|
671 |
|
|
include_once $plugin_file; |
672 |
|
|
|
673 |
|
|
$plugin_func = 'smarty_block_' . $tag_command; |
674 |
|
|
if (!function_exists($plugin_func)) { |
675 |
|
|
$message = "plugin function $plugin_func() not found in $plugin_file\n"; |
676 |
|
|
$have_function = false; |
677 |
|
|
} else { |
678 |
joko |
1.3 |
$this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); |
679 |
|
|
|
680 |
cvsjoko |
1.1 |
} |
681 |
|
|
} |
682 |
|
|
|
683 |
|
|
if (!$found) { |
684 |
|
|
return false; |
685 |
|
|
} else if (!$have_function) { |
686 |
joko |
1.3 |
$this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); |
687 |
cvsjoko |
1.1 |
return true; |
688 |
|
|
} |
689 |
|
|
|
690 |
|
|
/* |
691 |
|
|
* Even though we've located the plugin function, compilation |
692 |
|
|
* happens only once, so the plugin will still need to be loaded |
693 |
|
|
* at runtime for future requests. |
694 |
|
|
*/ |
695 |
|
|
$this->_add_plugin('block', $tag_command); |
696 |
|
|
|
697 |
joko |
1.3 |
if ($start_tag) |
698 |
|
|
$this->_push_tag($tag_command); |
699 |
|
|
else |
700 |
|
|
$this->_pop_tag($tag_command); |
701 |
|
|
|
702 |
cvsjoko |
1.1 |
if ($start_tag) { |
703 |
joko |
1.3 |
$output = '<?php ' . $this->_push_cacheable_state('block', $tag_command); |
704 |
cvsjoko |
1.1 |
$attrs = $this->_parse_attrs($tag_args); |
705 |
joko |
1.3 |
$arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs=''); |
706 |
|
|
$output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; |
707 |
|
|
$output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);'; |
708 |
|
|
$output .= 'while ($_block_repeat) { ob_start(); ?>'; |
709 |
|
|
} else { |
710 |
|
|
$output = '<?php $this->_block_content = ob_get_contents(); ob_end_clean(); '; |
711 |
|
|
$_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $this->_block_content, $this, $_block_repeat=false)'; |
712 |
|
|
if ($tag_modifier != '') { |
713 |
|
|
$this->_parse_modifiers($_out_tag_text, $tag_modifier); |
714 |
cvsjoko |
1.1 |
} |
715 |
joko |
1.3 |
$output .= 'echo '.$_out_tag_text.'; } '; |
716 |
|
|
$output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; |
717 |
cvsjoko |
1.1 |
} |
718 |
|
|
|
719 |
|
|
return true; |
720 |
|
|
} |
721 |
|
|
|
722 |
|
|
|
723 |
joko |
1.3 |
/** |
724 |
|
|
* compile custom function tag |
725 |
|
|
* |
726 |
|
|
* @param string $tag_command |
727 |
|
|
* @param string $tag_args |
728 |
|
|
* @param string $tag_modifier |
729 |
|
|
* @return string |
730 |
|
|
*/ |
731 |
|
|
function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) |
732 |
cvsjoko |
1.1 |
{ |
733 |
joko |
1.3 |
$found = false; |
734 |
|
|
$have_function = true; |
735 |
|
|
|
736 |
|
|
/* |
737 |
|
|
* First we check if the custom function has already been registered |
738 |
|
|
* or loaded from a plugin file. |
739 |
|
|
*/ |
740 |
|
|
if (isset($this->_plugins['function'][$tag_command])) { |
741 |
|
|
$found = true; |
742 |
|
|
$plugin_func = $this->_plugins['function'][$tag_command][0]; |
743 |
|
|
if (!is_callable($plugin_func)) { |
744 |
|
|
$message = "custom function '$tag_command' is not implemented"; |
745 |
|
|
$have_function = false; |
746 |
|
|
} |
747 |
|
|
} |
748 |
|
|
/* |
749 |
|
|
* Otherwise we need to load plugin file and look for the function |
750 |
|
|
* inside it. |
751 |
|
|
*/ |
752 |
|
|
else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { |
753 |
|
|
$found = true; |
754 |
|
|
|
755 |
|
|
include_once $plugin_file; |
756 |
|
|
|
757 |
|
|
$plugin_func = 'smarty_function_' . $tag_command; |
758 |
|
|
if (!function_exists($plugin_func)) { |
759 |
|
|
$message = "plugin function $plugin_func() not found in $plugin_file\n"; |
760 |
|
|
$have_function = false; |
761 |
|
|
} else { |
762 |
|
|
$this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); |
763 |
|
|
|
764 |
|
|
} |
765 |
|
|
} |
766 |
|
|
|
767 |
|
|
if (!$found) { |
768 |
|
|
return false; |
769 |
|
|
} else if (!$have_function) { |
770 |
|
|
$this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); |
771 |
|
|
return true; |
772 |
|
|
} |
773 |
|
|
|
774 |
|
|
/* declare plugin to be loaded on display of the template that |
775 |
|
|
we compile right now */ |
776 |
cvsjoko |
1.1 |
$this->_add_plugin('function', $tag_command); |
777 |
|
|
|
778 |
joko |
1.3 |
$_cacheable_state = $this->_push_cacheable_state('function', $tag_command); |
779 |
cvsjoko |
1.1 |
$attrs = $this->_parse_attrs($tag_args); |
780 |
joko |
1.3 |
$arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs=''); |
781 |
|
|
|
782 |
|
|
$output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; |
783 |
|
|
if($tag_modifier != '') { |
784 |
|
|
$this->_parse_modifiers($output, $tag_modifier); |
785 |
|
|
} |
786 |
|
|
|
787 |
|
|
if($output != '') { |
788 |
|
|
$output = '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';' |
789 |
|
|
. $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; |
790 |
cvsjoko |
1.1 |
} |
791 |
|
|
|
792 |
joko |
1.3 |
return true; |
793 |
cvsjoko |
1.1 |
} |
794 |
|
|
|
795 |
joko |
1.3 |
/** |
796 |
|
|
* compile a registered object tag |
797 |
|
|
* |
798 |
|
|
* @param string $tag_command |
799 |
|
|
* @param array $attrs |
800 |
|
|
* @param string $tag_modifier |
801 |
|
|
* @return string |
802 |
|
|
*/ |
803 |
|
|
function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) |
804 |
|
|
{ |
805 |
|
|
if ($tag_command{0} == '/') { |
806 |
|
|
$start_tag = false; |
807 |
|
|
$tag_command = substr($tag_command, 1); |
808 |
|
|
} else { |
809 |
|
|
$start_tag = true; |
810 |
|
|
} |
811 |
|
|
|
812 |
|
|
list($object, $obj_comp) = explode('->', $tag_command); |
813 |
|
|
|
814 |
|
|
$arg_list = array(); |
815 |
|
|
if(count($attrs)) { |
816 |
|
|
$_assign_var = false; |
817 |
|
|
foreach ($attrs as $arg_name => $arg_value) { |
818 |
|
|
if($arg_name == 'assign') { |
819 |
|
|
$_assign_var = $arg_value; |
820 |
|
|
unset($attrs['assign']); |
821 |
|
|
continue; |
822 |
|
|
} |
823 |
|
|
if (is_bool($arg_value)) |
824 |
|
|
$arg_value = $arg_value ? 'true' : 'false'; |
825 |
|
|
$arg_list[] = "'$arg_name' => $arg_value"; |
826 |
|
|
} |
827 |
|
|
} |
828 |
|
|
|
829 |
|
|
if($this->_reg_objects[$object][2]) { |
830 |
|
|
// smarty object argument format |
831 |
|
|
$args = "array(".implode(',', (array)$arg_list)."), \$this"; |
832 |
|
|
} else { |
833 |
|
|
// traditional argument format |
834 |
|
|
$args = implode(',', array_values($attrs)); |
835 |
|
|
if (empty($args)) { |
836 |
|
|
$args = 'null'; |
837 |
|
|
} |
838 |
|
|
} |
839 |
|
|
|
840 |
|
|
$prefix = ''; |
841 |
|
|
$postfix = ''; |
842 |
|
|
$newline = ''; |
843 |
|
|
if(!is_object($this->_reg_objects[$object][0])) { |
844 |
|
|
$this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); |
845 |
|
|
} elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { |
846 |
|
|
$this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); |
847 |
|
|
} elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { |
848 |
|
|
// method |
849 |
|
|
if(in_array($obj_comp, $this->_reg_objects[$object][3])) { |
850 |
|
|
// block method |
851 |
|
|
if ($start_tag) { |
852 |
|
|
$prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; |
853 |
|
|
$prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); "; |
854 |
|
|
$prefix .= "while (\$_block_repeat) { ob_start();"; |
855 |
|
|
$return = null; |
856 |
|
|
$postfix = ''; |
857 |
|
|
} else { |
858 |
|
|
$prefix = "\$this->_obj_block_content = ob_get_contents(); ob_end_clean(); "; |
859 |
|
|
$return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$this->_obj_block_content, \$this, \$_block_repeat=false)"; |
860 |
|
|
$postfix = "} array_pop(\$this->_tag_stack);"; |
861 |
|
|
} |
862 |
|
|
} else { |
863 |
|
|
// non-block method |
864 |
|
|
$return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; |
865 |
|
|
} |
866 |
|
|
} else { |
867 |
|
|
// property |
868 |
|
|
$return = "\$this->_reg_objects['$object'][0]->$obj_comp"; |
869 |
|
|
} |
870 |
|
|
|
871 |
|
|
if($return != null) { |
872 |
|
|
if($tag_modifier != '') { |
873 |
|
|
$this->_parse_modifiers($return, $tag_modifier); |
874 |
|
|
} |
875 |
cvsjoko |
1.1 |
|
876 |
joko |
1.3 |
if(!empty($_assign_var)) { |
877 |
|
|
$output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; |
878 |
|
|
} else { |
879 |
|
|
$output = 'echo ' . $return . ';'; |
880 |
|
|
$newline = $this->_additional_newline; |
881 |
|
|
} |
882 |
|
|
} else { |
883 |
|
|
$output = ''; |
884 |
|
|
} |
885 |
|
|
|
886 |
|
|
return '<?php ' . $prefix . $output . $postfix . "?>" . $newline; |
887 |
|
|
} |
888 |
|
|
|
889 |
|
|
/** |
890 |
|
|
* Compile {insert ...} tag |
891 |
|
|
* |
892 |
|
|
* @param string $tag_args |
893 |
|
|
* @return string |
894 |
|
|
*/ |
895 |
cvsjoko |
1.1 |
function _compile_insert_tag($tag_args) |
896 |
|
|
{ |
897 |
|
|
$attrs = $this->_parse_attrs($tag_args); |
898 |
|
|
$name = $this->_dequote($attrs['name']); |
899 |
|
|
|
900 |
|
|
if (empty($name)) { |
901 |
joko |
1.3 |
$this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); |
902 |
cvsjoko |
1.1 |
} |
903 |
|
|
|
904 |
|
|
if (!empty($attrs['script'])) { |
905 |
|
|
$delayed_loading = true; |
906 |
joko |
1.3 |
} else { |
907 |
|
|
$delayed_loading = false; |
908 |
cvsjoko |
1.1 |
} |
909 |
|
|
|
910 |
|
|
foreach ($attrs as $arg_name => $arg_value) { |
911 |
|
|
if (is_bool($arg_value)) |
912 |
|
|
$arg_value = $arg_value ? 'true' : 'false'; |
913 |
|
|
$arg_list[] = "'$arg_name' => $arg_value"; |
914 |
|
|
} |
915 |
|
|
|
916 |
|
|
$this->_add_plugin('insert', $name, $delayed_loading); |
917 |
|
|
|
918 |
joko |
1.3 |
$_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; |
919 |
cvsjoko |
1.1 |
|
920 |
joko |
1.3 |
return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline; |
921 |
cvsjoko |
1.1 |
} |
922 |
|
|
|
923 |
joko |
1.3 |
/** |
924 |
|
|
* Compile {include ...} tag |
925 |
|
|
* |
926 |
|
|
* @param string $tag_args |
927 |
|
|
* @return string |
928 |
|
|
*/ |
929 |
cvsjoko |
1.1 |
function _compile_include_tag($tag_args) |
930 |
|
|
{ |
931 |
|
|
$attrs = $this->_parse_attrs($tag_args); |
932 |
|
|
$arg_list = array(); |
933 |
|
|
|
934 |
|
|
if (empty($attrs['file'])) { |
935 |
joko |
1.3 |
$this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); |
936 |
cvsjoko |
1.1 |
} |
937 |
|
|
|
938 |
|
|
foreach ($attrs as $arg_name => $arg_value) { |
939 |
|
|
if ($arg_name == 'file') { |
940 |
|
|
$include_file = $arg_value; |
941 |
|
|
continue; |
942 |
|
|
} else if ($arg_name == 'assign') { |
943 |
|
|
$assign_var = $arg_value; |
944 |
|
|
continue; |
945 |
|
|
} |
946 |
|
|
if (is_bool($arg_value)) |
947 |
|
|
$arg_value = $arg_value ? 'true' : 'false'; |
948 |
|
|
$arg_list[] = "'$arg_name' => $arg_value"; |
949 |
|
|
} |
950 |
|
|
|
951 |
|
|
$output = '<?php '; |
952 |
|
|
|
953 |
|
|
if (isset($assign_var)) { |
954 |
joko |
1.3 |
$output .= "ob_start();\n"; |
955 |
cvsjoko |
1.1 |
} |
956 |
|
|
|
957 |
joko |
1.3 |
$output .= |
958 |
|
|
"\$_smarty_tpl_vars = \$this->_tpl_vars;\n"; |
959 |
|
|
|
960 |
|
|
|
961 |
|
|
$_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; |
962 |
|
|
$output .= "\$this->_smarty_include($_params);\n" . |
963 |
|
|
"\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . |
964 |
|
|
"unset(\$_smarty_tpl_vars);\n"; |
965 |
cvsjoko |
1.1 |
|
966 |
|
|
if (isset($assign_var)) { |
967 |
joko |
1.3 |
$output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; |
968 |
cvsjoko |
1.1 |
} |
969 |
|
|
|
970 |
|
|
$output .= ' ?>'; |
971 |
|
|
|
972 |
joko |
1.3 |
return $output; |
973 |
cvsjoko |
1.1 |
|
974 |
|
|
} |
975 |
|
|
|
976 |
joko |
1.3 |
/** |
977 |
|
|
* Compile {include ...} tag |
978 |
|
|
* |
979 |
|
|
* @param string $tag_args |
980 |
|
|
* @return string |
981 |
|
|
*/ |
982 |
cvsjoko |
1.1 |
function _compile_include_php_tag($tag_args) |
983 |
|
|
{ |
984 |
|
|
$attrs = $this->_parse_attrs($tag_args); |
985 |
|
|
|
986 |
|
|
if (empty($attrs['file'])) { |
987 |
joko |
1.3 |
$this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); |
988 |
cvsjoko |
1.1 |
} |
989 |
|
|
|
990 |
joko |
1.3 |
$assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); |
991 |
|
|
$once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; |
992 |
cvsjoko |
1.1 |
|
993 |
joko |
1.3 |
$arg_list = array(); |
994 |
|
|
foreach($attrs as $arg_name => $arg_value) { |
995 |
|
|
if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { |
996 |
|
|
if(is_bool($arg_value)) |
997 |
|
|
$arg_value = $arg_value ? 'true' : 'false'; |
998 |
|
|
$arg_list[] = "'$arg_name' => $arg_value"; |
999 |
|
|
} |
1000 |
|
|
} |
1001 |
|
|
|
1002 |
|
|
$_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; |
1003 |
|
|
|
1004 |
|
|
return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline; |
1005 |
cvsjoko |
1.1 |
} |
1006 |
|
|
|
1007 |
joko |
1.3 |
|
1008 |
|
|
/** |
1009 |
|
|
* Compile {section ...} tag |
1010 |
|
|
* |
1011 |
|
|
* @param string $tag_args |
1012 |
|
|
* @return string |
1013 |
|
|
*/ |
1014 |
cvsjoko |
1.1 |
function _compile_section_start($tag_args) |
1015 |
|
|
{ |
1016 |
|
|
$attrs = $this->_parse_attrs($tag_args); |
1017 |
|
|
$arg_list = array(); |
1018 |
|
|
|
1019 |
joko |
1.3 |
$output = '<?php '; |
1020 |
cvsjoko |
1.1 |
$section_name = $attrs['name']; |
1021 |
|
|
if (empty($section_name)) { |
1022 |
joko |
1.3 |
$this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); |
1023 |
cvsjoko |
1.1 |
} |
1024 |
|
|
|
1025 |
joko |
1.3 |
$output .= "unset(\$this->_sections[$section_name]);\n"; |
1026 |
cvsjoko |
1.1 |
$section_props = "\$this->_sections[$section_name]"; |
1027 |
|
|
|
1028 |
|
|
foreach ($attrs as $attr_name => $attr_value) { |
1029 |
|
|
switch ($attr_name) { |
1030 |
|
|
case 'loop': |
1031 |
joko |
1.3 |
$output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; |
1032 |
cvsjoko |
1.1 |
break; |
1033 |
|
|
|
1034 |
|
|
case 'show': |
1035 |
|
|
if (is_bool($attr_value)) |
1036 |
|
|
$show_attr_value = $attr_value ? 'true' : 'false'; |
1037 |
|
|
else |
1038 |
|
|
$show_attr_value = "(bool)$attr_value"; |
1039 |
|
|
$output .= "{$section_props}['show'] = $show_attr_value;\n"; |
1040 |
|
|
break; |
1041 |
|
|
|
1042 |
|
|
case 'name': |
1043 |
|
|
$output .= "{$section_props}['$attr_name'] = $attr_value;\n"; |
1044 |
|
|
break; |
1045 |
|
|
|
1046 |
|
|
case 'max': |
1047 |
|
|
case 'start': |
1048 |
|
|
$output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; |
1049 |
|
|
break; |
1050 |
|
|
|
1051 |
|
|
case 'step': |
1052 |
|
|
$output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; |
1053 |
|
|
break; |
1054 |
|
|
|
1055 |
|
|
default: |
1056 |
joko |
1.3 |
$this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); |
1057 |
cvsjoko |
1.1 |
break; |
1058 |
|
|
} |
1059 |
|
|
} |
1060 |
|
|
|
1061 |
|
|
if (!isset($attrs['show'])) |
1062 |
|
|
$output .= "{$section_props}['show'] = true;\n"; |
1063 |
|
|
|
1064 |
|
|
if (!isset($attrs['loop'])) |
1065 |
|
|
$output .= "{$section_props}['loop'] = 1;\n"; |
1066 |
|
|
|
1067 |
|
|
if (!isset($attrs['max'])) |
1068 |
|
|
$output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; |
1069 |
|
|
else |
1070 |
|
|
$output .= "if ({$section_props}['max'] < 0)\n" . |
1071 |
|
|
" {$section_props}['max'] = {$section_props}['loop'];\n"; |
1072 |
|
|
|
1073 |
|
|
if (!isset($attrs['step'])) |
1074 |
|
|
$output .= "{$section_props}['step'] = 1;\n"; |
1075 |
|
|
|
1076 |
|
|
if (!isset($attrs['start'])) |
1077 |
|
|
$output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; |
1078 |
|
|
else { |
1079 |
|
|
$output .= "if ({$section_props}['start'] < 0)\n" . |
1080 |
|
|
" {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . |
1081 |
|
|
"else\n" . |
1082 |
|
|
" {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; |
1083 |
|
|
} |
1084 |
|
|
|
1085 |
|
|
$output .= "if ({$section_props}['show']) {\n"; |
1086 |
|
|
if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { |
1087 |
|
|
$output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; |
1088 |
|
|
} else { |
1089 |
|
|
$output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; |
1090 |
|
|
} |
1091 |
|
|
$output .= " if ({$section_props}['total'] == 0)\n" . |
1092 |
|
|
" {$section_props}['show'] = false;\n" . |
1093 |
|
|
"} else\n" . |
1094 |
|
|
" {$section_props}['total'] = 0;\n"; |
1095 |
|
|
|
1096 |
|
|
$output .= "if ({$section_props}['show']):\n"; |
1097 |
|
|
$output .= " |
1098 |
|
|
for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; |
1099 |
|
|
{$section_props}['iteration'] <= {$section_props}['total']; |
1100 |
|
|
{$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; |
1101 |
|
|
$output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; |
1102 |
|
|
$output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; |
1103 |
|
|
$output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; |
1104 |
|
|
$output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; |
1105 |
|
|
$output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; |
1106 |
|
|
|
1107 |
|
|
$output .= "?>"; |
1108 |
|
|
|
1109 |
|
|
return $output; |
1110 |
|
|
} |
1111 |
|
|
|
1112 |
joko |
1.3 |
|
1113 |
|
|
/** |
1114 |
|
|
* Compile {foreach ...} tag. |
1115 |
|
|
* |
1116 |
|
|
* @param string $tag_args |
1117 |
|
|
* @return string |
1118 |
|
|
*/ |
1119 |
cvsjoko |
1.1 |
function _compile_foreach_start($tag_args) |
1120 |
|
|
{ |
1121 |
|
|
$attrs = $this->_parse_attrs($tag_args); |
1122 |
|
|
$arg_list = array(); |
1123 |
|
|
|
1124 |
|
|
if (empty($attrs['from'])) { |
1125 |
joko |
1.3 |
$this->_syntax_error("missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); |
1126 |
cvsjoko |
1.1 |
} |
1127 |
|
|
|
1128 |
|
|
if (empty($attrs['item'])) { |
1129 |
joko |
1.3 |
$this->_syntax_error("missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); |
1130 |
cvsjoko |
1.1 |
} |
1131 |
|
|
|
1132 |
|
|
$from = $attrs['from']; |
1133 |
|
|
$item = $this->_dequote($attrs['item']); |
1134 |
|
|
if (isset($attrs['name'])) |
1135 |
|
|
$name = $attrs['name']; |
1136 |
|
|
|
1137 |
|
|
$output = '<?php '; |
1138 |
|
|
if (isset($name)) { |
1139 |
|
|
$output .= "if (isset(\$this->_foreach[$name])) unset(\$this->_foreach[$name]);\n"; |
1140 |
|
|
$foreach_props = "\$this->_foreach[$name]"; |
1141 |
|
|
} |
1142 |
|
|
|
1143 |
|
|
$key_part = ''; |
1144 |
|
|
|
1145 |
|
|
foreach ($attrs as $attr_name => $attr_value) { |
1146 |
|
|
switch ($attr_name) { |
1147 |
|
|
case 'key': |
1148 |
|
|
$key = $this->_dequote($attrs['key']); |
1149 |
|
|
$key_part = "\$this->_tpl_vars['$key'] => "; |
1150 |
|
|
break; |
1151 |
|
|
|
1152 |
|
|
case 'name': |
1153 |
|
|
$output .= "{$foreach_props}['$attr_name'] = $attr_value;\n"; |
1154 |
|
|
break; |
1155 |
|
|
} |
1156 |
|
|
} |
1157 |
|
|
|
1158 |
|
|
if (isset($name)) { |
1159 |
joko |
1.3 |
$output .= "{$foreach_props}['total'] = count(\$_from = (array)$from);\n"; |
1160 |
cvsjoko |
1.1 |
$output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n"; |
1161 |
|
|
$output .= "if ({$foreach_props}['show']):\n"; |
1162 |
|
|
$output .= "{$foreach_props}['iteration'] = 0;\n"; |
1163 |
joko |
1.3 |
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; |
1164 |
cvsjoko |
1.1 |
$output .= " {$foreach_props}['iteration']++;\n"; |
1165 |
|
|
$output .= " {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n"; |
1166 |
|
|
$output .= " {$foreach_props}['last'] = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n"; |
1167 |
|
|
} else { |
1168 |
joko |
1.3 |
$output .= "if (count(\$_from = (array)$from)):\n"; |
1169 |
|
|
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; |
1170 |
cvsjoko |
1.1 |
} |
1171 |
|
|
$output .= '?>'; |
1172 |
|
|
|
1173 |
|
|
return $output; |
1174 |
|
|
} |
1175 |
|
|
|
1176 |
|
|
|
1177 |
joko |
1.3 |
/** |
1178 |
|
|
* Compile {capture} .. {/capture} tags |
1179 |
|
|
* |
1180 |
|
|
* @param boolean $start true if this is the {capture} tag |
1181 |
|
|
* @param string $tag_args |
1182 |
|
|
* @return string |
1183 |
|
|
*/ |
1184 |
|
|
|
1185 |
cvsjoko |
1.1 |
function _compile_capture_tag($start, $tag_args = '') |
1186 |
|
|
{ |
1187 |
|
|
$attrs = $this->_parse_attrs($tag_args); |
1188 |
|
|
|
1189 |
|
|
if ($start) { |
1190 |
|
|
if (isset($attrs['name'])) |
1191 |
|
|
$buffer = $attrs['name']; |
1192 |
|
|
else |
1193 |
|
|
$buffer = "'default'"; |
1194 |
|
|
|
1195 |
joko |
1.3 |
if (isset($attrs['assign'])) |
1196 |
|
|
$assign = $attrs['assign']; |
1197 |
|
|
else |
1198 |
|
|
$assign = null; |
1199 |
cvsjoko |
1.1 |
$output = "<?php ob_start(); ?>"; |
1200 |
joko |
1.3 |
$this->_capture_stack[] = array($buffer, $assign); |
1201 |
cvsjoko |
1.1 |
} else { |
1202 |
joko |
1.3 |
list($buffer, $assign) = array_pop($this->_capture_stack); |
1203 |
|
|
$output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); "; |
1204 |
|
|
if (isset($assign)) { |
1205 |
|
|
$output .= " \$this->assign($assign, ob_get_contents());"; |
1206 |
|
|
} |
1207 |
|
|
$output .= "ob_end_clean(); ?>"; |
1208 |
cvsjoko |
1.1 |
} |
1209 |
|
|
|
1210 |
|
|
return $output; |
1211 |
|
|
} |
1212 |
|
|
|
1213 |
joko |
1.3 |
/** |
1214 |
|
|
* Compile {if ...} tag |
1215 |
|
|
* |
1216 |
|
|
* @param string $tag_args |
1217 |
|
|
* @param boolean $elseif if true, uses elseif instead of if |
1218 |
|
|
* @return string |
1219 |
|
|
*/ |
1220 |
cvsjoko |
1.1 |
function _compile_if_tag($tag_args, $elseif = false) |
1221 |
|
|
{ |
1222 |
joko |
1.3 |
|
1223 |
cvsjoko |
1.1 |
/* Tokenize args for 'if' tag. */ |
1224 |
joko |
1.3 |
preg_match_all('/(?> |
1225 |
|
|
' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call |
1226 |
|
|
' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string |
1227 |
|
|
\-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token |
1228 |
|
|
\b\w+\b | # valid word token |
1229 |
|
|
\S+ # anything else |
1230 |
|
|
)/x', $tag_args, $match); |
1231 |
|
|
|
1232 |
cvsjoko |
1.1 |
$tokens = $match[0]; |
1233 |
|
|
|
1234 |
joko |
1.3 |
// make sure we have balanced parenthesis |
1235 |
|
|
$token_count = array_count_values($tokens); |
1236 |
|
|
if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { |
1237 |
|
|
$this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); |
1238 |
|
|
} |
1239 |
cvsjoko |
1.1 |
|
1240 |
|
|
$is_arg_stack = array(); |
1241 |
|
|
|
1242 |
joko |
1.3 |
for ($i = 0; $i < count($tokens); $i++) { |
1243 |
cvsjoko |
1.1 |
|
1244 |
|
|
$token = &$tokens[$i]; |
1245 |
joko |
1.3 |
|
1246 |
|
|
switch (strtolower($token)) { |
1247 |
|
|
case '!': |
1248 |
|
|
case '%': |
1249 |
|
|
case '!==': |
1250 |
|
|
case '==': |
1251 |
|
|
case '===': |
1252 |
|
|
case '>': |
1253 |
|
|
case '<': |
1254 |
|
|
case '!=': |
1255 |
|
|
case '<>': |
1256 |
|
|
case '<<': |
1257 |
|
|
case '>>': |
1258 |
|
|
case '<=': |
1259 |
|
|
case '>=': |
1260 |
|
|
case '&&': |
1261 |
|
|
case '||': |
1262 |
|
|
case '|': |
1263 |
|
|
case '^': |
1264 |
|
|
case '&': |
1265 |
|
|
case '~': |
1266 |
|
|
case ')': |
1267 |
|
|
case ',': |
1268 |
|
|
case '+': |
1269 |
|
|
case '-': |
1270 |
|
|
case '*': |
1271 |
|
|
case '/': |
1272 |
|
|
case '@': |
1273 |
|
|
break; |
1274 |
|
|
|
1275 |
cvsjoko |
1.1 |
case 'eq': |
1276 |
|
|
$token = '=='; |
1277 |
|
|
break; |
1278 |
|
|
|
1279 |
|
|
case 'ne': |
1280 |
|
|
case 'neq': |
1281 |
|
|
$token = '!='; |
1282 |
|
|
break; |
1283 |
|
|
|
1284 |
|
|
case 'lt': |
1285 |
|
|
$token = '<'; |
1286 |
|
|
break; |
1287 |
|
|
|
1288 |
|
|
case 'le': |
1289 |
|
|
case 'lte': |
1290 |
|
|
$token = '<='; |
1291 |
|
|
break; |
1292 |
|
|
|
1293 |
|
|
case 'gt': |
1294 |
|
|
$token = '>'; |
1295 |
|
|
break; |
1296 |
|
|
|
1297 |
|
|
case 'ge': |
1298 |
|
|
case 'gte': |
1299 |
|
|
$token = '>='; |
1300 |
|
|
break; |
1301 |
|
|
|
1302 |
|
|
case 'and': |
1303 |
|
|
$token = '&&'; |
1304 |
|
|
break; |
1305 |
|
|
|
1306 |
|
|
case 'or': |
1307 |
|
|
$token = '||'; |
1308 |
|
|
break; |
1309 |
|
|
|
1310 |
|
|
case 'not': |
1311 |
|
|
$token = '!'; |
1312 |
|
|
break; |
1313 |
|
|
|
1314 |
|
|
case 'mod': |
1315 |
|
|
$token = '%'; |
1316 |
|
|
break; |
1317 |
|
|
|
1318 |
|
|
case '(': |
1319 |
|
|
array_push($is_arg_stack, $i); |
1320 |
|
|
break; |
1321 |
|
|
|
1322 |
|
|
case 'is': |
1323 |
|
|
/* If last token was a ')', we operate on the parenthesized |
1324 |
|
|
expression. The start of the expression is on the stack. |
1325 |
|
|
Otherwise, we operate on the last encountered token. */ |
1326 |
|
|
if ($tokens[$i-1] == ')') |
1327 |
|
|
$is_arg_start = array_pop($is_arg_stack); |
1328 |
|
|
else |
1329 |
|
|
$is_arg_start = $i-1; |
1330 |
|
|
/* Construct the argument for 'is' expression, so it knows |
1331 |
|
|
what to operate on. */ |
1332 |
|
|
$is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); |
1333 |
|
|
|
1334 |
|
|
/* Pass all tokens from next one until the end to the |
1335 |
|
|
'is' expression parsing function. The function will |
1336 |
|
|
return modified tokens, where the first one is the result |
1337 |
|
|
of the 'is' expression and the rest are the tokens it |
1338 |
|
|
didn't touch. */ |
1339 |
|
|
$new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); |
1340 |
|
|
|
1341 |
|
|
/* Replace the old tokens with the new ones. */ |
1342 |
|
|
array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); |
1343 |
|
|
|
1344 |
|
|
/* Adjust argument start so that it won't change from the |
1345 |
|
|
current position for the next iteration. */ |
1346 |
|
|
$i = $is_arg_start; |
1347 |
|
|
break; |
1348 |
|
|
|
1349 |
|
|
default: |
1350 |
joko |
1.3 |
if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) { |
1351 |
|
|
// function call |
1352 |
|
|
if($this->security && |
1353 |
|
|
!in_array($token, $this->security_settings['IF_FUNCS'])) { |
1354 |
|
|
$this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); |
1355 |
|
|
} |
1356 |
|
|
} elseif(preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$!', $token)) { |
1357 |
|
|
// object or variable |
1358 |
|
|
$token = $this->_parse_var_props($token); |
1359 |
|
|
} elseif(is_numeric($token)) { |
1360 |
|
|
// number, skip it |
1361 |
|
|
} else { |
1362 |
|
|
$this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); |
1363 |
cvsjoko |
1.1 |
} |
1364 |
|
|
break; |
1365 |
|
|
} |
1366 |
|
|
} |
1367 |
|
|
|
1368 |
|
|
if ($elseif) |
1369 |
|
|
return '<?php elseif ('.implode(' ', $tokens).'): ?>'; |
1370 |
|
|
else |
1371 |
|
|
return '<?php if ('.implode(' ', $tokens).'): ?>'; |
1372 |
|
|
} |
1373 |
|
|
|
1374 |
|
|
|
1375 |
joko |
1.3 |
function _compile_arg_list($type, $name, $attrs, &$cache_code) { |
1376 |
|
|
$arg_list = array(); |
1377 |
|
|
|
1378 |
|
|
if (isset($type) && isset($name) |
1379 |
|
|
&& isset($this->_plugins[$type]) |
1380 |
|
|
&& isset($this->_plugins[$type][$name]) |
1381 |
|
|
&& empty($this->_plugins[$type][$name][4]) |
1382 |
|
|
&& is_array($this->_plugins[$type][$name][5]) |
1383 |
|
|
) { |
1384 |
|
|
/* we have a list of parameters that should be cached */ |
1385 |
|
|
$_cache_attrs = $this->_plugins[$type][$name][5]; |
1386 |
|
|
$_count = $this->_cache_attrs_count++; |
1387 |
|
|
$cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; |
1388 |
|
|
|
1389 |
|
|
} else { |
1390 |
|
|
/* no parameters are cached */ |
1391 |
|
|
$_cache_attrs = null; |
1392 |
|
|
} |
1393 |
|
|
|
1394 |
|
|
foreach ($attrs as $arg_name => $arg_value) { |
1395 |
|
|
if (is_bool($arg_value)) |
1396 |
|
|
$arg_value = $arg_value ? 'true' : 'false'; |
1397 |
|
|
if (is_null($arg_value)) |
1398 |
|
|
$arg_value = 'null'; |
1399 |
|
|
if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { |
1400 |
|
|
$arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; |
1401 |
|
|
} else { |
1402 |
|
|
$arg_list[] = "'$arg_name' => $arg_value"; |
1403 |
|
|
} |
1404 |
|
|
} |
1405 |
|
|
return $arg_list; |
1406 |
|
|
} |
1407 |
|
|
|
1408 |
|
|
/** |
1409 |
|
|
* Parse is expression |
1410 |
|
|
* |
1411 |
|
|
* @param string $is_arg |
1412 |
|
|
* @param array $tokens |
1413 |
|
|
* @return array |
1414 |
|
|
*/ |
1415 |
cvsjoko |
1.1 |
function _parse_is_expr($is_arg, $tokens) |
1416 |
|
|
{ |
1417 |
|
|
$expr_end = 0; |
1418 |
|
|
$negate_expr = false; |
1419 |
|
|
|
1420 |
|
|
if (($first_token = array_shift($tokens)) == 'not') { |
1421 |
|
|
$negate_expr = true; |
1422 |
|
|
$expr_type = array_shift($tokens); |
1423 |
|
|
} else |
1424 |
|
|
$expr_type = $first_token; |
1425 |
|
|
|
1426 |
|
|
switch ($expr_type) { |
1427 |
|
|
case 'even': |
1428 |
joko |
1.3 |
if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { |
1429 |
cvsjoko |
1.1 |
$expr_end++; |
1430 |
|
|
$expr_arg = $tokens[$expr_end++]; |
1431 |
joko |
1.3 |
$expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; |
1432 |
cvsjoko |
1.1 |
} else |
1433 |
joko |
1.3 |
$expr = "!(1 & $is_arg)"; |
1434 |
cvsjoko |
1.1 |
break; |
1435 |
|
|
|
1436 |
|
|
case 'odd': |
1437 |
joko |
1.3 |
if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { |
1438 |
cvsjoko |
1.1 |
$expr_end++; |
1439 |
|
|
$expr_arg = $tokens[$expr_end++]; |
1440 |
joko |
1.3 |
$expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; |
1441 |
cvsjoko |
1.1 |
} else |
1442 |
joko |
1.3 |
$expr = "(1 & $is_arg)"; |
1443 |
cvsjoko |
1.1 |
break; |
1444 |
|
|
|
1445 |
|
|
case 'div': |
1446 |
|
|
if (@$tokens[$expr_end] == 'by') { |
1447 |
|
|
$expr_end++; |
1448 |
|
|
$expr_arg = $tokens[$expr_end++]; |
1449 |
joko |
1.3 |
$expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; |
1450 |
cvsjoko |
1.1 |
} else { |
1451 |
joko |
1.3 |
$this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); |
1452 |
cvsjoko |
1.1 |
} |
1453 |
|
|
break; |
1454 |
|
|
|
1455 |
|
|
default: |
1456 |
joko |
1.3 |
$this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); |
1457 |
cvsjoko |
1.1 |
break; |
1458 |
|
|
} |
1459 |
|
|
|
1460 |
|
|
if ($negate_expr) { |
1461 |
|
|
$expr = "!($expr)"; |
1462 |
|
|
} |
1463 |
|
|
|
1464 |
|
|
array_splice($tokens, 0, $expr_end, $expr); |
1465 |
|
|
|
1466 |
|
|
return $tokens; |
1467 |
|
|
} |
1468 |
|
|
|
1469 |
|
|
|
1470 |
joko |
1.3 |
/** |
1471 |
|
|
* Parse attribute string |
1472 |
|
|
* |
1473 |
|
|
* @param string $tag_args |
1474 |
|
|
* @return array |
1475 |
|
|
*/ |
1476 |
|
|
function _parse_attrs($tag_args) |
1477 |
cvsjoko |
1.1 |
{ |
1478 |
joko |
1.3 |
|
1479 |
cvsjoko |
1.1 |
/* Tokenize tag attributes. */ |
1480 |
joko |
1.3 |
preg_match_all('/(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) |
1481 |
cvsjoko |
1.1 |
)+ | |
1482 |
|
|
[=] |
1483 |
|
|
/x', $tag_args, $match); |
1484 |
|
|
$tokens = $match[0]; |
1485 |
|
|
|
1486 |
|
|
$attrs = array(); |
1487 |
|
|
/* Parse state: |
1488 |
|
|
0 - expecting attribute name |
1489 |
|
|
1 - expecting '=' |
1490 |
|
|
2 - expecting attribute value (not '=') */ |
1491 |
|
|
$state = 0; |
1492 |
|
|
|
1493 |
|
|
foreach ($tokens as $token) { |
1494 |
|
|
switch ($state) { |
1495 |
|
|
case 0: |
1496 |
|
|
/* If the token is a valid identifier, we set attribute name |
1497 |
|
|
and go to state 1. */ |
1498 |
|
|
if (preg_match('!^\w+$!', $token)) { |
1499 |
|
|
$attr_name = $token; |
1500 |
|
|
$state = 1; |
1501 |
|
|
} else |
1502 |
joko |
1.3 |
$this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); |
1503 |
cvsjoko |
1.1 |
break; |
1504 |
|
|
|
1505 |
|
|
case 1: |
1506 |
|
|
/* If the token is '=', then we go to state 2. */ |
1507 |
|
|
if ($token == '=') { |
1508 |
|
|
$state = 2; |
1509 |
|
|
} else |
1510 |
joko |
1.3 |
$this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); |
1511 |
cvsjoko |
1.1 |
break; |
1512 |
|
|
|
1513 |
|
|
case 2: |
1514 |
|
|
/* If token is not '=', we set the attribute value and go to |
1515 |
|
|
state 0. */ |
1516 |
|
|
if ($token != '=') { |
1517 |
|
|
/* We booleanize the token if it's a non-quoted possible |
1518 |
|
|
boolean value. */ |
1519 |
joko |
1.3 |
if (preg_match('!^(on|yes|true)$!', $token)) { |
1520 |
|
|
$token = 'true'; |
1521 |
|
|
} else if (preg_match('!^(off|no|false)$!', $token)) { |
1522 |
|
|
$token = 'false'; |
1523 |
|
|
} else if ($token == 'null') { |
1524 |
|
|
$token = 'null'; |
1525 |
|
|
} else if (preg_match('!^-?([0-9]+|0[xX][0-9a-fA-F]+)$!', $token)) { |
1526 |
|
|
/* treat integer literally */ |
1527 |
|
|
} else if (!preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) { |
1528 |
|
|
/* treat as a string, double-quote it escaping quotes */ |
1529 |
|
|
$token = '"'.addslashes($token).'"'; |
1530 |
|
|
} |
1531 |
cvsjoko |
1.1 |
|
1532 |
|
|
$attrs[$attr_name] = $token; |
1533 |
|
|
$state = 0; |
1534 |
|
|
} else |
1535 |
joko |
1.3 |
$this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); |
1536 |
cvsjoko |
1.1 |
break; |
1537 |
|
|
} |
1538 |
joko |
1.3 |
$last_token = $token; |
1539 |
|
|
} |
1540 |
|
|
|
1541 |
|
|
if($state != 0) { |
1542 |
|
|
if($state == 1) { |
1543 |
|
|
$this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); |
1544 |
|
|
} else { |
1545 |
|
|
$this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); |
1546 |
|
|
} |
1547 |
cvsjoko |
1.1 |
} |
1548 |
|
|
|
1549 |
|
|
$this->_parse_vars_props($attrs); |
1550 |
|
|
|
1551 |
|
|
return $attrs; |
1552 |
|
|
} |
1553 |
|
|
|
1554 |
joko |
1.3 |
/** |
1555 |
|
|
* compile multiple variables and section properties tokens into |
1556 |
|
|
* PHP code |
1557 |
|
|
* |
1558 |
|
|
* @param array $tokens |
1559 |
|
|
*/ |
1560 |
cvsjoko |
1.1 |
function _parse_vars_props(&$tokens) |
1561 |
|
|
{ |
1562 |
joko |
1.3 |
foreach($tokens as $key => $val) { |
1563 |
|
|
$tokens[$key] = $this->_parse_var_props($val); |
1564 |
|
|
} |
1565 |
|
|
} |
1566 |
cvsjoko |
1.1 |
|
1567 |
joko |
1.3 |
/** |
1568 |
|
|
* compile single variable and section properties token into |
1569 |
|
|
* PHP code |
1570 |
|
|
* |
1571 |
|
|
* @param string $val |
1572 |
|
|
* @param string $tag_attrs |
1573 |
|
|
* @return string |
1574 |
|
|
*/ |
1575 |
|
|
function _parse_var_props($val) |
1576 |
|
|
{ |
1577 |
|
|
$val = trim($val); |
1578 |
|
|
|
1579 |
|
|
if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$!', $val, $match)) { |
1580 |
|
|
// $ variable or object |
1581 |
|
|
$return = $this->_parse_var($match[1]); |
1582 |
|
|
$modifiers = $match[2]; |
1583 |
|
|
if (!empty($this->default_modifiers) && !preg_match('!(^|\|)smarty:nodefaults($|\|)!',$modifiers)) { |
1584 |
|
|
$_default_mod_string = implode('|',(array)$this->default_modifiers); |
1585 |
|
|
$modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; |
1586 |
|
|
} |
1587 |
|
|
$this->_parse_modifiers($return, $modifiers); |
1588 |
|
|
return $return; |
1589 |
|
|
} elseif (preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { |
1590 |
|
|
// double quoted text |
1591 |
|
|
preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); |
1592 |
|
|
$return = $this->_expand_quoted_text($match[1]); |
1593 |
|
|
if($match[2] != '') { |
1594 |
|
|
$this->_parse_modifiers($return, $match[2]); |
1595 |
|
|
} |
1596 |
|
|
return $return; |
1597 |
|
|
} |
1598 |
|
|
elseif(preg_match('!^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { |
1599 |
|
|
// numerical constant |
1600 |
|
|
preg_match('!^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); |
1601 |
|
|
if($match[2] != '') { |
1602 |
|
|
$this->_parse_modifiers($match[1], $match[2]); |
1603 |
|
|
return $match[1]; |
1604 |
|
|
} |
1605 |
cvsjoko |
1.1 |
} |
1606 |
joko |
1.3 |
elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { |
1607 |
|
|
// single quoted text |
1608 |
|
|
preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); |
1609 |
|
|
if($match[2] != '') { |
1610 |
|
|
$this->_parse_modifiers($match[1], $match[2]); |
1611 |
|
|
return $match[1]; |
1612 |
|
|
} |
1613 |
cvsjoko |
1.1 |
} |
1614 |
joko |
1.3 |
elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { |
1615 |
|
|
// config var |
1616 |
|
|
return $this->_parse_conf_var($val); |
1617 |
|
|
} |
1618 |
|
|
elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { |
1619 |
|
|
// section var |
1620 |
|
|
return $this->_parse_section_prop($val); |
1621 |
|
|
} |
1622 |
|
|
elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { |
1623 |
|
|
// literal string |
1624 |
|
|
return $this->_expand_quoted_text('"' . $val .'"'); |
1625 |
|
|
} |
1626 |
|
|
return $val; |
1627 |
|
|
} |
1628 |
|
|
|
1629 |
|
|
/** |
1630 |
|
|
* expand quoted text with embedded variables |
1631 |
|
|
* |
1632 |
|
|
* @param string $var_expr |
1633 |
|
|
* @return string |
1634 |
|
|
*/ |
1635 |
|
|
function _expand_quoted_text($var_expr) |
1636 |
|
|
{ |
1637 |
|
|
// if contains unescaped $, expand it |
1638 |
|
|
if(preg_match_all('%(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)%', $var_expr, $_match)) { |
1639 |
|
|
$_match = $_match[0]; |
1640 |
|
|
rsort($_match); |
1641 |
|
|
reset($_match); |
1642 |
|
|
foreach($_match as $_var) { |
1643 |
|
|
$var_expr = str_replace ($_var, '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."', $var_expr); |
1644 |
cvsjoko |
1.1 |
} |
1645 |
joko |
1.3 |
$_return = preg_replace('%\.""|(?<!\\\\)""\.%', '', $var_expr); |
1646 |
|
|
} else { |
1647 |
|
|
$_return = $var_expr; |
1648 |
cvsjoko |
1.1 |
} |
1649 |
joko |
1.3 |
// replace double quoted literal string with single quotes |
1650 |
|
|
$_return = preg_replace('!^"([\s\w]+)"$!',"'\\1'",$_return); |
1651 |
|
|
return $_return; |
1652 |
cvsjoko |
1.1 |
} |
1653 |
|
|
|
1654 |
joko |
1.3 |
/** |
1655 |
|
|
* parse variable expression into PHP code |
1656 |
|
|
* |
1657 |
|
|
* @param string $var_expr |
1658 |
|
|
* @param string $output |
1659 |
|
|
* @return string |
1660 |
|
|
*/ |
1661 |
cvsjoko |
1.1 |
function _parse_var($var_expr) |
1662 |
|
|
{ |
1663 |
joko |
1.3 |
$_has_math = false; |
1664 |
|
|
$_math_vars = preg_split('!('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')!', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); |
1665 |
|
|
|
1666 |
|
|
if(count($_math_vars) > 1) { |
1667 |
|
|
$_first_var = ""; |
1668 |
|
|
$_complete_var = ""; |
1669 |
|
|
$_output = ""; |
1670 |
|
|
// simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) |
1671 |
|
|
foreach($_math_vars as $_k => $_math_var) { |
1672 |
|
|
$_math_var = $_math_vars[$_k]; |
1673 |
|
|
|
1674 |
|
|
if(!empty($_math_var) || is_numeric($_math_var)) { |
1675 |
|
|
// hit a math operator, so process the stuff which came before it |
1676 |
|
|
if(preg_match('!^' . $this->_dvar_math_regexp . '$!', $_math_var)) { |
1677 |
|
|
$_has_math = true; |
1678 |
|
|
if(!empty($_complete_var) || is_numeric($_complete_var)) { |
1679 |
|
|
$_output .= $this->_parse_var($_complete_var); |
1680 |
|
|
} |
1681 |
|
|
|
1682 |
|
|
// just output the math operator to php |
1683 |
|
|
$_output .= $_math_var; |
1684 |
|
|
|
1685 |
|
|
if(empty($_first_var)) |
1686 |
|
|
$_first_var = $_complete_var; |
1687 |
|
|
|
1688 |
|
|
$_complete_var = ""; |
1689 |
|
|
} else { |
1690 |
|
|
// fetch multiple -> (like $foo->bar->baz ) which wouldn't get fetched else, because it would only get $foo->bar and treat the ->baz as "-" ">baz" then |
1691 |
|
|
for($_i = $_k + 1; $_i <= count($_math_vars); $_i += 2) { |
1692 |
|
|
// fetch -> because it gets splitted at - and move it back together |
1693 |
|
|
if( /* prevent notice */ (isset($_math_vars[$_i]) && isset($_math_vars[$_i+1])) && ($_math_vars[$_i] === '-' && $_math_vars[$_i+1]{0} === '>')) { |
1694 |
|
|
$_math_var .= $_math_vars[$_i].$_math_vars[$_i+1]; |
1695 |
|
|
$_math_vars[$_i] = $_math_vars[$_i+1] = ''; |
1696 |
|
|
} else { |
1697 |
|
|
break; |
1698 |
|
|
} |
1699 |
|
|
} |
1700 |
|
|
$_complete_var .= $_math_var; |
1701 |
|
|
} |
1702 |
|
|
} |
1703 |
|
|
} |
1704 |
|
|
if($_has_math) { |
1705 |
|
|
if(!empty($_complete_var) || is_numeric($_complete_var)) |
1706 |
|
|
$_output .= $this->_parse_var($_complete_var); |
1707 |
cvsjoko |
1.1 |
|
1708 |
joko |
1.3 |
// get the modifiers working (only the last var from math + modifier is left) |
1709 |
|
|
$var_expr = $_complete_var; |
1710 |
cvsjoko |
1.1 |
} |
1711 |
|
|
} |
1712 |
|
|
|
1713 |
joko |
1.3 |
// prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) |
1714 |
|
|
if(is_numeric($var_expr{0})) |
1715 |
|
|
$_var_ref = $var_expr; |
1716 |
|
|
else |
1717 |
|
|
$_var_ref = substr($var_expr, 1); |
1718 |
|
|
|
1719 |
|
|
if(!$_has_math) { |
1720 |
|
|
// get [foo] and .foo and ->foo and (...) pieces |
1721 |
|
|
preg_match_all('!(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+!', $_var_ref, $match); |
1722 |
|
|
|
1723 |
|
|
$_indexes = $match[0]; |
1724 |
|
|
$_var_name = array_shift($_indexes); |
1725 |
|
|
|
1726 |
|
|
/* Handle $smarty.* variable references as a special case. */ |
1727 |
|
|
if ($_var_name == 'smarty') { |
1728 |
|
|
/* |
1729 |
|
|
* If the reference could be compiled, use the compiled output; |
1730 |
|
|
* otherwise, fall back on the $smarty variable generated at |
1731 |
|
|
* run-time. |
1732 |
|
|
*/ |
1733 |
|
|
if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { |
1734 |
|
|
$_output = $smarty_ref; |
1735 |
cvsjoko |
1.1 |
} else { |
1736 |
joko |
1.3 |
$_var_name = substr(array_shift($_indexes), 1); |
1737 |
|
|
$_output = "\$this->_smarty_vars['$_var_name']"; |
1738 |
|
|
} |
1739 |
|
|
} elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) { |
1740 |
|
|
// because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers |
1741 |
|
|
if(count($_indexes) > 0) |
1742 |
|
|
{ |
1743 |
|
|
$_var_name .= implode("", $_indexes); |
1744 |
|
|
$_indexes = array(); |
1745 |
|
|
} |
1746 |
|
|
$_output = $_var_name; |
1747 |
cvsjoko |
1.1 |
} else { |
1748 |
joko |
1.3 |
$_output = "\$this->_tpl_vars['$_var_name']"; |
1749 |
|
|
} |
1750 |
|
|
|
1751 |
|
|
foreach ($_indexes as $_index) { |
1752 |
|
|
if ($_index{0} == '[') { |
1753 |
|
|
$_index = substr($_index, 1, -1); |
1754 |
|
|
if (is_numeric($_index)) { |
1755 |
|
|
$_output .= "[$_index]"; |
1756 |
|
|
} elseif ($_index{0} == '$') { |
1757 |
|
|
if (strpos($_index, '.') !== false) { |
1758 |
|
|
$_output .= '[' . $this->_parse_var($_index) . ']'; |
1759 |
|
|
} else { |
1760 |
|
|
$_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; |
1761 |
|
|
} |
1762 |
|
|
} else { |
1763 |
|
|
$_var_parts = explode('.', $_index); |
1764 |
|
|
$_var_section = $_var_parts[0]; |
1765 |
|
|
$_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; |
1766 |
|
|
$_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; |
1767 |
|
|
} |
1768 |
|
|
} else if ($_index{0} == '.') { |
1769 |
|
|
if ($_index{1} == '$') |
1770 |
|
|
$_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; |
1771 |
|
|
else |
1772 |
|
|
$_output .= "['" . substr($_index, 1) . "']"; |
1773 |
|
|
} else if (substr($_index,0,2) == '->') { |
1774 |
|
|
if(substr($_index,2,2) == '__') { |
1775 |
|
|
$this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); |
1776 |
|
|
} elseif($this->security && substr($_index, 2, 1) == '_') { |
1777 |
|
|
$this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); |
1778 |
|
|
} elseif ($_index{2} == '$') { |
1779 |
|
|
if ($this->security) { |
1780 |
|
|
$this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); |
1781 |
|
|
} else { |
1782 |
|
|
$_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; |
1783 |
|
|
} |
1784 |
|
|
} else { |
1785 |
|
|
$_output .= $_index; |
1786 |
|
|
} |
1787 |
|
|
} elseif ($_index{0} == '(') { |
1788 |
|
|
$_index = $this->_parse_parenth_args($_index); |
1789 |
|
|
$_output .= $_index; |
1790 |
|
|
} else { |
1791 |
|
|
$_output .= $_index; |
1792 |
|
|
} |
1793 |
cvsjoko |
1.1 |
} |
1794 |
|
|
} |
1795 |
|
|
|
1796 |
joko |
1.3 |
return $_output; |
1797 |
cvsjoko |
1.1 |
} |
1798 |
|
|
|
1799 |
joko |
1.3 |
/** |
1800 |
|
|
* parse arguments in function call parenthesis |
1801 |
|
|
* |
1802 |
|
|
* @param string $parenth_args |
1803 |
|
|
* @return string |
1804 |
|
|
*/ |
1805 |
|
|
function _parse_parenth_args($parenth_args) |
1806 |
|
|
{ |
1807 |
|
|
preg_match_all('!' . $this->_param_regexp . '!',$parenth_args, $match); |
1808 |
|
|
$match = $match[0]; |
1809 |
|
|
rsort($match); |
1810 |
|
|
reset($match); |
1811 |
|
|
$orig_vals = $match; |
1812 |
|
|
$this->_parse_vars_props($match); |
1813 |
|
|
return str_replace($orig_vals, $match, $parenth_args); |
1814 |
|
|
} |
1815 |
|
|
|
1816 |
|
|
/** |
1817 |
|
|
* parse configuration variable expression into PHP code |
1818 |
|
|
* |
1819 |
|
|
* @param string $conf_var_expr |
1820 |
|
|
*/ |
1821 |
cvsjoko |
1.1 |
function _parse_conf_var($conf_var_expr) |
1822 |
|
|
{ |
1823 |
|
|
$parts = explode('|', $conf_var_expr, 2); |
1824 |
|
|
$var_ref = $parts[0]; |
1825 |
|
|
$modifiers = isset($parts[1]) ? $parts[1] : ''; |
1826 |
|
|
|
1827 |
|
|
$var_name = substr($var_ref, 1, -1); |
1828 |
|
|
|
1829 |
|
|
$output = "\$this->_config[0]['vars']['$var_name']"; |
1830 |
|
|
|
1831 |
|
|
$this->_parse_modifiers($output, $modifiers); |
1832 |
|
|
|
1833 |
|
|
return $output; |
1834 |
|
|
} |
1835 |
|
|
|
1836 |
joko |
1.3 |
/** |
1837 |
|
|
* parse section property expression into PHP code |
1838 |
|
|
* |
1839 |
|
|
* @param string $section_prop_expr |
1840 |
|
|
* @return string |
1841 |
|
|
*/ |
1842 |
cvsjoko |
1.1 |
function _parse_section_prop($section_prop_expr) |
1843 |
|
|
{ |
1844 |
|
|
$parts = explode('|', $section_prop_expr, 2); |
1845 |
|
|
$var_ref = $parts[0]; |
1846 |
|
|
$modifiers = isset($parts[1]) ? $parts[1] : ''; |
1847 |
|
|
|
1848 |
|
|
preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); |
1849 |
|
|
$section_name = $match[1]; |
1850 |
|
|
$prop_name = $match[2]; |
1851 |
|
|
|
1852 |
|
|
$output = "\$this->_sections['$section_name']['$prop_name']"; |
1853 |
|
|
|
1854 |
|
|
$this->_parse_modifiers($output, $modifiers); |
1855 |
|
|
|
1856 |
|
|
return $output; |
1857 |
|
|
} |
1858 |
|
|
|
1859 |
|
|
|
1860 |
joko |
1.3 |
/** |
1861 |
|
|
* parse modifier chain into PHP code |
1862 |
|
|
* |
1863 |
|
|
* sets $output to parsed modified chain |
1864 |
|
|
* @param string $output |
1865 |
|
|
* @param string $modifier_string |
1866 |
|
|
*/ |
1867 |
cvsjoko |
1.1 |
function _parse_modifiers(&$output, $modifier_string) |
1868 |
|
|
{ |
1869 |
joko |
1.3 |
preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $_match); |
1870 |
|
|
list(, $_modifiers, $modifier_arg_strings) = $_match; |
1871 |
|
|
|
1872 |
|
|
for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { |
1873 |
|
|
$_modifier_name = $_modifiers[$_i]; |
1874 |
|
|
|
1875 |
|
|
if($_modifier_name == 'smarty') { |
1876 |
|
|
// skip smarty modifier |
1877 |
|
|
continue; |
1878 |
|
|
} |
1879 |
|
|
|
1880 |
|
|
preg_match_all('!:(' . $this->_qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$_i], $_match); |
1881 |
|
|
$_modifier_args = $_match[1]; |
1882 |
|
|
|
1883 |
|
|
if ($_modifier_name{0} == '@') { |
1884 |
|
|
$_map_array = false; |
1885 |
|
|
$_modifier_name = substr($_modifier_name, 1); |
1886 |
cvsjoko |
1.1 |
} else { |
1887 |
joko |
1.3 |
$_map_array = true; |
1888 |
|
|
} |
1889 |
|
|
|
1890 |
|
|
if (empty($this->_plugins['modifier'][$_modifier_name]) |
1891 |
|
|
&& !$this->_get_plugin_filepath('modifier', $_modifier_name) |
1892 |
|
|
&& function_exists($_modifier_name)) { |
1893 |
|
|
if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { |
1894 |
|
|
$this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); |
1895 |
|
|
} else { |
1896 |
|
|
$this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); |
1897 |
|
|
} |
1898 |
cvsjoko |
1.1 |
} |
1899 |
joko |
1.3 |
$this->_add_plugin('modifier', $_modifier_name); |
1900 |
cvsjoko |
1.1 |
|
1901 |
joko |
1.3 |
$this->_parse_vars_props($_modifier_args); |
1902 |
cvsjoko |
1.1 |
|
1903 |
joko |
1.3 |
if($_modifier_name == 'default') { |
1904 |
|
|
// supress notifications of default modifier vars and args |
1905 |
|
|
if($output{0} == '$') { |
1906 |
|
|
$output = '@' . $output; |
1907 |
|
|
} |
1908 |
|
|
if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') { |
1909 |
|
|
$_modifier_args[0] = '@' . $_modifier_args[0]; |
1910 |
|
|
} |
1911 |
|
|
} |
1912 |
|
|
if (count($_modifier_args) > 0) |
1913 |
|
|
$_modifier_args = ', '.implode(', ', $_modifier_args); |
1914 |
cvsjoko |
1.1 |
else |
1915 |
joko |
1.3 |
$_modifier_args = ''; |
1916 |
|
|
|
1917 |
|
|
if ($_map_array) { |
1918 |
|
|
$output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; |
1919 |
cvsjoko |
1.1 |
|
1920 |
joko |
1.3 |
} else { |
1921 |
|
|
|
1922 |
|
|
$output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; |
1923 |
|
|
|
1924 |
|
|
} |
1925 |
cvsjoko |
1.1 |
} |
1926 |
|
|
} |
1927 |
|
|
|
1928 |
|
|
|
1929 |
joko |
1.3 |
/** |
1930 |
|
|
* add plugin |
1931 |
|
|
* |
1932 |
|
|
* @param string $type |
1933 |
|
|
* @param string $name |
1934 |
|
|
* @param boolean? $delayed_loading |
1935 |
|
|
*/ |
1936 |
cvsjoko |
1.1 |
function _add_plugin($type, $name, $delayed_loading = null) |
1937 |
|
|
{ |
1938 |
|
|
if (!isset($this->_plugin_info[$type])) { |
1939 |
|
|
$this->_plugin_info[$type] = array(); |
1940 |
|
|
} |
1941 |
|
|
if (!isset($this->_plugin_info[$type][$name])) { |
1942 |
|
|
$this->_plugin_info[$type][$name] = array($this->_current_file, |
1943 |
|
|
$this->_current_line_no, |
1944 |
|
|
$delayed_loading); |
1945 |
|
|
} |
1946 |
|
|
} |
1947 |
|
|
|
1948 |
joko |
1.3 |
|
1949 |
|
|
/** |
1950 |
|
|
* Compiles references of type $smarty.foo |
1951 |
|
|
* |
1952 |
|
|
* @param string $indexes |
1953 |
|
|
* @return string |
1954 |
|
|
*/ |
1955 |
cvsjoko |
1.1 |
function _compile_smarty_ref(&$indexes) |
1956 |
|
|
{ |
1957 |
|
|
/* Extract the reference name. */ |
1958 |
joko |
1.3 |
$_ref = substr($indexes[0], 1); |
1959 |
|
|
foreach($indexes as $_index_no=>$_index) { |
1960 |
|
|
if ($_index{0} != '.' && $_index_no<2 || !preg_match('!^(\.|\[|->)!', $_index)) { |
1961 |
|
|
$this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); |
1962 |
|
|
} |
1963 |
|
|
} |
1964 |
cvsjoko |
1.1 |
|
1965 |
joko |
1.3 |
switch ($_ref) { |
1966 |
cvsjoko |
1.1 |
case 'now': |
1967 |
|
|
$compiled_ref = 'time()'; |
1968 |
joko |
1.3 |
$_max_index = 1; |
1969 |
cvsjoko |
1.1 |
break; |
1970 |
|
|
|
1971 |
|
|
case 'foreach': |
1972 |
|
|
case 'section': |
1973 |
|
|
array_shift($indexes); |
1974 |
joko |
1.3 |
$_var = $this->_parse_var_props(substr($indexes[0], 1)); |
1975 |
|
|
if ($_ref == 'foreach') |
1976 |
|
|
$compiled_ref = "\$this->_foreach[$_var]"; |
1977 |
cvsjoko |
1.1 |
else |
1978 |
joko |
1.3 |
$compiled_ref = "\$this->_sections[$_var]"; |
1979 |
cvsjoko |
1.1 |
break; |
1980 |
|
|
|
1981 |
|
|
case 'get': |
1982 |
joko |
1.3 |
$compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; |
1983 |
cvsjoko |
1.1 |
break; |
1984 |
|
|
|
1985 |
|
|
case 'post': |
1986 |
joko |
1.3 |
$compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; |
1987 |
cvsjoko |
1.1 |
break; |
1988 |
|
|
|
1989 |
|
|
case 'cookies': |
1990 |
joko |
1.3 |
$compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; |
1991 |
cvsjoko |
1.1 |
break; |
1992 |
|
|
|
1993 |
|
|
case 'env': |
1994 |
joko |
1.3 |
$compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; |
1995 |
cvsjoko |
1.1 |
break; |
1996 |
|
|
|
1997 |
|
|
case 'server': |
1998 |
joko |
1.3 |
$compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; |
1999 |
cvsjoko |
1.1 |
break; |
2000 |
|
|
|
2001 |
|
|
case 'session': |
2002 |
joko |
1.3 |
$compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; |
2003 |
cvsjoko |
1.1 |
break; |
2004 |
|
|
|
2005 |
|
|
/* |
2006 |
|
|
* These cases are handled either at run-time or elsewhere in the |
2007 |
|
|
* compiler. |
2008 |
|
|
*/ |
2009 |
|
|
case 'request': |
2010 |
joko |
1.3 |
if ($this->request_use_auto_globals) { |
2011 |
|
|
$compiled_ref = '$_REQUEST'; |
2012 |
|
|
break; |
2013 |
|
|
} else { |
2014 |
|
|
$this->_init_smarty_vars = true; |
2015 |
|
|
} |
2016 |
cvsjoko |
1.1 |
return null; |
2017 |
|
|
|
2018 |
|
|
case 'capture': |
2019 |
|
|
return null; |
2020 |
|
|
|
2021 |
|
|
case 'template': |
2022 |
|
|
$compiled_ref = "'$this->_current_file'"; |
2023 |
joko |
1.3 |
$_max_index = 1; |
2024 |
|
|
break; |
2025 |
|
|
|
2026 |
|
|
case 'version': |
2027 |
|
|
$compiled_ref = "'$this->_version'"; |
2028 |
|
|
$_max_index = 1; |
2029 |
|
|
break; |
2030 |
|
|
|
2031 |
|
|
case 'const': |
2032 |
|
|
array_shift($indexes); |
2033 |
|
|
$_val = $this->_parse_var_props(substr($indexes[0],1)); |
2034 |
|
|
$compiled_ref = '@constant(' . $_val . ')'; |
2035 |
|
|
$_max_index = 1; |
2036 |
|
|
break; |
2037 |
|
|
|
2038 |
|
|
case 'config': |
2039 |
|
|
$compiled_ref = "\$this->_config[0]['vars']"; |
2040 |
|
|
$_max_index = 3; |
2041 |
cvsjoko |
1.1 |
break; |
2042 |
|
|
|
2043 |
|
|
default: |
2044 |
joko |
1.3 |
$this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); |
2045 |
cvsjoko |
1.1 |
break; |
2046 |
|
|
} |
2047 |
|
|
|
2048 |
joko |
1.3 |
if (isset($_max_index) && count($indexes) > $_max_index) { |
2049 |
|
|
$this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); |
2050 |
|
|
} |
2051 |
|
|
|
2052 |
cvsjoko |
1.1 |
array_shift($indexes); |
2053 |
|
|
return $compiled_ref; |
2054 |
|
|
} |
2055 |
|
|
|
2056 |
joko |
1.3 |
/** |
2057 |
|
|
* compiles call to plugin of type $type with name $name |
2058 |
|
|
* returns a string containing the function-name or method call |
2059 |
|
|
* without the paramter-list that would have follow to make the |
2060 |
|
|
* call valid php-syntax |
2061 |
|
|
* |
2062 |
|
|
* @param string $type |
2063 |
|
|
* @param string $name |
2064 |
|
|
* @return string |
2065 |
|
|
*/ |
2066 |
|
|
function _compile_plugin_call($type, $name) { |
2067 |
|
|
if (isset($this->_plugins[$type][$name])) { |
2068 |
|
|
/* plugin loaded */ |
2069 |
|
|
if (is_array($this->_plugins[$type][$name][0])) { |
2070 |
|
|
return ((is_object($this->_plugins[$type][$name][0][0])) ? |
2071 |
|
|
"\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ |
2072 |
|
|
: (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ |
2073 |
|
|
). $this->_plugins[$type][$name][0][1]; |
2074 |
cvsjoko |
1.1 |
|
2075 |
joko |
1.3 |
} else { |
2076 |
|
|
/* function callback */ |
2077 |
|
|
return $this->_plugins[$type][$name][0]; |
2078 |
|
|
|
2079 |
|
|
} |
2080 |
|
|
} else { |
2081 |
|
|
/* plugin not loaded -> auto-loadable-plugin */ |
2082 |
|
|
return 'smarty_'.$type.'_'.$name; |
2083 |
|
|
|
2084 |
|
|
} |
2085 |
|
|
} |
2086 |
|
|
|
2087 |
|
|
/** |
2088 |
|
|
* load pre- and post-filters |
2089 |
|
|
*/ |
2090 |
cvsjoko |
1.1 |
function _load_filters() |
2091 |
|
|
{ |
2092 |
|
|
if (count($this->_plugins['prefilter']) > 0) { |
2093 |
|
|
foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { |
2094 |
|
|
if ($prefilter === false) { |
2095 |
|
|
unset($this->_plugins['prefilter'][$filter_name]); |
2096 |
joko |
1.3 |
$_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); |
2097 |
|
|
require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); |
2098 |
|
|
smarty_core_load_plugins($_params, $this); |
2099 |
cvsjoko |
1.1 |
} |
2100 |
|
|
} |
2101 |
|
|
} |
2102 |
|
|
if (count($this->_plugins['postfilter']) > 0) { |
2103 |
|
|
foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { |
2104 |
|
|
if ($postfilter === false) { |
2105 |
|
|
unset($this->_plugins['postfilter'][$filter_name]); |
2106 |
joko |
1.3 |
$_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); |
2107 |
|
|
require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); |
2108 |
|
|
smarty_core_load_plugins($_params, $this); |
2109 |
cvsjoko |
1.1 |
} |
2110 |
|
|
} |
2111 |
|
|
} |
2112 |
|
|
} |
2113 |
|
|
|
2114 |
|
|
|
2115 |
joko |
1.3 |
/** |
2116 |
|
|
* Quote subpattern references |
2117 |
|
|
* |
2118 |
|
|
* @param string $string |
2119 |
|
|
* @return string |
2120 |
|
|
*/ |
2121 |
|
|
function _quote_replace($string) |
2122 |
|
|
{ |
2123 |
|
|
return preg_replace('![\\$]\d!', '\\\\\\0', $string); |
2124 |
|
|
} |
2125 |
|
|
|
2126 |
|
|
/** |
2127 |
|
|
* display Smarty syntax error |
2128 |
|
|
* |
2129 |
|
|
* @param string $error_msg |
2130 |
|
|
* @param integer $error_type |
2131 |
|
|
* @param string $file |
2132 |
|
|
* @param integer $line |
2133 |
|
|
*/ |
2134 |
|
|
function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) |
2135 |
|
|
{ |
2136 |
|
|
$this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); |
2137 |
|
|
} |
2138 |
|
|
|
2139 |
|
|
|
2140 |
|
|
/** |
2141 |
|
|
* check if the compilation changes from cacheable to |
2142 |
|
|
* non-cacheable state with the beginning of the current |
2143 |
|
|
* plugin. return php-code to reflect the transition. |
2144 |
|
|
* @return string |
2145 |
|
|
*/ |
2146 |
|
|
function _push_cacheable_state($type, $name) { |
2147 |
|
|
$_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; |
2148 |
|
|
if ($_cacheable |
2149 |
|
|
|| 0<$this->_cacheable_state++) return ''; |
2150 |
|
|
if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); |
2151 |
|
|
$_ret = 'if ($this->caching) { echo \'{nocache:' |
2152 |
|
|
. $this->_cache_serial . '#' . $this->_nocache_count |
2153 |
|
|
. '}\';}'; |
2154 |
|
|
return $_ret; |
2155 |
|
|
} |
2156 |
|
|
|
2157 |
|
|
|
2158 |
|
|
/** |
2159 |
|
|
* check if the compilation changes from non-cacheable to |
2160 |
|
|
* cacheable state with the end of the current plugin return |
2161 |
|
|
* php-code to reflect the transition. |
2162 |
|
|
* @return string |
2163 |
|
|
*/ |
2164 |
|
|
function _pop_cacheable_state($type, $name) { |
2165 |
|
|
$_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; |
2166 |
|
|
if ($_cacheable |
2167 |
|
|
|| --$this->_cacheable_state>0) return ''; |
2168 |
|
|
return 'if ($this->caching) { echo \'{/nocache:' |
2169 |
|
|
. $this->_cache_serial . '#' . ($this->_nocache_count++) |
2170 |
|
|
. '}\';}'; |
2171 |
|
|
} |
2172 |
|
|
|
2173 |
|
|
|
2174 |
|
|
/** |
2175 |
|
|
* push opening tag-name, file-name and line-number on the tag-stack |
2176 |
|
|
* @param: string the opening tag's name |
2177 |
|
|
*/ |
2178 |
|
|
function _push_tag($open_tag) |
2179 |
|
|
{ |
2180 |
|
|
array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); |
2181 |
|
|
} |
2182 |
|
|
|
2183 |
|
|
/** |
2184 |
|
|
* pop closing tag-name |
2185 |
|
|
* raise an error if this stack-top doesn't match with the closing tag |
2186 |
|
|
* @param: string the closing tag's name |
2187 |
|
|
* @return: string the opening tag's name |
2188 |
|
|
*/ |
2189 |
|
|
function _pop_tag($close_tag) |
2190 |
|
|
{ |
2191 |
|
|
$message = ''; |
2192 |
|
|
if (count($this->_tag_stack)>0) { |
2193 |
|
|
list($_open_tag, $_line_no) = array_pop($this->_tag_stack); |
2194 |
|
|
if ($close_tag == $_open_tag) { |
2195 |
|
|
return $_open_tag; |
2196 |
|
|
} |
2197 |
|
|
if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { |
2198 |
|
|
return $this->_pop_tag($close_tag); |
2199 |
|
|
} |
2200 |
|
|
if ($close_tag == 'section' && $_open_tag == 'sectionelse') { |
2201 |
|
|
$this->_pop_tag($close_tag); |
2202 |
|
|
return $_open_tag; |
2203 |
|
|
} |
2204 |
|
|
if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { |
2205 |
|
|
$this->_pop_tag($close_tag); |
2206 |
|
|
return $_open_tag; |
2207 |
|
|
} |
2208 |
|
|
$message = " expected {/$_open_tag} (opened line $_line_no)."; |
2209 |
|
|
} |
2210 |
|
|
$this->_syntax_error("mismatched tag {/$close_tag}.$message", |
2211 |
|
|
E_USER_ERROR, __FILE__, __LINE__); |
2212 |
cvsjoko |
1.1 |
} |
2213 |
joko |
1.3 |
|
2214 |
cvsjoko |
1.1 |
} |
2215 |
joko |
1.3 |
|
2216 |
|
|
/** |
2217 |
|
|
* compare to values by their string length |
2218 |
|
|
* |
2219 |
|
|
* @access private |
2220 |
|
|
* @param string $a |
2221 |
|
|
* @param string $b |
2222 |
|
|
* @return 0|-1|1 |
2223 |
|
|
*/ |
2224 |
|
|
function _smarty_sort_length($a, $b) |
2225 |
|
|
{ |
2226 |
|
|
if($a == $b) |
2227 |
|
|
return 0; |
2228 |
|
|
|
2229 |
|
|
if(strlen($a) == strlen($b)) |
2230 |
|
|
return ($a > $b) ? -1 : 1; |
2231 |
|
|
|
2232 |
|
|
return (strlen($a) > strlen($b)) ? -1 : 1; |
2233 |
|
|
} |
2234 |
|
|
|
2235 |
cvsjoko |
1.1 |
|
2236 |
|
|
/* vim: set et: */ |
2237 |
|
|
|
2238 |
|
|
?> |