Files
smarty/libs/Smarty.class.php

1132 lines
33 KiB
PHP
Raw Normal View History

2000-08-08 17:05:38 +00:00
<?
/*
* Project: Smarty: the PHP compiling template engine
2000-08-08 17:05:38 +00:00
* File: Smarty.class.php
* Author: Monte Ohrt <monte@ispi.net>
* Andrei Zmievski <andrei@ispi.net>
2000-11-17 21:47:41 +00:00
*
2001-01-30 21:57:01 +00:00
* Version: 1.2.2
2001-01-25 23:07:36 +00:00
* Copyright: 2001 ispi of Lincoln, Inc.
2000-11-20 23:08:17 +00:00
*
2001-01-18 20:41:43 +00:00
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* You may contact the authors of Smarty by e-mail at:
* monte@ispi.net
* andrei@ispi.net
*
* Or, write to:
* Monte Ohrt
* CTO, ispi
* 237 S. 70th suite 220
* Lincoln, NE 68510
*
* The latest version of Smarty can be obtained from:
* http://www.phpinsider.com/
2000-08-08 17:05:38 +00:00
*
*/
2000-11-17 21:47:41 +00:00
require("Smarty.addons.php");
2000-08-08 17:05:38 +00:00
class Smarty
{
// public vars
var $compile_check = true; // whether to check for compiling step or not:
// This is generally set to false once the
// application is entered into production and
// initially compiled. Leave set to true
// during development. true/false
var $compile_force = false; // force templates to compile every time.
// overrides compile_check. true/false
var $allow_url_compile = true; // allow forced recompile from URL ?compile_force=1
// NOTE: all cache directives override
// compiling directives. If a cached version
// is available, that will be used regardless
// of compile settings.
var $cache_engine = true; // whether to use caching or not. true/false
2001-01-30 22:08:02 +00:00
var $cache_expire = 3600; // number of seconds cached content will expire.
// 0 = never expires. default is one hour (3600)
var $cache_force = false; // force caches to expire every time. true/false
var $allow_url_cache = true; // allow forced cache expire from URL ?cache_force=1
2000-11-15 17:08:52 +00:00
2001-01-12 19:24:31 +00:00
var $template_dir = "./templates"; // name of directory for templates
var $compile_dir = "./templates_c"; // name of directory for compiled templates
var $cache_dir = "./cache"; // name of directory for template cache
2000-08-08 17:05:38 +00:00
var $tpl_file_ext = ".tpl"; // template file extentions
var $allow_php = false; // whether or not to allow embedded php
// in the templates. By default, php tags
// are escaped. true/false
2000-08-08 17:05:38 +00:00
var $left_delimiter = "{"; // template tag delimiters.
var $right_delimiter = "}";
2000-11-27 17:39:40 +00:00
var $config_dir = "./configs"; // directory where config files are located
2000-11-20 20:06:06 +00:00
2001-01-02 14:51:02 +00:00
var $custom_funcs = array( 'html_options' => 'smarty_func_html_options',
2000-12-04 21:48:51 +00:00
'html_select_date' => 'smarty_func_html_select_date'
2000-11-21 20:29:55 +00:00
);
2000-08-08 17:05:38 +00:00
2001-01-12 16:05:26 +00:00
var $custom_mods = array( 'lower' => 'strtolower',
2000-11-20 22:31:38 +00:00
'upper' => 'strtoupper',
'capitalize' => 'ucwords',
'escape' => 'smarty_mod_escape',
'truncate' => 'smarty_mod_truncate',
2000-12-04 21:48:51 +00:00
'spacify' => 'smarty_mod_spacify',
'date_format' => 'smarty_mod_date_format',
2000-12-18 21:40:21 +00:00
'string_format' => 'smarty_mod_string_format',
2000-12-27 19:58:05 +00:00
'replace' => 'smarty_mod_replace',
2001-01-18 21:09:49 +00:00
'strip_tags' => 'smarty_mod_strip_tags',
'default' => 'smarty_mod_default'
2000-11-17 21:47:41 +00:00
);
2000-11-22 16:23:19 +00:00
var $global_assign = array( 'SCRIPT_NAME'
);
2001-01-02 14:51:02 +00:00
2000-08-08 17:05:38 +00:00
// internal vars
var $_error_msg = false; // error messages. true/false
2000-08-08 17:05:38 +00:00
var $_tpl_vars = array();
2000-11-20 03:20:55 +00:00
var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part
2000-11-27 17:39:40 +00:00
var $_literal_blocks = array(); // keeps literal template blocks
2001-01-26 16:11:21 +00:00
var $_current_file = null; // the current template being compiled
var $_current_line_no = 1; // line number for error messages
2000-08-08 17:05:38 +00:00
2000-11-22 16:23:19 +00:00
/*======================================================================*\
Function: Smarty
Purpose: Constructor
\*======================================================================*/
function Smarty()
{
foreach ($this->global_assign as $var_name)
$this->assign($var_name, $GLOBALS[$var_name]);
}
2000-08-08 17:05:38 +00:00
/*======================================================================*\
Function: assign()
2000-11-21 15:21:16 +00:00
Purpose: assigns values to template variables
2000-08-08 17:05:38 +00:00
\*======================================================================*/
function assign($tpl_var, $value = NULL)
{
2000-11-20 20:06:06 +00:00
if (is_array($tpl_var)){
foreach ($tpl_var as $key => $val) {
if (!empty($key))
$this->_tpl_vars[$key] = $val;
2000-08-08 17:05:38 +00:00
}
2000-11-20 20:06:06 +00:00
} else {
if (!empty($tpl_var) && isset($value))
$this->_tpl_vars[$tpl_var] = $value;
2000-08-08 17:05:38 +00:00
}
}
2000-11-21 15:21:16 +00:00
/*======================================================================*\
Function: append
Purpose: appens values to template variables
\*======================================================================*/
function append($tpl_var, $value = NULL)
{
if (is_array($tpl_var)) {
foreach ($tpl_var as $key => $val) {
if (!empty($key)) {
if (!is_array($this->_tpl_vars[$key]))
settype($this->_tpl_vars[$key], 'array');
$this->_tpl_vars[$key][] = $val;
}
}
} else {
if (!empty($tpl_var) && isset($value)) {
if (!is_array($this->_tpl_vars[$tpl_var]))
settype($this->_tpl_vars[$tpl_var], 'array');
$this->_tpl_vars[$tpl_var][] = $value;
}
}
}
2000-08-08 17:05:38 +00:00
/*======================================================================*\
Function: clear_assign()
Purpose: clear the given assigned template variable.
\*======================================================================*/
function clear_assign($tpl_var)
{
unset($this->_tpl_vars[$tpl_var]);
}
/*======================================================================*\
Function: clear_all_assign()
Purpose: clear all the assigned template variables.
\*======================================================================*/
function clear_all_assign()
{
2000-11-21 15:21:16 +00:00
$this->_tpl_vars = array();
2000-08-08 17:05:38 +00:00
}
2000-11-21 15:21:16 +00:00
/*======================================================================*\
Function: get_template_vars
Purpose: Returns an array containing template variables
\*======================================================================*/
function &get_template_vars()
{
return $this->_tpl_vars;
}
2000-08-08 17:05:38 +00:00
/*======================================================================*\
2000-11-20 20:06:06 +00:00
Function: display()
Purpose: executes & displays the template results
2000-08-08 17:05:38 +00:00
\*======================================================================*/
2000-11-20 20:06:06 +00:00
function display($tpl_file)
2000-08-08 17:05:38 +00:00
{
print $this->fetch($tpl_file);
2000-12-18 15:34:29 +00:00
}
2000-08-08 17:05:38 +00:00
/*======================================================================*\
Function: fetch()
Purpose: executes & returns the template results
\*======================================================================*/
function fetch($tpl_file)
{
global $HTTP_GET_VARS,$PHP_SELF;
if($this->cache_engine)
{
if($this->allow_url_cache && $HTTP_GET_VARS["cache_force"])
$this->cache_force = true;
// cache id = template path + the invoked script
$cache_file = $this->cache_dir."/".urlencode($tpl_file."@".$PHP_SELF).".che";
if(!$this->cache_force &&
(file_exists($cache_file) &&
($this->cache_expire == 0 ||
(mktime() - filectime($cache_file) <= $this->cache_expire)
)))
{
$results = $this->_read_file($cache_file);
$results = $this->_process_cached_inserts($results);
return $results;
}
}
if($this->allow_url_compile && $HTTP_GET_VARS["compile_force"])
$this->compile_force = true;
2000-08-08 17:05:38 +00:00
ob_start();
// compile files
$this->_compile($this->template_dir);
//assemble compile directory path to file
$_compile_file = $this->compile_dir."/".$tpl_file.".php";
extract($this->_tpl_vars);
include($_compile_file);
$results = ob_get_contents();
2000-08-08 17:05:38 +00:00
ob_end_clean();
if($this->cache_engine)
{
$this->_write_file($cache_file,$results);
$results = $this->_process_cached_inserts($results);
}
2000-08-08 17:05:38 +00:00
return $results;
}
/*======================================================================*\
Function: compile()
Purpose: called to compile the templates
\*======================================================================*/
function _compile($tpl_dir)
{
if($this->compile_check || $this->compile_force)
2000-08-08 17:05:38 +00:00
{
2001-01-12 19:24:31 +00:00
if($this->_traverse_files($tpl_dir, 0))
2000-08-08 17:05:38 +00:00
return true;
else
return false;
}
else
return false;
}
2000-08-08 17:05:38 +00:00
/*======================================================================*\
Function: _traverse_files()
Purpose: traverse the template files & process each one
\*======================================================================*/
2001-01-12 19:24:31 +00:00
function _traverse_files($tpl_dir, $depth)
2000-08-08 17:05:38 +00:00
{
2001-01-12 19:24:31 +00:00
if(is_dir($tpl_dir)) {
2000-08-08 17:05:38 +00:00
if($tpl_dir)
2001-01-12 16:05:26 +00:00
$dir_handle = opendir($tpl_dir);
2000-08-08 17:05:38 +00:00
2001-01-12 19:24:31 +00:00
while($curr_file = readdir($dir_handle)) {
2001-01-12 16:05:26 +00:00
if ($curr_file == '.' || $curr_file == '..')
2000-08-08 17:05:38 +00:00
continue;
2001-01-12 16:05:26 +00:00
2000-08-08 17:05:38 +00:00
$filepath = $tpl_dir."/".$curr_file;
2001-01-12 19:24:31 +00:00
if(is_readable($filepath)) {
if(is_file($filepath) && substr($curr_file,-strlen($this->tpl_file_ext)) == $this->tpl_file_ext) {
2000-08-08 17:05:38 +00:00
if(!$this->_process_file($filepath))
2001-01-12 16:05:26 +00:00
return false;
2001-01-12 19:24:31 +00:00
} else if(is_dir($filepath)) {
if(!$this->_traverse_files($filepath, $depth + 1))
2000-08-08 17:05:38 +00:00
return false;
2001-01-12 19:24:31 +00:00
} else {
2000-08-08 17:05:38 +00:00
// invalid file type, skipping
2000-11-20 22:31:38 +00:00
$this->_set_error_msg("Invalid filetype for $filepath, skipping");
2000-08-08 17:05:38 +00:00
continue;
}
}
}
2001-01-12 19:24:31 +00:00
} else {
2000-11-20 22:31:38 +00:00
$this->_set_error_msg("Directory \"$tpl_dir\" does not exist or is not a directory.");
2000-08-08 17:05:38 +00:00
return false;
}
2001-01-12 19:24:31 +00:00
2000-08-08 17:05:38 +00:00
return true;
}
/*======================================================================*\
Function: _process_file()
Input: test template files for modifications
and execute the compilation for each
one requiring it.
\*======================================================================*/
function _process_file($filepath)
{
2001-01-12 19:24:31 +00:00
if(preg_match("/^(.+)\/([^\/]+)$/", $filepath, $match)) {
2000-08-08 17:05:38 +00:00
$tpl_file_dir = $match[1];
2001-01-19 14:36:52 +00:00
$tpl_file_name = $match[2] . ".php";
2000-08-08 17:05:38 +00:00
2001-01-30 18:05:26 +00:00
$compile_dir = preg_replace('!^' . preg_quote($this->template_dir, '!') . '!',
$this->compile_dir, $match[1]);
2000-08-08 17:05:38 +00:00
//create directory if none exists
2001-01-30 18:05:26 +00:00
if(!file_exists($compile_dir)) {
$compile_dir_parts = preg_split('!/+!', $compile_dir);
2000-11-27 17:39:40 +00:00
$new_dir = "";
foreach ($compile_dir_parts as $dir_part) {
$new_dir .= $dir_part."/";
if (!file_exists($new_dir) && !mkdir($new_dir, 0755)) {
2001-01-30 18:05:26 +00:00
$this->_set_error_msg("problem creating directory \"$compile_dir\"");
2000-11-27 17:39:40 +00:00
return false;
}
2000-08-08 17:05:38 +00:00
}
2000-11-27 17:39:40 +00:00
}
// compile the template file if none exists or has been modified or compile_force
if (!file_exists($compile_dir."/".$tpl_file_name) || $this->compile_force ||
2001-01-30 18:05:26 +00:00
($this->_modified_file($filepath, $compile_dir."/".$tpl_file_name))) {
if (!$this->_compile_file($filepath, $compile_dir."/".$tpl_file_name))
2000-08-08 17:05:38 +00:00
return false;
2001-01-12 19:24:31 +00:00
} else {
2000-08-08 17:05:38 +00:00
// no compilation needed
return true;
}
2001-01-12 19:24:31 +00:00
} else {
2000-11-20 22:31:38 +00:00
$this->_set_error_msg("problem matching \"$filepath.\"");
2000-08-08 17:05:38 +00:00
return false;
}
2001-01-12 19:24:31 +00:00
2000-08-08 17:05:38 +00:00
return true;
}
/*======================================================================*\
Function: _modified_file()
Input: return comparison of modification times of files
\*======================================================================*/
2001-01-12 19:24:31 +00:00
function _modified_file($filepath, $compilepath)
2000-08-08 17:05:38 +00:00
{
if(filemtime($filepath) >= filemtime($compilepath))
return true;
return false;
}
/*======================================================================*\
Function: _compile_file()
Input: compile a template file
\*======================================================================*/
2001-01-12 20:48:43 +00:00
function _compile_file($filepath, $compilepath)
2000-08-08 17:05:38 +00:00
{
2001-01-26 16:11:21 +00:00
if (!($template_contents = $this->_read_file($filepath)))
2000-08-08 17:05:38 +00:00
return false;
2001-01-26 16:11:21 +00:00
$this->_current_file = str_replace($this->template_dir . "/", "", $filepath);
$this->_current_line_no = 1;
$ldq = preg_quote($this->left_delimiter, '!');
$rdq = preg_quote($this->right_delimiter, '!');
2000-08-08 21:10:12 +00:00
2000-11-27 17:39:40 +00:00
/* Pull out the literal blocks. */
preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_contents, $match);
$this->_literal_blocks = $match[1];
$template_contents = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",
'{literal}', $template_contents);
2000-11-17 21:47:41 +00:00
/* Gather all template tags. */
2001-01-12 19:24:31 +00:00
preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_contents, $match);
2000-11-17 21:47:41 +00:00
$template_tags = $match[1];
/* Split content by template tags to obtain non-template content. */
2001-01-12 19:24:31 +00:00
$text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_contents);
2000-11-21 20:29:55 +00:00
if(!$this->allow_php) {
/* Escape php tags. */
$text_blocks = preg_replace('!<\?([^?]*?)\?>!', '&lt;?$1?&gt;', $text_blocks);
}
2000-11-17 21:47:41 +00:00
2001-01-12 19:24:31 +00:00
/* Compile the template tags into PHP code. */
2000-11-17 21:47:41 +00:00
$compiled_tags = array();
2001-01-26 16:11:21 +00:00
for ($i = 0; $i < count($template_tags); $i++) {
$this->_current_line_no += substr_count($text_blocks[$i], "\n");
$compiled_tags[] = $this->_compile_tag($template_tags[$i]);
$this->_current_line_no += substr_count($template_tags[$i], "\n");
}
2000-08-08 17:05:38 +00:00
$compiled_contents = "";
2001-01-26 16:11:21 +00:00
/* Interleave the compiled contents and text blocks to get the final result. */
2000-11-17 21:47:41 +00:00
for ($i = 0; $i < count($compiled_tags); $i++) {
$compiled_contents .= $text_blocks[$i].$compiled_tags[$i];
}
$compiled_contents .= $text_blocks[$i];
2000-08-08 17:05:38 +00:00
2000-11-20 23:08:17 +00:00
/* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
2000-11-21 15:21:16 +00:00
if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_contents, $match)) {
$strip_tags = $match[0];
2001-01-12 19:24:31 +00:00
$strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
2001-01-04 21:39:51 +00:00
$strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
2000-11-21 15:21:16 +00:00
for ($i = 0; $i < count($strip_tags); $i++)
$compiled_contents = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
$strip_tags_modified[$i], $compiled_contents, 1);
}
2000-11-20 23:08:17 +00:00
2001-01-19 14:36:52 +00:00
if(!$this->_write_file($compilepath, $compiled_contents))
2000-11-17 21:47:41 +00:00
return false;
return true;
}
function _process_cached_inserts($results)
{
preg_match_all("/\{\{\{insert_cache name=([^ ]+) (.*)\}\}\}/Uis",$results,$match);
$fulltags = $match[0];
$names = $match[1];
$args = $match[2];
for($curr_tag = 0; $curr_tag < count($fulltags); $curr_tag++)
{
$attrs = $this->_parse_attrs($args[$curr_tag]);
$name = substr($attrs['name'], 1, -1);
if (empty($names[$curr_tag])) {
$this->_syntax_error("missing insert name");
}
foreach ($attrs as $arg_name => $arg_value) {
if ($arg_name == 'name') continue;
if (is_bool($arg_value))
$arg_value = $arg_value ? 'true' : 'false';
$arg_list[] = "'$arg_name' => $arg_value";
}
$evalcode = "print insert_".$names[$curr_tag]."(array(".implode(',', (array)$arg_list)."));";
ob_start();
eval($evalcode);
$replace = ob_get_contents();
ob_end_clean();
$results = str_replace($fulltags[$curr_tag],$replace,$results);
}
return $results;
}
2000-11-17 21:47:41 +00:00
function _compile_tag($template_tag)
{
/* Matched comment. */
2001-01-11 19:57:07 +00:00
if ($template_tag{0} == '*' && $template_tag{strlen($template_tag)-1} == '*')
2000-11-17 21:47:41 +00:00
return "";
2000-11-17 23:14:51 +00:00
/* Split tag into two parts: command and the arguments. */
2000-12-04 22:30:15 +00:00
preg_match('/^(
2001-01-11 19:57:07 +00:00
(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'\s]+))+
2000-12-04 22:30:15 +00:00
)
(?:\s+(.*))?
2001-01-11 19:57:07 +00:00
/xs', $template_tag, $match);
2000-12-04 22:30:15 +00:00
list(, $tag_command, $tag_args) = $match;
2000-11-17 23:14:51 +00:00
/* If the tag name matches a variable or section property definition,
we simply process it. */
2001-01-26 15:15:55 +00:00
if (preg_match('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) || // if a variable
2000-12-07 22:47:01 +00:00
preg_match('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) || // or a configuration variable
preg_match('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tag_command)) { // or a section property
2000-11-17 23:14:51 +00:00
settype($tag_command, 'array');
$this->_parse_vars_props($tag_command);
2000-11-20 03:20:55 +00:00
return "<?php print $tag_command[0]; ?>";
2000-11-17 21:47:41 +00:00
}
2000-11-17 23:14:51 +00:00
switch ($tag_command) {
2000-11-17 21:47:41 +00:00
case 'include':
2000-11-20 20:06:06 +00:00
return $this->_compile_include_tag($tag_args);
2000-11-17 21:47:41 +00:00
case 'if':
2000-11-17 23:14:51 +00:00
return $this->_compile_if_tag($tag_args);
2000-08-08 17:05:38 +00:00
2000-11-17 21:47:41 +00:00
case 'else':
return '<?php else: ?>';
2000-08-08 17:05:38 +00:00
2000-12-04 21:48:51 +00:00
case 'elseif':
return $this->_compile_if_tag($tag_args, true);
2000-11-17 21:47:41 +00:00
case '/if':
return '<?php endif; ?>';
case 'ldelim':
return $this->left_delimiter;
case 'rdelim':
return $this->right_delimiter;
case 'section':
2000-11-20 03:20:55 +00:00
array_push($this->_sectionelse_stack, false);
2000-11-17 23:14:51 +00:00
return $this->_compile_section_start($tag_args);
2000-11-17 21:47:41 +00:00
2000-11-20 03:20:55 +00:00
case 'sectionelse':
$this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
return "<?php endfor; else: ?>";
2000-11-17 21:47:41 +00:00
case '/section':
2000-11-20 03:20:55 +00:00
if (array_pop($this->_sectionelse_stack))
return "<?php endif; ?>";
else
return "<?php endfor; endif; ?>";
2000-11-17 21:47:41 +00:00
2000-11-20 20:06:06 +00:00
case 'config_load':
return $this->_compile_config_load_tag($tag_args);
2000-11-20 23:08:17 +00:00
case 'strip':
case '/strip':
return $this->left_delimiter.$tag_command.$this->right_delimiter;
2000-11-27 17:39:40 +00:00
case 'literal':
list (,$literal_block) = each($this->_literal_blocks);
2001-01-26 16:11:21 +00:00
$this->_current_line_no += substr_count($literal_block, "\n");
2000-11-27 17:39:40 +00:00
return $literal_block;
case 'insert':
return $this->_compile_insert_tag($tag_args);
2000-11-17 21:47:41 +00:00
default:
2001-01-02 14:51:02 +00:00
if (isset($this->custom_funcs[$tag_command])) {
2000-11-21 21:54:26 +00:00
return $this->_compile_custom_tag($tag_command, $tag_args);
2001-01-18 17:41:30 +00:00
} else {
2001-01-26 16:11:21 +00:00
$this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING);
2001-01-18 17:41:30 +00:00
return "";
}
2000-11-17 21:47:41 +00:00
}
}
2000-11-21 21:54:26 +00:00
function _compile_custom_tag($tag_command, $tag_args)
2000-11-21 20:29:55 +00:00
{
$attrs = $this->_parse_attrs($tag_args);
2001-01-02 14:51:02 +00:00
$function = $this->custom_funcs[$tag_command];
2000-12-04 21:48:51 +00:00
foreach ($attrs as $arg_name => $arg_value) {
if (is_bool($arg_value))
$arg_value = $arg_value ? 'true' : 'false';
2000-11-21 20:29:55 +00:00
$arg_list[] = "'$arg_name' => $arg_value";
2000-12-04 21:48:51 +00:00
}
2000-11-21 20:29:55 +00:00
2000-12-04 21:48:51 +00:00
return "<?php $function(array(".implode(',', (array)$arg_list).")); ?>";
2000-11-21 20:29:55 +00:00
}
function _compile_insert_tag($tag_args)
{
$attrs = $this->_parse_attrs($tag_args);
$name = substr($attrs['name'], 1, -1);
if($this->cache_engine)
return "<?php print \"{{{insert_cache ".addslashes($tag_args)."}}}\"; ?>";
if (empty($name)) {
2001-01-26 16:11:21 +00:00
$this->_syntax_error("missing insert name");
}
foreach ($attrs as $arg_name => $arg_value) {
if ($arg_name == 'name') continue;
if (is_bool($arg_value))
$arg_value = $arg_value ? 'true' : 'false';
$arg_list[] = "'$arg_name' => $arg_value";
}
return "<?php print insert_$name(array(".implode(',', (array)$arg_list).")); ?>";
}
2000-11-20 20:06:06 +00:00
function _compile_config_load_tag($tag_args)
{
$attrs = $this->_parse_attrs($tag_args);
if (empty($attrs['file'])) {
2001-01-26 16:11:21 +00:00
$this->_syntax_error("missing 'file' attribute in config_load tag");
2000-11-20 20:06:06 +00:00
}
2001-01-12 19:24:31 +00:00
$output = "<?php if (!class_exists('Config_File'))\n" .
" include_once 'Config_File.class.php';\n" .
"if (!is_object(\$_conf_obj) || get_class(\$_conf_obj) != 'config_file') {\n" .
" \$_conf_obj = new Config_File('".$this->config_dir."');\n" .
"}\n" .
"\$_config = array_merge((array)\$_config, \$_conf_obj->get(".$attrs['file']."));\n";
2000-11-27 17:39:40 +00:00
if (!empty($attrs['section']))
$output .= '$_config = array_merge((array)$_config, $_conf_obj->get('.$attrs['file'].', '.$attrs['section'].')); ';
2000-11-20 20:06:06 +00:00
2000-11-27 17:39:40 +00:00
$output .= '?>';
2000-11-20 20:06:06 +00:00
return $output;
}
function _compile_include_tag($tag_args)
{
$attrs = $this->_parse_attrs($tag_args);
if (empty($attrs['file'])) {
2001-01-26 16:11:21 +00:00
$this->_syntax_error("missing 'file' attribute in include tag");
2000-11-27 17:39:40 +00:00
} else
$attrs['file'] = $this->_dequote($attrs['file']);
if (count($attrs) > 1) {
$include_func_name = uniqid("_include_");
$include_file_name = $this->compile_dir.'/'.$attrs['file'];
foreach ($attrs as $arg_name => $arg_value) {
if ($arg_name == 'file') continue;
if (is_bool($arg_value))
$arg_value = $arg_value ? 'true' : 'false';
$arg_list[] = "'$arg_name' => $arg_value";
}
return "<?php " .
2000-12-27 19:58:05 +00:00
"function $include_func_name(\$file_name, \$def_vars, \$include_vars)\n" .
"{\n" .
2000-12-27 19:58:05 +00:00
" extract(\$def_vars);\n" .
" extract(\$include_vars);\n" .
2001-01-12 20:48:43 +00:00
" include \"\$file_name.php\";\n" .
"}\n" .
2000-12-27 19:58:05 +00:00
"$include_func_name(\"$include_file_name\", get_defined_vars(), array(".implode(',', (array)$arg_list)."));\n?>\n";
} else
return '<?php include "'.$this->compile_dir.'/'.$attrs['file'].'.php"; ?>';
2000-11-20 20:06:06 +00:00
}
2000-12-04 21:48:51 +00:00
function _compile_section_start($tag_args)
2000-11-17 21:47:41 +00:00
{
2000-12-04 21:48:51 +00:00
$attrs = $this->_parse_attrs($tag_args);
2000-11-20 03:20:55 +00:00
$output = "<?php ";
2000-11-20 03:20:55 +00:00
$section_name = $attrs['name'];
if (empty($section_name)) {
2001-01-26 16:11:21 +00:00
$this->_syntax_error("missing section name");
2000-11-20 03:20:55 +00:00
}
2000-11-27 17:39:40 +00:00
$output .= "unset(\$_sections[$section_name]);\n";
$section_props = "\$_sections[$section_name]['properties']";
2000-11-20 03:20:55 +00:00
foreach ($attrs as $attr_name => $attr_value) {
switch ($attr_name) {
case 'loop':
$output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : $attr_value;\n";
2000-11-20 03:20:55 +00:00
break;
2000-12-04 22:39:48 +00:00
case 'show':
if (is_bool($attr_value))
$attr_value = $attr_value ? 'true' : 'false';
$output .= "{$section_props}['$attr_name'] = $attr_value;\n";
break;
2000-11-20 03:20:55 +00:00
default:
$output .= "{$section_props}['$attr_name'] = $attr_value;\n";
break;
}
}
if (isset($attrs['loop'])) {
2000-12-13 15:08:25 +00:00
$loop_check_code = "{$section_props}['loop'] > 0 && ";
2000-11-20 03:20:55 +00:00
} else {
$output .= "{$section_props}['loop'] = 1;\n";
}
if (isset($attrs['show'])) {
$show_check_code = "{$section_props}['show'] && ";
2001-01-09 17:50:51 +00:00
} else {
$output .= "{$section_props}['show'] = {$section_props}['loop'] > 0;\n";
2000-11-20 03:20:55 +00:00
}
$output .= "if ($loop_check_code $show_check_code true): ";
$output .= "
for ({$section_props}['index'] = 0;
{$section_props}['index'] < {$section_props}['loop'];
{$section_props}['index']++):\n";
2000-12-27 19:58:05 +00:00
$output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n";
2000-11-20 03:20:55 +00:00
$output .= "?>\n";
return $output;
2000-11-17 23:14:51 +00:00
}
2000-12-04 21:48:51 +00:00
function _compile_if_tag($tag_args, $elseif = false)
2000-11-17 23:14:51 +00:00
{
/* Tokenize args for 'if' tag. */
preg_match_all('/(?:
"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | # match all double quoted strings allowed escaped double quotes
\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | # match all single quoted strings allowed escaped single quotes
[()] | # match parentheses
[^"\'\s()]+ # match any other token that is not any of the above
)/x', $tag_args, $match);
$tokens = $match[0];
2000-11-17 21:47:41 +00:00
$this->_parse_vars_props($tokens);
$is_arg_stack = array();
2000-11-15 17:08:52 +00:00
2000-11-17 21:47:41 +00:00
for ($i = 0; $i < count($tokens); $i++) {
$token = &$tokens[$i];
switch ($token) {
case 'eq':
$token = '==';
break;
case 'ne':
case 'neq':
$token = '!=';
break;
case 'lt':
$token = '<';
break;
case 'le':
case 'lte':
$token = '<=';
break;
case 'gt':
$token = '>';
break;
2000-11-15 17:08:52 +00:00
2000-11-17 21:47:41 +00:00
case 'ge':
case 'gte':
$token = '>=';
break;
case 'and':
$token = '&&';
break;
case 'or':
$token = '||';
break;
case 'not':
$token = '!';
break;
case 'mod':
$token = '%';
break;
case '(':
array_push($is_arg_stack, $i);
break;
case 'is':
/* If last token was a ')', we operate on the parenthesized
expression. The start of the expression is on the stack.
Otherwise, we operate on the last encountered token. */
if ($tokens[$i-1] == ')')
$is_arg_start = array_pop($is_arg_stack);
else
$is_arg_start = $i-1;
/* Construct the argument for 'is' expression, so it knows
what to operate on. */
$is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
/* Pass all tokens from next one until the end to the
'is' expression parsing function. The function will
return modified tokens, where the first one is the result
of the 'is' expression and the rest are the tokens it
didn't touch. */
$new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
/* Replace the old tokens with the new ones. */
array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
/* Adjust argument start so that it won't change from the
current position for the next iteration. */
$i = $is_arg_start;
break;
}
}
2000-11-15 17:08:52 +00:00
2000-12-04 21:48:51 +00:00
if ($elseif)
return '<?php elseif ('.implode(' ', $tokens).'): ?>';
else
return '<?php if ('.implode(' ', $tokens).'): ?>';
2000-11-17 21:47:41 +00:00
}
function _parse_is_expr($is_arg, $tokens)
{
$expr_end = 0;
if (($first_token = array_shift($tokens)) == 'not') {
$negate_expr = true;
$expr_type = array_shift($tokens);
} else
$expr_type = $first_token;
switch ($expr_type) {
case 'even':
if ($tokens[$expr_end] == 'by') {
$expr_end++;
$expr_arg = $tokens[$expr_end++];
2000-11-20 20:06:06 +00:00
$expr = "!(($is_arg / $expr_arg) % $expr_arg)";
2000-11-17 21:47:41 +00:00
}
else
$expr = "!($is_arg % 2)";
break;
case 'odd':
if ($tokens[$expr_end] == 'by') {
$expr_end++;
$expr_arg = $tokens[$expr_end++];
2000-11-20 20:06:06 +00:00
$expr = "(($is_arg / $expr_arg) % $expr_arg)";
2000-11-17 21:47:41 +00:00
}
else
$expr = "($is_arg % 2)";
break;
2001-01-16 15:50:30 +00:00
case 'div':
if ($tokens[$expr_end] == 'by') {
$expr_end++;
$expr_arg = $tokens[$expr_end++];
$expr = "!($is_arg % $expr_arg)";
} else {
2001-01-26 16:11:21 +00:00
$this->_syntax_error("expecting 'by' after 'div'");
2001-01-16 15:50:30 +00:00
}
2000-11-17 21:47:41 +00:00
break;
default:
2001-01-26 16:11:21 +00:00
$this->_syntax_error("unknown 'is' expression - '$expr_type'");
2000-11-17 21:47:41 +00:00
break;
}
if ($negate_expr) {
$expr = "!($expr)";
}
array_splice($tokens, 0, $expr_end, $expr);
return $tokens;
}
2000-11-17 23:14:51 +00:00
function _parse_attrs($tag_args)
{
/* Tokenize tag attributes. */
2000-12-04 21:48:51 +00:00
preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
2001-01-12 19:24:31 +00:00
\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'=\s]+)
2000-12-04 21:48:51 +00:00
)+ |
[=]
/x', $tag_args, $match);
2000-11-17 23:14:51 +00:00
$tokens = $match[0];
2000-12-04 21:51:45 +00:00
$var_delims = array('$', '#', '%');
2000-11-17 23:14:51 +00:00
$attrs = array();
/* Parse state:
0 - expecting attr name
1 - expecting '=' or another attr name
2 - expecting attr value (not '=') */
$state = 0;
2000-11-20 03:20:55 +00:00
foreach ($tokens as $token) {
2000-11-17 23:14:51 +00:00
switch ($state) {
case 0:
/* If the token is a valid identifier, we set attribute name
and go to state 1. */
if (preg_match('!\w+!', $token)) {
$attr_name = $token;
$state = 1;
} else
2001-01-26 16:11:21 +00:00
$this->_syntax_error("invalid attribute name - '$token'");
2000-11-17 23:14:51 +00:00
break;
case 1:
/* If the token is a valid identifier, the previously set
attribute name does not need an argument. We put it in
the attrs array, set the new attribute name to the
current token and don't switch state.
If the token is '=', then we go to state 2. */
2000-12-04 21:48:51 +00:00
if ($token == '=') {
2000-11-17 23:14:51 +00:00
$state = 2;
} else
2001-01-26 16:11:21 +00:00
$this->_syntax_error("expecting '=' after attribute name");
2000-11-17 23:14:51 +00:00
break;
case 2:
/* If token is not '=', we set the attribute value and go to
state 0. */
if ($token != '=') {
2000-12-04 21:48:51 +00:00
/* We booleanize the token if it's a non-quoted possible
boolean value. */
if (preg_match('!^(on|yes|true)$!', $token))
$token = true;
else if (preg_match('!^(off|no|false)$!', $token))
$token = false;
/* If the token is not variable (doesn't start with
'$', '#', or '%') and not enclosed in single or
double quotes we single-quote it. */
2000-12-04 21:51:45 +00:00
else if (!in_array($token{0}, $var_delims) &&
2000-12-04 21:48:51 +00:00
!(($token{0} == '"' || $token[0] == "'") &&
$token{strlen($token)-1} == $token{0}))
2000-11-27 17:39:40 +00:00
$token = "'".$token."'";
2000-12-04 21:48:51 +00:00
2000-11-17 23:14:51 +00:00
$attrs[$attr_name] = $token;
$state = 0;
} else
2001-01-26 16:11:21 +00:00
$this->_syntax_error("'=' cannot be an attribute value");
2000-11-17 23:14:51 +00:00
break;
}
}
2000-12-04 21:48:51 +00:00
$this->_parse_vars_props($attrs);
2000-11-17 23:14:51 +00:00
return $attrs;
}
2001-01-12 19:24:31 +00:00
function _preg_grep($pattern, $array)
{
$result = array();
foreach ($array as $key => $entry) {
if (preg_match($pattern, $entry))
$result[$key] = $entry;
}
return $result;
}
2000-11-17 21:47:41 +00:00
function _parse_vars_props(&$tokens)
{
2001-01-12 19:24:31 +00:00
/* preg_grep() was fixed to return keys properly in 4.0.4 and later. To
allow people to use older versions of PHP we emulate preg_grep() and
use the version check to see what function to call. */
if (strnatcmp(PHP_VERSION, '4.0.4') >= 0) {
2001-01-26 15:15:55 +00:00
$var_exprs = preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
2001-01-12 19:24:31 +00:00
$conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
$sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
} else {
2001-01-26 15:15:55 +00:00
$var_exprs = $this->_preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
2001-01-12 19:24:31 +00:00
$conf_var_exprs = $this->_preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
$sect_prop_exprs = $this->_preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
}
2000-11-17 21:47:41 +00:00
if (count($var_exprs)) {
foreach ($var_exprs as $expr_index => $var_expr) {
$tokens[$expr_index] = $this->_parse_var($var_expr);
}
}
2000-11-20 20:06:06 +00:00
if (count($conf_var_exprs)) {
foreach ($conf_var_exprs as $expr_index => $var_expr) {
$tokens[$expr_index] = $this->_parse_conf_var($var_expr);
}
}
2000-11-17 21:47:41 +00:00
if (count($sect_prop_exprs)) {
2000-11-20 03:20:55 +00:00
foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
2000-11-17 21:47:41 +00:00
$tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
}
}
2000-08-08 17:05:38 +00:00
}
2000-11-17 21:47:41 +00:00
function _parse_var($var_expr)
{
2001-01-09 17:50:51 +00:00
$modifiers = explode('|', substr($var_expr, 1));
2000-11-17 21:47:41 +00:00
2001-01-09 17:50:51 +00:00
$sections = explode('/', array_shift($modifiers));
2001-01-26 15:15:55 +00:00
$props = explode('.', array_pop($sections));
$var_name = array_shift($props);
2000-11-17 21:47:41 +00:00
$output = "\$$var_name";
foreach ($sections as $section) {
$output .= "[\$_sections['$section']['properties']['index']]";
}
2001-01-26 15:15:55 +00:00
foreach ($props as $prop) {
$output .= "['$prop']";
}
2000-11-17 21:47:41 +00:00
2001-01-09 17:50:51 +00:00
$this->_parse_modifiers($output, $modifiers);
2000-11-17 21:47:41 +00:00
return $output;
}
2000-11-20 20:06:06 +00:00
function _parse_conf_var($conf_var_expr)
{
2001-01-09 17:50:51 +00:00
$modifiers = explode('|', $conf_var_expr);
2000-11-20 20:06:06 +00:00
2001-01-09 17:50:51 +00:00
$var_name = substr(array_shift($modifiers), 1, -1);
2000-11-20 20:06:06 +00:00
$output = "\$_config['$var_name']";
2001-01-09 17:50:51 +00:00
$this->_parse_modifiers($output, $modifiers);
2000-11-20 20:06:06 +00:00
return $output;
}
2000-11-17 21:47:41 +00:00
function _parse_section_prop($section_prop_expr)
{
2001-01-09 17:50:51 +00:00
$modifiers = explode('|', $section_prop_expr);
2000-11-17 21:47:41 +00:00
2001-01-09 17:50:51 +00:00
preg_match('!%(\w+)\.(\w+)%!', array_shift($modifiers), $match);
2000-11-17 21:47:41 +00:00
$section_name = $match[1];
$prop_name = $match[2];
$output = "\$_sections['$section_name']['properties']['$prop_name']";
2001-01-09 17:50:51 +00:00
$this->_parse_modifiers($output, $modifiers);
2000-11-17 21:47:41 +00:00
return $output;
}
2001-01-09 17:50:51 +00:00
function _parse_modifiers(&$output, $modifiers)
2000-11-17 21:47:41 +00:00
{
2001-01-09 17:50:51 +00:00
foreach ($modifiers as $modifier) {
2000-11-17 21:47:41 +00:00
$modifier = explode(':', $modifier);
$modifier_name = array_shift($modifier);
2000-12-07 22:47:01 +00:00
if ($modifier_name{0} == '@') {
$map_array = 'false';
$modifier_name = substr($modifier_name, 1);
} else
$map_array = 'true';
2000-11-17 21:47:41 +00:00
/*
* First we lookup the modifier function name in the registered
* modifiers table.
*/
2001-01-02 14:51:02 +00:00
$mod_func_name = $this->custom_mods[$modifier_name];
2000-11-17 21:47:41 +00:00
/*
* If we don't find that modifier there, we assume it's just a PHP
* function name.
*/
if (!isset($mod_func_name))
$mod_func_name = $modifier_name;
2000-11-20 20:06:06 +00:00
$this->_parse_vars_props($modifier);
2000-11-17 21:47:41 +00:00
if (count($modifier) > 0)
2000-11-27 17:39:40 +00:00
$modifier_args = ', '.implode(', ', $modifier);
2000-11-17 21:47:41 +00:00
else
2000-11-27 17:39:40 +00:00
$modifier_args = '';
2000-11-17 21:47:41 +00:00
2000-12-07 22:47:01 +00:00
$output = "_smarty_mod_handler('$mod_func_name', $map_array, $output$modifier_args)";
2000-11-17 21:47:41 +00:00
}
}
2000-11-27 17:39:40 +00:00
/*======================================================================*\
Function: _dequote
Purpose: Remove starting and ending quotes from the string
\*======================================================================*/
function _dequote($string)
{
if (($string{0} == "'" || $string{0} == '"') &&
$string{strlen($string)-1} == $string{0})
return substr($string, 1, -1);
}
2000-08-08 17:05:38 +00:00
/*======================================================================*\
Function: _read_file()
Purpose: read in a file
\*======================================================================*/
function _read_file($filename)
{
2001-01-12 19:24:31 +00:00
if(!($fd = fopen($filename, 'r'))) {
$this->_set_error_msg("problem reading '$filename.'");
2000-08-08 17:05:38 +00:00
return false;
}
2001-01-12 19:24:31 +00:00
$contents = fread($fd, filesize($filename));
2000-08-08 17:05:38 +00:00
fclose($fd);
return $contents;
}
/*======================================================================*\
Function: _write_file()
Purpose: write out a file
\*======================================================================*/
function _write_file($filename,$contents)
{
2001-01-12 19:24:31 +00:00
if(!($fd = fopen($filename, 'w'))) {
$this->_set_error_msg("problem writing '$filename.'");
2000-08-08 17:05:38 +00:00
return false;
}
2001-01-12 19:24:31 +00:00
fwrite($fd, $contents);
2000-08-08 17:05:38 +00:00
fclose($fd);
return true;
}
/*======================================================================*\
2000-11-20 22:31:38 +00:00
Function: _set_error_msg()
2000-08-08 17:05:38 +00:00
Purpose: set the error message
\*======================================================================*/
2000-11-20 22:31:38 +00:00
function _set_error_msg($error_msg)
2000-08-08 17:05:38 +00:00
{
2000-11-20 22:31:38 +00:00
$this->_error_msg="smarty error: $error_msg";
2000-08-08 17:05:38 +00:00
return true;
}
2001-01-26 16:11:21 +00:00
/*======================================================================*\
Function: _syntax_error
Purpose: display Smarty syntax error
\*======================================================================*/
function _syntax_error($error_msg, $error_type = E_USER_ERROR)
{
trigger_error("Smarty: [in " . $this->_current_file . " line " .
$this->_current_line_no . "]: syntax error: $error_msg", $error_type);
}
2000-08-08 17:05:38 +00:00
}
?>