条件语句:
<!--{if $op == 'syn' || $op == 'find' || $op == 'search' || $op == 'group' || $op == 'request'}-->
这是判断语句
<!--{elseif $op == 'find'}-->
这是elseif的应用
<!--{else}-->
这是else应用语句
<!--{/if}-->
循环语句:
<!--{loop $array $a_key $a_val}-->
这是循环语句
<!--{/loop}-->
模板变量语句:
{$var}
eval应用语句:(后面的分号记得要加上)
{eval echo 1+2+3+4+5;}
语言模块的调用:(简单理解成读取了$language['china'])
{lang china}
两种引入模板文件的方法:
{subtemplate header} //这种是静态引入, 即把header的代码直接加载在当前的缓存文件上。
{template header} //这种是动态引入, 会通过include来引入。
Discuz的模板引擎 一个比较好的模板引擎类,很久以前就在网上找到,目前这个Discuz的模板引擎应该很老了,是DZ7.2以前的版本了,自己也用得很顺手,分享下这个模板类。
有两个文件,一个模板类,一个模板替换中需要用到的函数:
模板函数文件:template.func.php
<?php /** * 模板替换中需要用到的函数 */ function transamp($template) { $template = str_replace('&', '&', $template); $template = str_replace('&', '&', $template); $template = str_replace('"', '"', $template); return $template; } function stripvtags($expr, $statement) { $expr = str_replace("\"", """, preg_replace("/<?=(\$.+?)?>/s", "\1", $expr)); $statement = str_replace("\"", """, $statement); return $expr . $statement; } function addquote($var) { return str_replace("\"", """, preg_replace("/[([a-zA-Z0-9_-.x7f-xff]+)]/s", "['\1']", $var)); } function stripscriptamp($s) { $s = str_replace('&', '&', $s); return "<script src="$s" type="text/javascript"></script>"; } function stripblock($var, $s) { $s = str_replace('\"', '"', $s); $s = preg_replace("/<?=\$(.+?)?>/", "{$\1}", $s); preg_match_all("/<?=(.+?)?>/e", $s, $constary); $constadd = ''; $constary[1] = array_unique($constary[1]); foreach($constary[1] as $const) { $constadd .= '$__' . $const .' = ' . $const . ';'; } $s = preg_replace("/<?=(.+?)?>/", "{$__\1}", $s); $s = str_replace('?>', " $$var .= <<<EOF ", $s); $s = str_replace('<?', " EOF; ", $s); return "<? $constadd$$var = <<<EOF " . $s . " EOF; ?>"; } ?>
模板引擎类:
<?php /** * 模板类 - 使用 Discuz 模板引擎解析 */ require_once (DIR_ROOT . '/../function/template.func.php'); class Template { const DIR_SEP = DIRECTORY_SEPARATOR; /** * 模板实例 * * @staticvar * @var object Template */ protected static $_instance; /** * 模板参数信息 * * @var array */ protected $_options = array(); /** * 单件模式调用方法 * * @static * @return object Template */ public static function getInstance() { if (!self::$_instance instanceof self) self::$_instance = new self(); return self::$_instance; } /** * 构造方法 * * @return void */ private function __construct() { $this->_options = array( 'template_dir' => 'templates' . self::DIR_SEP, // 模板文件所在目录 'cache_dir' => 'templates' . self::DIR_SEP . 'cache' . self::DIR_SEP, // 缓存文件存放目录 'auto_update' => false, // 当模板文件改动时是否重新生成缓存 'cache_lifetime' => 0 // 缓存生命周期(分钟),为 0 表示永久 ); } /** * 设定模板参数信息 * * @param array $options * 参数数组 * @return void */ public function setOptions(array $options) { foreach ($options as $name => $value) $this->set($name, $value); } /** * 设定模板参数 * * @param string $name * 参数名称 * @param mixed $value * 参数值 * @return void */ public function set($name, $value) { switch ($name) { case 'template_dir' : $value = $this->_trimpath($value); if (!file_exists($value)) $this->_throwException("未找到指定的模板目录 "$value""); $this->_options['template_dir'] = $value; break; case 'cache_dir' : $value = $this->_trimpath($value); if (!file_exists($value)) $this->_throwException("未找到指定的缓存目录 "$value""); $this->_options['cache_dir'] = $value; break; case 'auto_update' : $this->_options['auto_update'] = (boolean)$value; break; case 'cache_lifetime' : $this->_options['cache_lifetime'] = (float)$value; break; default : $this->_throwException("未知的模板配置选项 "$name""); } } /** * 通过魔术方法设定模板参数 * * @see Template::set() * @param string $name * 参数名称 * @param mixed $value * 参数值 * @return void */ public function __set($name, $value) { $this->set($name, $value); } /** * 获取模板文件 * * @param string $file * 模板文件名称 * @return string */ public function getfile($file) { $cachefile = $this->_getCacheFile($file); if (!file_exists($cachefile)) $this->cache($file); return $cachefile; } /** * 检测模板文件是否需要更新缓存 * * @param string $file * 模板文件名称 * @param string $md5data * 模板文件 md5 校验信息 * @param integer $md5data * 模板文件到期时间校验信息 * @return void */ public function check($file, $md5data, $expireTime) { if ($this->_options['auto_update'] && md5_file($this->_getTplFile($file)) != $md5data) $this->cache($file); if ($this->_options['cache_lifetime'] != 0 && (time() - $expireTime >= $this->_options['cache_lifetime'] * 60)) $this->cache($file); } /** * 对模板文件进行缓存 * * @param string $file * 模板文件名称 * @return void */ public function cache($file) { $tplfile = $this->_getTplFile($file); if (!is_readable($tplfile)) { $this->_throwException("模板文件 "$tplfile" 未找到或者无法打开"); } // 取得模板内容 $template = file_get_contents($tplfile); // 过滤 <!--{}--> $template = preg_replace("/<!--{(.+?)}-->/s", "{\1}", $template); // 替换语言包变量 // $template = preg_replace("/{langs+(.+?)}/ies", "languagevar('\1')", $template); // 替换 PHP 换行符 $template = str_replace("{LF}", "<?="\n"?>", $template); // 替换直接变量输出 $varRegexp = "((\$[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)" . "([[a-zA-Z0-9_-."'[]$x7f-xff]+])*)"; $template = preg_replace("/{(\$[a-zA-Z0-9_[]'"$.x7f-xff]+)}/s", "<?=\1?>", $template); $template = preg_replace("/$varRegexp/es", "addquote('<?=\1?>')", $template); $template = preg_replace("/<?=<?=$varRegexp?>?>/es", "addquote('<?=\1?>')", $template); // 替换模板载入命令 $template = preg_replace("/[ ]*{templates+([a-z0-9_]+)}[ ]*/is", " <? include($template->getfile('\1')); ?> ", $template); $template = preg_replace("/[ ]*{templates+(.+?)}[ ]*/is", " <? include($template->getfile(\1)); ?> ", $template); // 替换特定函数 $template = preg_replace("/[ ]*{evals+(.+?)}[ ]*/ies", "stripvtags('<? \1 ?>','')", $template); $template = preg_replace("/[ ]*{echos+(.+?)}[ ]*/ies", "stripvtags('<? echo \1; ?>','')", $template); $template = preg_replace("/([ ]*){elseifs+(.+?)}([ ]*)/ies", "stripvtags('\1<? } elseif(\2) { ?>\3','')", $template); $template = preg_replace("/([ ]*){else}([ ]*)/is", "\1<? } else { ?>\2", $template); // 替换循环函数及条件判断语句 $nest = 5; for ($i = 0; $i < $nest; $i++) { $template = preg_replace("/[ ]*{loops+(S+)s+(S+)}[ ]*(.+?)[ ]*{/loop}[ ]*/ies", "stripvtags('<? if(is_array(\1)) { foreach(\1 as \2) { ?>','\3<? } } ?>')", $template); $template = preg_replace("/[ ]*{loops+(S+)s+(S+)s+(S+)}[ ]*(.+?)[ ]*{/loop}[ ]*/ies", "stripvtags('<? if(is_array(\1)) { foreach(\1 as \2 => \3) { ?>','\4<? } } ?>')", $template); $template = preg_replace("/([ ]*){ifs+(.+?)}([ ]*)(.+?)([ ]*){/if}([ ]*)/ies", "stripvtags('\1<? if(\2) { ?>\3','\4\5<? } ?>\6')", $template); } // 常量替换 $template = preg_replace("/{([a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)}/s", "<?=\1?>", $template); // 删除 PHP 代码断间多余的空格及换行 $template = preg_replace("/ ?>[ ]*<? /s", " ", $template); // 其他替换 $template = preg_replace("/"(http)?[w./:]+?[^"]+?&[^"]+?"/e", "transamp('\0')", $template); $template = preg_replace("/<script[^>]*?src="(.+?)".*?>s*</script>/ise", "stripscriptamp('\1')", $template); $template = preg_replace("/[ ]*{blocks+([a-zA-Z0-9_]+)}(.+?){/block}/ies", "stripblock('\1', '\2')", $template); // 添加 md5 及过期校验 $md5data = md5_file($tplfile); $expireTime = time(); $template = "<? if (!class_exists('template')) die('Access Denied');" . "$template->getInstance()->check('$file', '$md5data', $expireTime);" . "?> $template"; // 写入缓存文件 $cachefile = $this->_getCacheFile($file); $makepath = $this->_makepath($cachefile); if ($makepath !== true) $this->_throwException("无法创建缓存目录 "$makepath""); file_put_contents($cachefile, $template); } /** * 将路径修正为适合操作系统的形式 * * @param string $path * 路径名称 * @return string */ protected function _trimpath($path) { return str_replace(array( '/', '\', '//', '\\' ), self::DIR_SEP, $path); } /** * 获取模板文件名及路径 * * @param string $file * 模板文件名称 * @return string */ protected function _getTplFile($file) { return $this->_trimpath($this->_options['template_dir'] . self::DIR_SEP . $file); } /** * 获取模板缓存文件名及路径 * * @param string $file * 模板文件名称 * @return string */ protected function _getCacheFile($file) { $file = preg_replace('/.[a-z0-9-_]+$/i', '.cache.php', $file); return $this->_trimpath($this->_options['cache_dir'] . self::DIR_SEP . $file); } /** * 根据指定的路径创建不存在的文件夹 * * @param string $path * 路径/文件夹名称 * @return string */ protected function _makepath($path) { $dirs = explode(self::DIR_SEP, dirname($this->_trimpath($path))); $tmp = ''; foreach ($dirs as $dir) { $tmp .= $dir . self::DIR_SEP; if (!file_exists($tmp) && !@mkdir($tmp, 0777)) return $tmp; } return true; } /** * 抛出一个错误信息 * * @param string $message * @return void */ protected function _throwException($message) { throw new Exception($message); } } ?>