/[corp_html]/inc/Smarty.class.php
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /inc/Smarty.class.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations)
Sat Mar 17 15:46:05 2001 UTC (23 years, 1 month ago) by dpavlin
Branch: MAIN
Changes since 1.2: +4 -1 lines
nukleus for filesize var modifier

1 <?
2 /*
3 * Project: Smarty: the PHP compiling template engine
4 * File: Smarty.class.php
5 * Author: Monte Ohrt <monte@ispi.net>
6 * Andrei Zmievski <andrei@ispi.net>
7 *
8 * Version: 1.2.2
9 * Copyright: 2001 ispi of Lincoln, Inc.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 *
25 * You may contact the authors of Smarty by e-mail at:
26 * monte@ispi.net
27 * andrei@ispi.net
28 *
29 * Or, write to:
30 * Monte Ohrt
31 * CTO, ispi
32 * 237 S. 70th suite 220
33 * Lincoln, NE 68510
34 *
35 * The latest version of Smarty can be obtained from:
36 * http://www.phpinsider.com/
37 *
38 */
39
40 require("Smarty.addons.php");
41 require("Smarty.local.php");
42
43 class Smarty
44 {
45
46 // public vars
47 var $compile_check = true; // whether to check for compiling step or not:
48 // This is generally set to false once the
49 // application is entered into production and
50 // initially compiled. Leave set to true
51 // during development.
52
53 var $template_dir = "./templates"; // name of directory for templates
54 var $compile_dir = "./templates_c"; // name of directory for compiled templates
55
56
57 var $tpl_file_ext = ".tpl"; // template file extentions
58
59 var $allow_php = false; // whether or not to allow embedded php
60 // in the templates. By default, php tags
61 // are escaped.
62 var $left_delimiter = "{"; // template tag delimiters.
63 var $right_delimiter = "}";
64
65 var $config_dir = "./configs"; // directory where config files are located
66
67 var $custom_funcs = array( 'html_options' => 'smarty_func_html_options',
68 'html_select_date' => 'smarty_func_html_select_date',
69 //----- local
70 'img' => 'smarty_func_img',
71 'html_checkboxes' => 'smarty_func_html_checkboxes',
72 );
73
74 var $custom_mods = array( 'lower' => 'strtolower',
75 'upper' => 'strtoupper',
76 'capitalize' => 'ucwords',
77 'escape' => 'smarty_mod_escape',
78 'truncate' => 'smarty_mod_truncate',
79 'spacify' => 'smarty_mod_spacify',
80 'date_format' => 'smarty_mod_date_format',
81 'string_format' => 'smarty_mod_string_format',
82 'replace' => 'smarty_mod_replace',
83 'strip_tags' => 'smarty_mod_strip_tags',
84 'default' => 'smarty_mod_default',
85 //----- local
86 'filesize' => 'smarty_mod_filesize',
87 );
88 var $global_assign = array( 'SCRIPT_NAME'
89 );
90
91 // internal vars
92 var $_error_msg = false; // error messages
93 var $_tpl_vars = array();
94 var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part
95 var $_literal_blocks = array(); // keeps literal template blocks
96 var $_current_file = null; // the current template being compiled
97 var $_current_line_no = 1; // line number for error messages
98
99
100 /*======================================================================*\
101 Function: Smarty
102 Purpose: Constructor
103 \*======================================================================*/
104 function Smarty()
105 {
106 foreach ($this->global_assign as $var_name)
107 $this->assign($var_name, $GLOBALS[$var_name]);
108 }
109
110
111 /*======================================================================*\
112 Function: assign()
113 Purpose: assigns values to template variables
114 \*======================================================================*/
115
116 function assign($tpl_var, $value = NULL)
117 {
118 if (is_array($tpl_var)){
119 foreach ($tpl_var as $key => $val) {
120 if (!empty($key))
121 $this->_tpl_vars[$key] = $val;
122 }
123 } else {
124 if (!empty($tpl_var) && isset($value))
125 $this->_tpl_vars[$tpl_var] = $value;
126 }
127 }
128
129
130 /*======================================================================*\
131 Function: append
132 Purpose: appens values to template variables
133 \*======================================================================*/
134 function append($tpl_var, $value = NULL)
135 {
136 if (is_array($tpl_var)) {
137 foreach ($tpl_var as $key => $val) {
138 if (!empty($key)) {
139 if (!is_array($this->_tpl_vars[$key]))
140 settype($this->_tpl_vars[$key], 'array');
141 $this->_tpl_vars[$key][] = $val;
142 }
143 }
144 } else {
145 if (!empty($tpl_var) && isset($value)) {
146 if (!is_array($this->_tpl_vars[$tpl_var]))
147 settype($this->_tpl_vars[$tpl_var], 'array');
148 $this->_tpl_vars[$tpl_var][] = $value;
149 }
150 }
151 }
152
153
154 /*======================================================================*\
155 Function: clear_assign()
156 Purpose: clear the given assigned template variable.
157 \*======================================================================*/
158
159 function clear_assign($tpl_var)
160 {
161 unset($this->_tpl_vars[$tpl_var]);
162 }
163
164 /*======================================================================*\
165 Function: clear_all_assign()
166 Purpose: clear all the assigned template variables.
167 \*======================================================================*/
168
169 function clear_all_assign()
170 {
171 $this->_tpl_vars = array();
172 }
173
174
175 /*======================================================================*\
176 Function: get_template_vars
177 Purpose: Returns an array containing template variables
178 \*======================================================================*/
179 function &get_template_vars()
180 {
181 return $this->_tpl_vars;
182 }
183
184
185 /*======================================================================*\
186 Function: display()
187 Purpose: executes & displays the template results
188 \*======================================================================*/
189
190 function display($tpl_file)
191 {
192 // compile files
193 $this->_compile($this->template_dir);
194 //assemble compile directory path to file
195 $_compile_file = $this->compile_dir.'/'.$tpl_file.'.php';
196
197 extract($this->_tpl_vars);
198 include($_compile_file);
199 }
200
201 /*======================================================================*\
202 Function: fetch()
203 Purpose: executes & returns the template results
204 \*======================================================================*/
205
206 function fetch($tpl_file)
207 {
208 ob_start();
209 $this->display($tpl_file);
210 $results = ob_get_contents();
211 ob_end_clean();
212 return $results;
213 }
214
215 /*======================================================================*\
216 Function: compile()
217 Purpose: called to compile the templates
218 \*======================================================================*/
219
220 function _compile($tpl_dir)
221 {
222 if($this->compile_check)
223 {
224 if($this->_traverse_files($tpl_dir, 0))
225 return true;
226 else
227 return false;
228 }
229 else
230 return false;
231 }
232
233 /*======================================================================*\
234 Function: _traverse_files()
235 Purpose: traverse the template files & process each one
236 \*======================================================================*/
237
238 function _traverse_files($tpl_dir, $depth)
239 {
240 if(is_dir($tpl_dir)) {
241 if($tpl_dir)
242 $dir_handle = opendir($tpl_dir);
243
244 while($curr_file = readdir($dir_handle)) {
245 if ($curr_file == '.' || $curr_file == '..')
246 continue;
247
248 $filepath = $tpl_dir."/".$curr_file;
249 if(is_readable($filepath)) {
250 if(is_file($filepath) && preg_match('!' . preg_quote($this->tpl_file_ext, '!') . '$!', $curr_file)) {
251 if(!$this->_process_file($filepath))
252 return false;
253 } else if(is_dir($filepath)) {
254 if(!$this->_traverse_files($filepath, $depth + 1))
255 return false;
256 } else {
257 // invalid file type, skipping
258 $this->_set_error_msg("Invalid filetype for $filepath, skipping");
259 continue;
260 }
261 }
262 }
263 } else {
264 $this->_set_error_msg("Directory \"$tpl_dir\" does not exist or is not a directory.");
265 return false;
266 }
267
268 return true;
269 }
270
271 /*======================================================================*\
272 Function: _process_file()
273 Input: test template files for modifications
274 and execute the compilation for each
275 one requiring it.
276 \*======================================================================*/
277
278 function _process_file($filepath)
279 {
280 if(preg_match("/^(.+)\/([^\/]+)$/", $filepath, $match)) {
281 $tpl_file_dir = $match[1];
282 $tpl_file_name = $match[2] . ".php";
283
284 $compile_dir = preg_replace('!^' . preg_quote($this->template_dir, '!') . '!',
285 $this->compile_dir, $match[1]);
286
287 //create directory if none exists
288 if(!file_exists($compile_dir)) {
289 $compile_dir_parts = preg_split('!/+!', $compile_dir);
290 $new_dir = "";
291 foreach ($compile_dir_parts as $dir_part) {
292 $new_dir .= $dir_part."/";
293 if (!file_exists($new_dir) && !mkdir($new_dir, 0755)) {
294 $this->_set_error_msg("problem creating directory \"$compile_dir\"");
295 return false;
296 }
297 }
298 }
299
300 // compile the template file if none exists or has been modified
301 if (!file_exists($compile_dir."/".$tpl_file_name) ||
302 ($this->_modified_file($filepath, $compile_dir."/".$tpl_file_name))) {
303 if (!$this->_compile_file($filepath, $compile_dir."/".$tpl_file_name))
304 return false;
305 } else {
306 // no compilation needed
307 return true;
308 }
309 } else {
310 $this->_set_error_msg("problem matching \"$filepath.\"");
311 return false;
312 }
313
314 return true;
315 }
316
317 /*======================================================================*\
318 Function: _modified_file()
319 Input: return comparison of modification times of files
320 \*======================================================================*/
321
322 function _modified_file($filepath, $compilepath)
323 {
324 if(filemtime($filepath) >= filemtime($compilepath))
325 return true;
326 return false;
327 }
328
329 /*======================================================================*\
330 Function: _compile_file()
331 Input: compile a template file
332 \*======================================================================*/
333
334 function _compile_file($filepath, $compilepath)
335 {
336 if (!($template_contents = $this->_read_file($filepath)))
337 return false;
338
339 $this->_current_file = str_replace($this->template_dir . "/", "", $filepath);
340 $this->_current_line_no = 1;
341 $ldq = preg_quote($this->left_delimiter, '!');
342 $rdq = preg_quote($this->right_delimiter, '!');
343
344 /* Pull out the literal blocks. */
345 preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_contents, $match);
346 $this->_literal_blocks = $match[1];
347 $template_contents = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",
348 '{literal}', $template_contents);
349
350 /* Gather all template tags. */
351 preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_contents, $match);
352 $template_tags = $match[1];
353 /* Split content by template tags to obtain non-template content. */
354 $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_contents);
355 if(!$this->allow_php) {
356 /* Escape php tags. */
357 $text_blocks = preg_replace('!<\?([^?]*?)\?>!', '&lt;?$1?&gt;', $text_blocks);
358 }
359
360 /* Compile the template tags into PHP code. */
361 $compiled_tags = array();
362 for ($i = 0; $i < count($template_tags); $i++) {
363 $this->_current_line_no += substr_count($text_blocks[$i], "\n");
364 $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
365 $this->_current_line_no += substr_count($template_tags[$i], "\n");
366 }
367
368 $compiled_contents = "";
369
370 /* Interleave the compiled contents and text blocks to get the final result. */
371 for ($i = 0; $i < count($compiled_tags); $i++) {
372 $compiled_contents .= $text_blocks[$i].$compiled_tags[$i];
373 }
374 $compiled_contents .= $text_blocks[$i];
375
376 /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
377 if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_contents, $match)) {
378 $strip_tags = $match[0];
379 $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
380 $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
381 for ($i = 0; $i < count($strip_tags); $i++)
382 $compiled_contents = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
383 $strip_tags_modified[$i], $compiled_contents, 1);
384 }
385
386 if(!$this->_write_file($compilepath, $compiled_contents))
387 return false;
388
389 return true;
390 }
391
392 function _compile_tag($template_tag)
393 {
394 /* Matched comment. */
395 if ($template_tag{0} == '*' && $template_tag{strlen($template_tag)-1} == '*')
396 return "";
397
398 /* Split tag into two parts: command and the arguments. */
399 preg_match('/^(
400 (?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'\s]+))+
401 )
402 (?:\s+(.*))?
403 /xs', $template_tag, $match);
404 list(, $tag_command, $tag_args) = $match;
405
406 /* If the tag name matches a variable or section property definition,
407 we simply process it. */
408 if (preg_match('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) || // if a variable
409 preg_match('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) || // or a configuration variable
410 preg_match('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tag_command)) { // or a section property
411 settype($tag_command, 'array');
412 $this->_parse_vars_props($tag_command);
413 return "<?php print $tag_command[0]; ?>";
414 }
415
416 switch ($tag_command) {
417 case 'include':
418 return $this->_compile_include_tag($tag_args);
419
420 case 'if':
421 return $this->_compile_if_tag($tag_args);
422
423 case 'else':
424 return '<?php else: ?>';
425
426 case 'elseif':
427 return $this->_compile_if_tag($tag_args, true);
428
429 case '/if':
430 return '<?php endif; ?>';
431
432 case 'ldelim':
433 return $this->left_delimiter;
434
435 case 'rdelim':
436 return $this->right_delimiter;
437
438 case 'section':
439 array_push($this->_sectionelse_stack, false);
440 return $this->_compile_section_start($tag_args);
441
442 case 'sectionelse':
443 $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
444 return "<?php endfor; else: ?>";
445
446 case '/section':
447 if (array_pop($this->_sectionelse_stack))
448 return "<?php endif; ?>";
449 else
450 return "<?php endfor; endif; ?>";
451
452 case 'config_load':
453 return $this->_compile_config_load_tag($tag_args);
454
455 case 'strip':
456 case '/strip':
457 return $this->left_delimiter.$tag_command.$this->right_delimiter;
458
459 case 'literal':
460 list (,$literal_block) = each($this->_literal_blocks);
461 $this->_current_line_no += substr_count($literal_block, "\n");
462 return $literal_block;
463
464 case 'insert':
465 return $this->_compile_insert_tag($tag_args);
466
467 default:
468 if (isset($this->custom_funcs[$tag_command])) {
469 return $this->_compile_custom_tag($tag_command, $tag_args);
470 } else {
471 $this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING);
472 return "";
473 }
474 }
475 }
476
477
478 function _compile_custom_tag($tag_command, $tag_args)
479 {
480 $attrs = $this->_parse_attrs($tag_args);
481 $function = $this->custom_funcs[$tag_command];
482 foreach ($attrs as $arg_name => $arg_value) {
483 if (is_bool($arg_value))
484 $arg_value = $arg_value ? 'true' : 'false';
485 $arg_list[] = "'$arg_name' => $arg_value";
486 }
487
488 return "<?php $function(array(".implode(',', (array)$arg_list).")); ?>";
489 }
490
491
492 function _compile_insert_tag($tag_args)
493 {
494 $attrs = $this->_parse_attrs($tag_args);
495 $name = substr($attrs['name'], 1, -1);
496
497 if (empty($name)) {
498 $this->_syntax_error("missing insert name");
499 }
500
501 foreach ($attrs as $arg_name => $arg_value) {
502 if ($arg_name == 'name') continue;
503 if (is_bool($arg_value))
504 $arg_value = $arg_value ? 'true' : 'false';
505 $arg_list[] = "'$arg_name' => $arg_value";
506 }
507
508 return "<?php print insert_$name(array(".implode(',', (array)$arg_list).")); ?>";
509 }
510
511
512 function _compile_config_load_tag($tag_args)
513 {
514 $attrs = $this->_parse_attrs($tag_args);
515
516 if (empty($attrs['file'])) {
517 $this->_syntax_error("missing 'file' attribute in config_load tag");
518 }
519
520 $output = "<?php if (!class_exists('Config_File'))\n" .
521 " include_once 'Config_File.class.php';\n" .
522 "if (!is_object(\$_conf_obj) || get_class(\$_conf_obj) != 'config_file') {\n" .
523 " \$_conf_obj = new Config_File('".$this->config_dir."');\n" .
524 "}\n" .
525 "\$_config = array_merge((array)\$_config, \$_conf_obj->get(".$attrs['file']."));\n";
526
527 if (!empty($attrs['section']))
528 $output .= '$_config = array_merge((array)$_config, $_conf_obj->get('.$attrs['file'].', '.$attrs['section'].')); ';
529
530 $output .= '?>';
531
532 return $output;
533 }
534
535
536 function _compile_include_tag($tag_args)
537 {
538 $attrs = $this->_parse_attrs($tag_args);
539
540 if (empty($attrs['file'])) {
541 $this->_syntax_error("missing 'file' attribute in include tag");
542 } else
543 $attrs['file'] = $this->_dequote($attrs['file']);
544
545 if (count($attrs) > 1) {
546 $include_func_name = uniqid("_include_");
547 $include_file_name = $this->compile_dir.'/'.$attrs['file'];
548
549 foreach ($attrs as $arg_name => $arg_value) {
550 if ($arg_name == 'file') continue;
551 if (is_bool($arg_value))
552 $arg_value = $arg_value ? 'true' : 'false';
553 $arg_list[] = "'$arg_name' => $arg_value";
554 }
555
556 return "<?php " .
557 "function $include_func_name(\$file_name, \$def_vars, \$include_vars)\n" .
558 "{\n" .
559 " extract(\$def_vars);\n" .
560 " extract(\$include_vars);\n" .
561 " include \"\$file_name.php\";\n" .
562 "}\n" .
563 "$include_func_name(\"$include_file_name\", get_defined_vars(), array(".implode(',', (array)$arg_list)."));\n?>\n";
564 } else
565 return '<?php include "'.$this->compile_dir.'/'.$attrs['file'].'.php"; ?>';
566 }
567
568 function _compile_section_start($tag_args)
569 {
570 $attrs = $this->_parse_attrs($tag_args);
571
572 $output = "<?php ";
573 $section_name = $attrs['name'];
574 if (empty($section_name)) {
575 $this->_syntax_error("missing section name");
576 }
577
578 $output .= "unset(\$_sections[$section_name]);\n";
579 $section_props = "\$_sections[$section_name]['properties']";
580
581 foreach ($attrs as $attr_name => $attr_value) {
582 switch ($attr_name) {
583 case 'loop':
584 $output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : $attr_value;\n";
585 break;
586
587 case 'show':
588 if (is_bool($attr_value))
589 $attr_value = $attr_value ? 'true' : 'false';
590 $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
591 break;
592
593 default:
594 $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
595 break;
596 }
597 }
598
599 if (isset($attrs['loop'])) {
600 $loop_check_code = "{$section_props}['loop'] > 0 && ";
601 } else {
602 $output .= "{$section_props}['loop'] = 1; #-fix- \n";
603 }
604
605 if (isset($attrs['show'])) {
606 $show_check_code = "{$section_props}['show'] && ";
607 } else {
608 $output .= "{$section_props}['show'] = {$section_props}['loop'] > 0;\n";
609 }
610
611 $output .= "if ($loop_check_code $show_check_code true): ";
612
613 $output .= "
614 for ({$section_props}['index'] = 0;
615 {$section_props}['index'] < {$section_props}['loop'];
616 {$section_props}['index']++):\n";
617 $output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n";
618
619 $output .= "?>\n";
620
621 return $output;
622 }
623
624 function _compile_if_tag($tag_args, $elseif = false)
625 {
626 /* Tokenize args for 'if' tag. */
627 preg_match_all('/(?:
628 "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | # match all double quoted strings allowed escaped double quotes
629 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | # match all single quoted strings allowed escaped single quotes
630 [()] | # match parentheses
631 [^"\'\s()]+ # match any other token that is not any of the above
632 )/x', $tag_args, $match);
633 $tokens = $match[0];
634
635 $this->_parse_vars_props($tokens);
636
637 $is_arg_stack = array();
638
639 for ($i = 0; $i < count($tokens); $i++) {
640 $token = &$tokens[$i];
641 switch ($token) {
642 case 'eq':
643 $token = '==';
644 break;
645
646 case 'ne':
647 case 'neq':
648 $token = '!=';
649 break;
650
651 case 'lt':
652 $token = '<';
653 break;
654
655 case 'le':
656 case 'lte':
657 $token = '<=';
658 break;
659
660 case 'gt':
661 $token = '>';
662 break;
663
664 case 'ge':
665 case 'gte':
666 $token = '>=';
667 break;
668
669 case 'and':
670 $token = '&&';
671 break;
672
673 case 'or':
674 $token = '||';
675 break;
676
677 case 'not':
678 $token = '!';
679 break;
680
681 case 'mod':
682 $token = '%';
683 break;
684
685 case '(':
686 array_push($is_arg_stack, $i);
687 break;
688
689 case 'is':
690 /* If last token was a ')', we operate on the parenthesized
691 expression. The start of the expression is on the stack.
692 Otherwise, we operate on the last encountered token. */
693 if ($tokens[$i-1] == ')')
694 $is_arg_start = array_pop($is_arg_stack);
695 else
696 $is_arg_start = $i-1;
697 /* Construct the argument for 'is' expression, so it knows
698 what to operate on. */
699 $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
700
701 /* Pass all tokens from next one until the end to the
702 'is' expression parsing function. The function will
703 return modified tokens, where the first one is the result
704 of the 'is' expression and the rest are the tokens it
705 didn't touch. */
706 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
707
708 /* Replace the old tokens with the new ones. */
709 array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
710
711 /* Adjust argument start so that it won't change from the
712 current position for the next iteration. */
713 $i = $is_arg_start;
714 break;
715 }
716 }
717
718 if ($elseif)
719 return '<?php elseif ('.implode(' ', $tokens).'): ?>';
720 else
721 return '<?php if ('.implode(' ', $tokens).'): ?>';
722 }
723
724 function _parse_is_expr($is_arg, $tokens)
725 {
726 $expr_end = 0;
727
728 if (($first_token = array_shift($tokens)) == 'not') {
729 $negate_expr = true;
730 $expr_type = array_shift($tokens);
731 } else
732 $expr_type = $first_token;
733
734 switch ($expr_type) {
735 case 'even':
736 if ($tokens[$expr_end] == 'by') {
737 $expr_end++;
738 $expr_arg = $tokens[$expr_end++];
739 $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
740 }
741 else
742 $expr = "!($is_arg % 2)";
743 break;
744
745 case 'odd':
746 if ($tokens[$expr_end] == 'by') {
747 $expr_end++;
748 $expr_arg = $tokens[$expr_end++];
749 $expr = "(($is_arg / $expr_arg) % $expr_arg)";
750 }
751 else
752 $expr = "($is_arg % 2)";
753 break;
754
755 case 'div':
756 if ($tokens[$expr_end] == 'by') {
757 $expr_end++;
758 $expr_arg = $tokens[$expr_end++];
759 $expr = "!($is_arg % $expr_arg)";
760 } else {
761 $this->_syntax_error("expecting 'by' after 'div'");
762 }
763 break;
764
765 default:
766 $this->_syntax_error("unknown 'is' expression - '$expr_type'");
767 break;
768 }
769
770 if ($negate_expr) {
771 $expr = "!($expr)";
772 }
773
774 array_splice($tokens, 0, $expr_end, $expr);
775
776 return $tokens;
777 }
778
779 function _parse_attrs($tag_args)
780 {
781 /* Tokenize tag attributes. */
782 preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
783 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'=\s]+)
784 )+ |
785 [=]
786 /x', $tag_args, $match);
787 $tokens = $match[0];
788 $var_delims = array('$', '#', '%');
789
790 $attrs = array();
791 /* Parse state:
792 0 - expecting attr name
793 1 - expecting '=' or another attr name
794 2 - expecting attr value (not '=') */
795 $state = 0;
796
797 foreach ($tokens as $token) {
798 switch ($state) {
799 case 0:
800 /* If the token is a valid identifier, we set attribute name
801 and go to state 1. */
802 if (preg_match('!\w+!', $token)) {
803 $attr_name = $token;
804 $state = 1;
805 } else
806 $this->_syntax_error("invalid attribute name - '$token'");
807 break;
808
809 case 1:
810 /* If the token is a valid identifier, the previously set
811 attribute name does not need an argument. We put it in
812 the attrs array, set the new attribute name to the
813 current token and don't switch state.
814
815 If the token is '=', then we go to state 2. */
816 if ($token == '=') {
817 $state = 2;
818 } else
819 $this->_syntax_error("expecting '=' after attribute name");
820 break;
821
822 case 2:
823 /* If token is not '=', we set the attribute value and go to
824 state 0. */
825 if ($token != '=') {
826 /* We booleanize the token if it's a non-quoted possible
827 boolean value. */
828 if (preg_match('!^(on|yes|true)$!', $token))
829 $token = true;
830 else if (preg_match('!^(off|no|false)$!', $token))
831 $token = false;
832 /* If the token is not variable (doesn't start with
833 '$', '#', or '%') and not enclosed in single or
834 double quotes we single-quote it. */
835 else if (!in_array($token{0}, $var_delims) &&
836 !(($token{0} == '"' || $token[0] == "'") &&
837 $token{strlen($token)-1} == $token{0}))
838 $token = "'".$token."'";
839
840 $attrs[$attr_name] = $token;
841 $state = 0;
842 } else
843 $this->_syntax_error("'=' cannot be an attribute value");
844 break;
845 }
846 }
847
848 $this->_parse_vars_props($attrs);
849
850 return $attrs;
851 }
852
853 function _preg_grep($pattern, $array)
854 {
855 $result = array();
856
857 foreach ($array as $key => $entry) {
858 if (preg_match($pattern, $entry))
859 $result[$key] = $entry;
860 }
861
862 return $result;
863 }
864
865 function _parse_vars_props(&$tokens)
866 {
867 /* preg_grep() was fixed to return keys properly in 4.0.4 and later. To
868 allow people to use older versions of PHP we emulate preg_grep() and
869 use the version check to see what function to call. */
870 if (strnatcmp(PHP_VERSION, '4.0.4') >= 0) {
871 $var_exprs = preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
872 $conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
873 $sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
874 } else {
875 $var_exprs = $this->_preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
876 $conf_var_exprs = $this->_preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
877 $sect_prop_exprs = $this->_preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
878 }
879
880 if (count($var_exprs)) {
881 foreach ($var_exprs as $expr_index => $var_expr) {
882 $tokens[$expr_index] = $this->_parse_var($var_expr);
883 }
884 }
885
886 if (count($conf_var_exprs)) {
887 foreach ($conf_var_exprs as $expr_index => $var_expr) {
888 $tokens[$expr_index] = $this->_parse_conf_var($var_expr);
889 }
890 }
891
892 if (count($sect_prop_exprs)) {
893 foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
894 $tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
895 }
896 }
897 }
898
899 function _parse_var($var_expr)
900 {
901 $modifiers = explode('|', substr($var_expr, 1));
902
903 $sections = explode('/', array_shift($modifiers));
904 $props = explode('.', array_pop($sections));
905 $var_name = array_shift($props);
906
907 $output = "\$$var_name";
908
909 foreach ($sections as $section) {
910 $output .= "[\$_sections['$section']['properties']['index']]";
911 }
912 foreach ($props as $prop) {
913 $output .= "['$prop']";
914 }
915
916 $this->_parse_modifiers($output, $modifiers);
917
918 return $output;
919 }
920
921 function _parse_conf_var($conf_var_expr)
922 {
923 $modifiers = explode('|', $conf_var_expr);
924
925 $var_name = substr(array_shift($modifiers), 1, -1);
926
927 $output = "\$_config['$var_name']";
928
929 $this->_parse_modifiers($output, $modifiers);
930
931 return $output;
932 }
933
934 function _parse_section_prop($section_prop_expr)
935 {
936 $modifiers = explode('|', $section_prop_expr);
937
938 preg_match('!%(\w+)\.(\w+)%!', array_shift($modifiers), $match);
939 $section_name = $match[1];
940 $prop_name = $match[2];
941
942 $output = "\$_sections['$section_name']['properties']['$prop_name']";
943
944 $this->_parse_modifiers($output, $modifiers);
945
946 return $output;
947 }
948
949 function _parse_modifiers(&$output, $modifiers)
950 {
951 foreach ($modifiers as $modifier) {
952 $modifier = explode(':', $modifier);
953 $modifier_name = array_shift($modifier);
954
955 if ($modifier_name{0} == '@') {
956 $map_array = 'false';
957 $modifier_name = substr($modifier_name, 1);
958 } else
959 $map_array = 'true';
960
961 /*
962 * First we lookup the modifier function name in the registered
963 * modifiers table.
964 */
965 $mod_func_name = $this->custom_mods[$modifier_name];
966
967 /*
968 * If we don't find that modifier there, we assume it's just a PHP
969 * function name.
970 */
971 if (!isset($mod_func_name))
972 $mod_func_name = $modifier_name;
973
974 $this->_parse_vars_props($modifier);
975
976 if (count($modifier) > 0)
977 $modifier_args = ', '.implode(', ', $modifier);
978 else
979 $modifier_args = '';
980
981 $output = "_smarty_mod_handler('$mod_func_name', $map_array, $output$modifier_args)";
982 }
983 }
984
985
986 /*======================================================================*\
987 Function: _dequote
988 Purpose: Remove starting and ending quotes from the string
989 \*======================================================================*/
990 function _dequote($string)
991 {
992 if (($string{0} == "'" || $string{0} == '"') &&
993 $string{strlen($string)-1} == $string{0})
994 return substr($string, 1, -1);
995 }
996
997
998 /*======================================================================*\
999 Function: _read_file()
1000 Purpose: read in a file
1001 \*======================================================================*/
1002
1003 function _read_file($filename)
1004 {
1005 if(!($fd = fopen($filename, 'r'))) {
1006 $this->_set_error_msg("problem reading '$filename.'");
1007 return false;
1008 }
1009 $contents = fread($fd, filesize($filename));
1010 fclose($fd);
1011 return $contents;
1012 }
1013
1014 /*======================================================================*\
1015 Function: _write_file()
1016 Purpose: write out a file
1017 \*======================================================================*/
1018
1019 function _write_file($filename,$contents)
1020 {
1021 if(!($fd = fopen($filename, 'w'))) {
1022 $this->_set_error_msg("problem writing '$filename.'");
1023 return false;
1024 }
1025 fwrite($fd, $contents);
1026 fclose($fd);
1027 return true;
1028 }
1029
1030 /*======================================================================*\
1031 Function: _set_error_msg()
1032 Purpose: set the error message
1033 \*======================================================================*/
1034
1035 function _set_error_msg($error_msg)
1036 {
1037 $this->_error_msg="smarty error: $error_msg";
1038 return true;
1039 }
1040
1041 /*======================================================================*\
1042 Function: _syntax_error
1043 Purpose: display Smarty syntax error
1044 \*======================================================================*/
1045 function _syntax_error($error_msg, $error_type = E_USER_ERROR)
1046 {
1047 trigger_error("Smarty: [in " . $this->_current_file . " line " .
1048 $this->_current_line_no . "]: syntax error: $error_msg", $error_type);
1049 }
1050 }
1051
1052 ?>

  ViewVC Help
Powered by ViewVC 1.1.26