<?php /* 系统核心模板类 模板支持静态化, 模板表单安全验证, 模板可直接调用验证码, COOKIE, SESSION, 所有常用标签解析(一定程度上支持嵌套, 逻辑判断), 模板扩展标签解析, 模板插件(函数直接调用), 并做了几个常用系统函数标签, 模板局部静态化, 模板一次性编译, 模板缓存生存时间限制, 模板缓存清除(自动清除和手工清除均支持, 手工指定模板是否缓存), 模板可控制是否与php代码嵌套, 模板布局渲染(页面首尾分离, 可手工指定不分离), 更多配置, 可在配置文件中选择 */ defined("IN_SHOP") or die(); class Tpl { protected $template_dir = 'tmp/template/'; //模板目录 protected $compile_dir = 'tmp/compile/'; //模板编译目录 protected $left_delimiter = '{'; //模板解析标识符 protected $right_delimiter = '}'; protected $tpl_suffix = '.html'; //模板后缀, 与静态页面后缀保持一致 protected $cpl_prefix = ''; //模板编译文件前缀 protected $max_cache_time = 0; //模板最大缓存时间(0默认永久缓存, 以后可在后台手工清除缓存, 或者在系统常量中定义最大缓存时间) protected $make_cache = false; //是否开启模板编译缓存 protected $max_make_time = 0; //模板最大编译缓存时间(0默认永久缓存) protected $is_cache = false; //是否开启模板缓存(模板整体静态化) protected $cache_dir = 'tpl_caches'; //模板缓存目录 protected $_var = array(); //assign变量 protected $form_hash = ''; //模板表单随机码, 防止跨域提交(模板静态化时, 该功能将关闭) protected $layout = false; //是否开启布局渲染, 后台一般不需要启用模板布局 protected $layout_dir = 'layout'; //模板布局目录 protected $layout_file = 'layout.html'; //模板布局文件(格式 header {$layout} footer) protected $tpl_char = 'utf-8'; //默认模板编码格式 protected $tpl_php = true; //是否允许模板中内嵌PHP代码 protected $tpl_extends_dir = 'tpl_extends'; //模板扩展目录 protected $tpl_plugins_file = 'tpl_plugins.php'; //模板插件文件 protected $tag_extends_file = 'tag_extends_file'; //自定义扩展标签解析文件 protected $tag = array( /* notice: 请严格按照标签示例写 */ /* 标签解析规则 $key:标签名, attr:标签属性, level:允许标签嵌套层次 function: 标签函数 */ 'var' => array('function' => '_var'), //普通一维数组 'include' => array('function' => '_include'), //css文件引入 'insert' => array('function' => '_insert'), //js文件引入 'foreach' => array('level' => 3, 'function' => '_foreach'), 'if' => array('function' => '_if'), 'tag_note' => array('function' => 'tag_note'), //模板注释标签 'date' => array('function' => '_date'), //返回当前时间 'session' => array('function' => '_session'), //session标签处理 'cookie' => array('function' => '_cookie'), //cookie标签处理 'cache' => array('function' => '_cache'), //局部缓存标签 'captcha' => array('function' => '_captcha'), //验证码标签(可直接生成验证码) 'for' => array('attr' => array( 'start' => 0, /* 默认从0开始循环, 最多循环10次, 步长为1 */ 'stop' => 10, 'step' => 1, ), 'level' => 2, 'function' => '_for'), /* 系统函数标签 */ 'substr' => array('function' => '_substr'), 'english_str' => array('attr' => array( 'ucfirst', 'strtolower', 'strtoupper', //英文字符串处理 ),'function' => 'english_str'), /* 插件调用 */ 'function' => array('function' => '_function'), /* 自定义扩展标签解析 */ 'extends' => array('function' => '_extends'), ); function __construct($tpl_dir = '', $cpl_dir = '', $cache_dir = '') { /* 可以控制前后台模板目录, 编译目录和缓存目录的不同位置 */ if ($tpl_dir) { $this->template_dir = $tpl_dir; if (!is_dir($this->template_dir)) @mkdir($this->template_dir, 0755, true); } else { $this->template_dir = ROOT_PATH . $this->template_dir; if (!is_dir($this->template_dir)) @mkdir($this->template_dir, 0755, true); } if ($cpl_dir) { $this->compile_dir = $cpl_dir; if (!is_dir($this->compile_dir)) @mkdir($this->compile_dir, 0755, true); } else { $this->compile_dir = ROOT_PATH . $this->template_dir; if (!is_dir($this->compile_dir)) @mkdir($this->compile_dir, 0755, true); } if (TAG_LEFT) $this->left_delimiter = TAG_LEFT; if (TAG_RIGHT) $this->right_delimiter = TAG_RIGHT; if (TPL_CACHE) $this->is_cache = TPL_CACHE; if (MAX_TPL_CACHE) $this->max_cache_time = MAX_TPL_CACHE; if ($cache_dir) { $this->cache_dir = $cache_dir; if (!is_dir($this->cache_dir)) @mkdir($this->cache_dir, 0755, true); } if (TPL_SUFFIX) $this->tpl_suffix = TPL_SUFFIX; if (CPL_PREFIX) $this->cpl_prefix = CPL_PREFIX; if (TPL_HASH) $this->form_hash = md5($this->template_dir . $this->compile_dir . date('YmdHis', time()) . rand(1000, 10000)); if (MAKE_CACHE) $this->make_cache = MAKE_CACHE; if (TPL_EXTENDS_DIR) { $this->tpl_extends_dir = ROOT_PATH . '/' .TPL_EXTENDS_DIR . '/'; if (!is_dir($this->tpl_extends_dir)) @mkdir($this->tpl_extends_dir); } if (TPL_PLUGINS_FILE) { $this->tpl_plugins_file = $this->tpl_extends_dir . TPL_PLUGINS_FILE; if (!file_exists($this->tpl_plugins_file)) @touch($this->tpl_plugins_file); } if (TAG_EXTENDS_FILE) { $this->tag_extends_file = $this->tpl_extends_dir . TAG_EXTENDS_FILE; if (!file_exists($this->tag_extends_file)) @touch($this->tag_extends_file); } if (LAYOUT_ON) { $this->layout = LAYOUT_ON; if(LAYOUT_DIR) $this->layout_dir = ROOT_PATH . LAYOUT_DIR . '/'; else $this->layout_dir = ROOT_PATH . $this->layout_dir . '/'; if (!is_dir($this->layout_dir)) @mkdir($this->layout_dir, 0755, true); if (LAYOUT_FILE) $this->layout_file = $this->layout_dir . LAYOUT_FILE; else $this->layout_file = $this->layout_dir . $this->layout_file; } if (MAX_MAKE_TIME) $this->max_make_time = MAX_MAKE_TIME; if (SHOP_CHARSET) $this->tpl_char = SHOP_CHARSET; if (!TPL_PHP) $this->tpl_php = TPL_PHP; header('Content-Type: text/html;charset=' . $this->tpl_char); //模板默认字符集 } /* 模板变量赋值 @parmas $name string 模板变量名 $value mixed 模板变量值(暂时不能接受对象, 资源) */ function assign($name, $value = '') { $this->_var[$name] = $value; } /* 手动指定模板是否缓存 */ function display($file, $is_cache = true, $layout = true) { //手工控制是否缓存 $this->tpl_cache = !$is_cache ? $is_cache : !$is_cache; //生成静态文件名 $static_file = $this->cache_dir . $file . $this->tpl_suffix; //生成编译文件名, 唯一文件 $make_name = $this->cpl_prefix . md5($this->compile_dir . $file) . '.php'; $make_file = $this->compile_dir . $make_name; //DEBUG模式下不启用静态缓存文件 if ($this->is_cache && DEBUG) { if (file_exists($static_file) && (filesize($static_file) > 0)) { //检测静态文件是否过期 if ($this->max_cache_time > 0) { if (!$this->check_file($static_file)) { //静态文件未过期 include ($static_file); exit(); } else { @unlink($static_file); } } else { include ($static_file); exit(); //永久缓存, 除非手工清除 } } else { //如果不存在检测编译文件是否存在, 如果存在则一并删除 if (file_exists($make_file)) @unlink($make_file); } } //检测编译文件是否存在, 如何存在则直接使用, 不用再编译 if (file_exists($make_file) && $this->make_cache && (filesize($make_file) > 0)) { //检测文件是否过期 if ($this->max_make_time > 0) { if (!$this->check_file($make_file, 'make')) { //编译未过期, 对其静态化 include ($make_file); exit(); } else { //删除编译文件 @unlink($make_file); } } else //编译文件永久缓存 { include ($make_file); exit(); } } $file = $this->template_dir . $file . $this->tpl_suffix; //检测模板是否存在 if (!file_exists($file)) { return $this->tpl_exception('模板异常: 模板不存在, 错误行号: ' . __LINE__); } //解析模板 $out = $this->fetch($file, $layout); //生成编译文件 if ($this->make_cache) $this->make_file($make_file, $out); //模板内容输出 echo $content = $this->_eval($out); //模板静态化, DEBUG模式下不缓存 if ($this->tpl_cache && !DEBUG) { $this->static_file($static_file, $content); } } /* 生成模板编译文件 */ protected function make_file($file, $content) { @file_put_contents($file, $content, LOCK_EX); } /* 模板静态化 */ protected function static_file($file, $content) { @file_put_contents($file, $content); } /* 检测文件是否过期, 如果过期返回true */ protected function check_file($file, $type = 'static') { if ((time() - filectime($file)) > $this->max_cache_time && $type == 'static') return true; elseif ((time() - filectime($file)) > $this->max_make_time && $type == 'make') return true; return false; } function fetch($file, $layout = true) { $content = file_get_contents($file); // 判断是否开启模板布局 if ($this->layout && file_exists($this->layout_file) && $layout) { $layout = file_get_contents($this->layout_file); $content = preg_replace('/\{\$layout\}/', $content, $layout); } //解析之前, 判断是否允许模板内嵌PHP代码 if (!$this->tpl_php) { $content = preg_replace('/\<\?php.*?\?\>/i', '', $content); } //去除编译文件中所有的换行, 增加编译代码执行效率 $content = $this->_trim($content); //开始解析标签 //最先解析所有模板注释标签 if (preg_match('/\\' . $this->left_delimiter . '\\*\*\*.*\*\*\*\\' . $this->right_delimiter . '/', $content, $res)) { $content = $this->tag_resolving('tag_note', $content); } //普通标签解析 preg_match_all('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\\'. $this->right_delimiter . '/i', $content, $tag); //匹配变量标签 if (!empty($tag[0])) $content = $this->_var($tag, $content); //普通标签处理 //include标签解析 if (preg_match('/\\' . $this->left_delimiter . '(include)\s+file\=.*\s+type\=css\s+\/\\' . $this->right_delimiter . '/is', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } //insert标签解析 if (preg_match('/\\' . $this->left_delimiter . '(insert)\sfile\=.*\stype\=javascript\s\/\\' . $this->right_delimiter . '/i', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } //foreach标签解析 if (preg_match('/\\' . $this->left_delimiter . '(foreach)\s+from/i', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } if (preg_match('/\\' . $this->left_delimiter . '(foreach)\s\.*\\' . $this->right_delimiter . '.*\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $tag)) { echo 123; } //for标签解析 if (preg_match('/\\' . $this->left_delimiter . '(for).*\\' . $this->right_delimiter . '.*\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/is', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } //if标签解析 if (preg_match('/\\' . $this->left_delimiter . '(if).*\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/if\\' . $this->right_delimiter . '/is', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } //substr标签 if (preg_match('/\\' . $this->left_delimiter . '\$.*?\:\s+_(substr)\([0-9]+\,\s{0,}[0-9]+\)\\' . $this->right_delimiter . '/i', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) $content = $this->tag_resolving($tag[1], $content); } /* english_str标签 */ //ucfirst if (preg_match('/\\' . $this->left_delimiter . '\\$.*?\:\s+_(ucfirst)\(\)\\' . $this->right_delimiter . '/i', $content, $tag)) { $function = $this->tag['english_str']['function']; $content = $this->$function($content, $tag[1]); } //strtolower if (preg_match('/\\' . $this->left_delimiter . '\\$.*?\:\s+_(strtolower)\(\)\\' . $this->right_delimiter . '/i', $content, $tag)) { $function = $this->tag['english_str']['function']; $content = $this->$function($content, $tag[1]); } //strtolupper if (preg_match('/\\' . $this->left_delimiter . '\\$.*?\:\s+_(strtoupper)\(\)\\' . $this->right_delimiter . '/i', $content, $tag)) { $function = $this->tag['english_str']['function']; $content = $this->$function($content, $tag[1]); } //解析date标签 if (preg_match('/\\' . $this->left_delimiter . '_(date)\(\)\\' . $this->right_delimiter . '/i', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } //session标签解析 if (preg_match('/\\' . $this->left_delimiter . '\$_(SESSION)\[[a-zA-Z0-9_]+\]\\' . $this->right_delimiter . '/i', $content, $tag)) { $session = strtolower($tag[1]); if (array_key_exists($session, $this->tag)) { $content = $this->tag_resolving($session, $content); } } //cookie标签解析 if (preg_match('/\\' . $this->left_delimiter . '\$_(COOKIE)\[[a-zA-Z0-9_]+\]\\' . $this->right_delimiter . '/i', $content, $tag)) { $session = strtolower($tag[1]); if (array_key_exists($session, $this->tag)) { $content = $this->tag_resolving($session, $content); } } //插件解析 if (preg_match('/\\' . $this->left_delimiter . '(function)\:\s+[a-zA-Z0-9_]+\(\)\\' . $this->right_delimiter . '/i', $content, $tag)) { $content = $this->tag_resolving($tag[1], $content); } //自定义标签解析 if (preg_match('/\\' . $this->left_delimiter . '(extends)\:\s+[a-zA-Z0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/extends\:\s+[a-zA-Z0-9]+\\' . $this->right_delimiter . '/i', $content, $tag)) { $content = $this->tag_resolving($tag[1], $content); } //普通数组标签解析 if (preg_match('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', $content, $tag)) { $content = $this->_array_var($content); } //验证码标签解析 if (preg_match('/\{(captcha).*\/\}/i', $content, $tag)) { $content = $this->tag_resolving($tag[1], $content); } //cache标签解析, 该标签最后解析 if (preg_match('/\\' . $this->left_delimiter . '(cache)\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/cache\\' . $this->right_delimiter . '/i', $content, $tag)) { if (array_key_exists($tag[1], $this->tag)) { $content = $this->tag_resolving($tag[1], $content); } } //表单hash串生成, 模板静态化时, 不生成表单随机码 if ($this->form_hash != '' && !$this->tpl_cache) { $content = $this->_hash($content); } return $content; } /* 模板异常处理 */ protected function tpl_exception($msg) { try{ throw New Exception($msg); //抛出异常 } catch(Exception $e) { echo $e->getMessage(); } return; } /* PHP代码可执行函数 */ protected function _eval($str) { if ($this->is_cache) { ob_start(); eval('?>' . trim($str)); $content = ob_get_contents(); ob_end_clean(); return $content; } else { return eval('?>' . trim($str)); } } /* 去除模板编译后文件的所有换行 */ protected function _trim($str) { return preg_replace('/[\r]+|[\n]+|[\r\n]+/', '', $str); } /* 标签解析调用方法 */ protected function tag_resolving($tag, $content) { $function = $this->tag[$tag]['function']; return $this->$function($content); } /* ************************************* ************************************* 标签解析函数 ************************************* ************************************* */ /* 注释标签 example: {*** 注释内容 ***} notice: 注释标签率先解析, 将注释掉所包含的所有代码(包括html, js, css代码) */ protected function tag_note($content) { $content = preg_replace('/\\' . $this->left_delimiter . '\*\*\*.*?\*\*\*\\' . $this->right_delimiter . '/', '', $content); return $content; } /* 普通标签处理 example: {$content} @params $tag array 匹配到的标签 $content string 文本内容 */ protected function _var($tag, $content) { foreach ($tag[1] as $v) { if (array_key_exists($v, $this->_var)) { //对数据普通变量进行匹配 $content = preg_replace('/\\' . $this->left_delimiter . '\$' . $v . '\\' . $this->right_delimiter . '/', '<?php echo $this->_var["' . $v .'"]; ?>', $content); } } return $content; } /* include标签 example: {include file=type.css type=css /} notice: 可以引入多个文件{include file=type.css my.css type=css /} */ protected function _include($content) { //替换单个文件 $content = preg_replace('/\\' . $this->left_delimiter . 'include\s+file\=([a-zA_Z0-9_\.\/\:]+)\s+type\=css\s+\/\\' . $this->right_delimiter . '/i', '<style rel="stylesheet" type="text/css" href="\1"></style>', $content); //替换多个文件 if (preg_match_all('/\\' . $this->left_delimiter . 'include\s+file\=([a-zA_Z0-9_\.\:]+\,){1,}[a-zA_Z0-9_\.\:]+\s+type\=css\s+\/\\' . $this->right_delimiter . '/i', $content, $res)) { $include = ''; foreach ($res[0] as $r) { $str[] = substr($r, 13, -11); } foreach ($str as $s) { $arr = explode(',', $s); foreach ($arr as $a) { $include .= '<style rel="stylesheet" tpye="text/css" href="' . $a .'"></style>'; } } $content = preg_replace('/\\' . $this->left_delimiter . 'include\sfile\=([a-zA_Z0-9_\.\:]+\,){1,}[a-zA_Z0-9_\.\:]+\stype\=css\s\/\\' . $this->right_delimiter . '/i', $include, $content); } return $content; } /* insert标签 example: {insert file=type.js type=js /} notice: 可以引入多个文件 */ function _insert($content) { //引入单个文件 $content = preg_replace('/\\' . $this->left_delimiter . 'insert\sfile\=([a-zA-Z0-9_\.\:]+)\stype\=javascript\s\/\\' . $this->right_delimiter . '/i', '<script type="text/javascript" src="\1"></script>', $content); //引入多个文件 if (preg_match_all('/\\' . $this->left_delimiter . 'insert\sfile\=([a-zA-Z0-9_\.\:]+\,){1,}[a-zA_Z0-9_\.\:]+\stype\=javascript\s\/\\' . $this->right_delimiter . '/i', $content, $res)) { $insert = ''; foreach ($res[0] as $r) { $str[] = substr($r, 13, -18); } foreach ($str as $s) { $arr = explode(',', $s); foreach ($arr as $a) { $insert .= '<script type="text/javascript" src="' . $a . '"></script>'; } } $content = preg_replace('/\\' . $this->left_delimiter . 'insert\sfile\=([a-zA-Z0-9_\.\:]+\,){1,}[a-zA_Z0-9_\.\:]+\stype\=javascript\s\/\\' . $this->right_delimiter . '/i', $insert, $content); } return $content; } /* for循环标签 example: {for star=0 stop=100 step=1}循环体{$start}{/for}----{$start}为模板引擎关键词$i, 请勿在for标签循环体外使用 notice: 只默认一层循环, 最多支持两层循环, 可在标签规则中设定level级别 *****************双层for标签不支持********************** 单层标签如果使用$i(初始变量) {for start=[$i=0] stop=100 step=1}{/for} */ protected function _for($content) { /* 解析顺序: 从多到少解析, 防止解析冲突 notice: 标签嵌套初始值, 最终值, 步长请自定义, 没有配置level默认只解析一层标签 */ //解析双层for标签 if ($this->tag['for']['level'] == 2) { if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=[0-9]+\s+stop\=[0-9_]+\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . 'for\s+start\=[0-9]+\s+stop\=[0-9_]+\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '.*\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/(\{for\s+start\=([0-9]+)\s+stop\=([0-9_]+)\s+step\=([0-9]+)\}).*?(\{for\s+start\=([0-9]+)\s+stop\=([0-9_]+)\s+step\=([0-9]+)\}).*?\{\/for\}.*?\{\/for\}/i', $content, $res); //解析for标签 foreach ($res[1] as $k => $v) { $content = str_replace($v, '<?php for($i=' . $res[2][$k] . ';$i<' . $res[3][$k] . ';$i=$i+' . $res[4][$k] . '){ ?>', $content); } } } /* 解析单层标签 */ if (preg_match('/\\' . $this->left_delimiter . 'for.*?\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/is', $content, $res)) { //默认单层标签循环10次 if (preg_match('/\\' . $this->left_delimiter . 'for\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/is', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\\' . $this->right_delimiter . '/is', '<?php for($i=' . $this->tag['for']['attr']['start'] . ';$i<' . $this->tag['for']['attr']['stop'] . ';$i++){ ?>', $content); } //只指定start if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for($i=\1;$i<' . $this->tag['for']['attr']['stop'] . ';$i++){ ?>', $content); } //只指定stop if (preg_match('/\\' . $this->left_delimiter . 'for\s+stop\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+stop\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for($i=' . $this->tag['for']['attr']['start'] . ';$i<\1;$i++){ ?>', $content); } //只指定step if (preg_match('/\\' . $this->left_delimiter . 'for\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+step=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for($i=' . $this->tag['for']['attr']['start'] . ';$i<' . $this->tag['for']['attr']['stop'] . ';$i=$i+\1){ ?>', $content); } //指定start, 并在循环体内调用start if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=\[\$[a-zA-Z_]+\=[0-9]+\]\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z_]+)\=([0-9]+)\]\\' . $this->right_delimiter . '/i', $content, $res); //先解析start foreach ($res[1] as $k => $v) { $content = str_replace($this->left_delimiter . $v . $this->right_delimiter, '<?php echo ' . $v . '; ?>', $content); } $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start=\[(\$[a-zA-Z_]+)\=([0-9]+)\]\\' . $this->right_delimiter . '/i', '<?php for(\1=\2;$1<' . $this->tag['for']['attr']['stop'] . ';\1++){ ?>', $content); } //指定start 和 stop if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=[0-9]+\s+stop\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\{for\s+start\=([0-9]+)\s+stop\=([0-9]+)\}/i', '<?php for($i=\1;$i<\2;$i++){ ?>', $content); } //指定start 和 step if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=[0-9]+\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start\=([0-9]+)\s+step\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for($i=\1;$i<' . $this->tag['for']['attr']['stop'] . ';$i=$i+\2){ ?>', $content); } //指定stop 和 step if (preg_match('/\\' . $this->left_delimiter . 'for\s+stop\=[0-9]+\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+stop\=([0-9]+)\s+step\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for($i=' . $this->tag['for']['attr']['start'] . ';$i<\1;$i=$i+\2){ ?>', $content); } //指定start 和 stop 并使用start变量 if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=\[\$[a-zA-Z_]+\=[0-9]+\]\s+stop\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z_]+)\=([0-9]+)\]\s+stop\=([0-9]+)\\' . $this->right_delimiter . '/i', $content, $res); foreach ($res[1] as $k => $v) { $content = str_replace($this->left_delimiter . $v . $this->right_delimiter, '<?php echo ' . $v .'; ?>', $content); } $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z_]+)\=([0-9]+)\]\s+stop\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for (\1=\2;\1<\3;\1++){ ?>', $content); } //指定start 和 step 并使用start变量 if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=\[\$[a-zA-Z_]+\=[0-9]+\]\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z_]+)\=([0-9]+)\]\s+step\=([0-9]+)\\' . $this->right_delimiter . '/is', $content, $res); foreach ($res[1] as $k => $v) { $content = str_replace($this->left_delimiter . $v . $this->right_delimiter, '<?php echo ' . $v .'; ?>', $content); } $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z_]+)\=([0-9]+)\]\s+step\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for (\1=\2;\1<' . $this->tag['for']['attr']['stop'] . ';\1=\1+\3){ ?>', $content); } //指定start stop step if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=[0-9]+\s+stop\=[0-9]+\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start\=([0-9]+)\s+stop\=([0-9]+)\s+step\=([0-9]+)\\' . $this->right_delimiter . '/i','<?php for($i=\1;$i<\2;$i=$i+\3){ ?>', $content); } //指定start 并调用$start if (preg_match('/\\' . $this->left_delimiter . 'for\s+start\=\[\$[a-zA-Z0-9]+\=[0-9]+\]\s+stop\=[0-9]+\s+step\=[0-9]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z0-9]+)\=([0-9]+)\]\s+stop\=([0-9]+)\s+step\=([0-9]+)\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/i', $content, $res); foreach ($res[1] as $k => $v) { $content = str_replace($this->left_delimiter . $v . $this->right_delimiter, '<?php echo ' . $v .'; ?>', $content); } $content = preg_replace('/\\' . $this->left_delimiter . 'for\s+start\=\[(\$[a-zA-Z0-9]+)\=([0-9]+)\]\s+stop\=([0-9]+)\s+step\=([0-9]+)\\' . $this->right_delimiter . '/i', '<?php for(\1=\2;\1<\3;\1=\1+\4){ ?>', $content); } } //解析所有for标签结束标签 $content = preg_replace('/\\' . $this->left_delimiter . '\/for\\' . $this->right_delimiter . '/is', '<?php } ?>', $content); return $content; } /* 二维数组解析 foreach 标签 example: {foreach from=$arr key=$key item=$value}({$value.value} or {$value.0(下标)}){key.$key}{/foreach} or {foreac from=$arr item=$value}{$value.value}{/foreach} notice: 标签可以嵌套, 默认最多嵌套三层(请注意key标签的用法) */ protected function _foreach($content) { /* 解析顺序: 从多到少解析, 防止解析冲突 notice: 标签嵌套不解析$key, 没有配置level默认最多解析双层标签 */ if ($this->tag['foreach']['level'] == 3) { //解析三层标签 if ( preg_match('/(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-z-A-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-z-A-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-z-A-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . ')/i', $content, $res)) { preg_match_all('/(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-z-A-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-z-A-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-z-A-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . ')/i', $content, $res); if (array_key_exists($res[2][0], $this->_var)) { foreach ($res[1] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[2][$k] .'"] as ' . $res[3][$k] . '){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } if (array_key_exists($res[5][0], $this->_var)) { foreach ($res[4] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[5][$k] .'"] as ' . $res[6][$k] . '){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } if (array_key_exists($res[8][0], $this->_var)) { foreach ($res[7] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[8][$k] .'"] as ' . $res[9][$k] . '){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } } } //解析双层标签 if (preg_match('/\\' . $this->left_delimiter . 'foreach\s+from\=\$[a-zA-Z0-9_]+\s+item\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . 'foreach\s+from\=\$[a-zA-Z0-9_]+\s+item\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-zA-Z0-9_]+)\\' . $this->right_delimiter . ').*?(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-zA-Z0-9_]+)\\' . $this->right_delimiter . ').*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $res); if (array_key_exists($res[2][0], $this->_var)) { foreach ($res[1] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[2][$k] . '"] as ' . $res[3][$k] . '){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } if (array_key_exists($res[5][0], $this->_var)) { foreach ($res[4] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[5][$k] . '"] as ' . $res[6][$k] . '){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } } /* 解析单层标签 */ //无$key时 if (preg_match('/\\' . $this->left_delimiter . 'foreach\s+from\=\$[a-zA-Z0-9_]+\s+item\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9_]+)\s+item\=(\$[a-zA-Z0-9_]+)\\' . $this->right_delimiter . ').*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $res); if (array_key_exists($res[2][0], $this->_var)) { foreach ($res[1] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[2][$k] .'"] as ' . $res[3][$k] . '){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } } //有$key时 if (preg_match('/\\' . $this->left_delimiter . 'foreach\s+from\=\$[a-zA-Z0-9]+\s+key\=\$[a-zA-Z0-9_]+\s+item\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $res)) { preg_match_all('/(\\' . $this->left_delimiter . 'foreach\s+from\=\$([a-zA-Z0-9]+)\s+key\=(\$[a-zA-Z0-9_]+)\s+item\=(\$[a-zA-Z0-9_]+)\\' . $this->right_delimiter . ').*?\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', $content, $res); if (array_key_exists($res[2][0], $this->_var)) { foreach ($res[1] as $k => $v) { $content = str_replace($v, '<?php foreach ($this->_var["' . $res[2][$k] . '"] as ' . $res[3][$k] .'=>' . $res[4][$k] .'){ ?>', $content); } } else { return $this->tpl_exception('模板变量异常: value未定义, 错误行号: ' . __LINE__); } //解析标签中的{key.$key} 键值 if (preg_match('/\\' . $this->left_delimiter . 'key\.\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/is', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'key\.(\$[a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php echo \1; ?>', $content); } } //解析标签中的数组变量 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\.[a-zA-Z0-9]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . '(\$[a-zA-Z0-9_]+)\.([a-zA-Z0-9]+)\\' . $this->right_delimiter . '/i', '<?php echo \1["\2"]; ?>', $content); } //解析闭合标签{/foreach} $content = preg_replace('/\\' . $this->left_delimiter . '\/foreach\\' . $this->right_delimiter . '/i', '<?php } ?>', $content); return $content; } /* if标签 example: {if $value(!$value)}{/if} {if $value(!$value)}{elseif}{/if} {if $value}{else}{/if} notice: 默认最多支持两层嵌套 */ protected function _if($content) { /* 解析顺序: 先解析{if} 再解析{elseif} 最后解析{/if}*/ /* notice: if条件中可放入一维数组的键值形式 */ /* {if}标签 */ //{if $value}, $value为普通变量 if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]){ ?>', $content); } //{if !$value} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\!\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\!\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if(!$this->_var["\1"]){ ?>', $content); } //{if $value[key]}, 放入普通一维数组 if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]["\2"]){ ?>', $content); } //{if !$value[key]} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\!\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\!\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/is', '<?php if(!$this->_var["\1"]["\2"]){ ?>', $content); } /* 条件比较只支持普通变量比较, 如果要进行一维数组比较, 可在模板赋值时, 直接传入具体数组值 */ //{if $value1==$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\=\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\=\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]==$this->_var["\2"]){ ?>', $content); } //{if $value1!=$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\!\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\!\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]!=$this->_var["\2"]){ ?>', $content); } //{if $value1===$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\=\=\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\=\=\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]===$this->_var["\2"]){ ?>', $content); } //{if $value1!==$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\!\=\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\!\=\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]!==$this->_var["\2"]){ ?>', $content); } //{if $value1!>$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\>\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/is', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\>\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]>$this->_var["\2"]){ ?>', $content); } //{if $value1!>=$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\>\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\>\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]>=$this->_var["\2"]){ ?>', $content); } //{if $value1<$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\<\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\<\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]<$this->_var["\2"]){ ?>', $content); } //{if $value1<=$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\<\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\<\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"]<=$this->_var["\2"]){ ?>', $content); } /* if多条件判断 notice 多条件判断只支持普通变量, 不支持数组, 多条件判断目前最多支持两个条件, 不支持比较运算 */ //&&运算 //{if $value1 and $value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\s+and\s+\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\s+and\s+\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"] && $this->_var["\2"]){ ?>', $content); } //{if !$value1 and !$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\!\$[a-zA-Z0-9_]+\s+and\s+\!\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\!\$([a-zA-Z0-9_]+)\s+and\s+\!\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if(!$this->_var["\1"] && !$this->_var["\2"]){ ?>', $content); } //{if $value1 and !$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\s+and\s+\!\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\s+and\s+\!\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"] && !$this->_var["\2"]){ ?>', $content); } //{if !$value1 and $value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\!\$[a-zA-Z0-9_]+\s+and\s+\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\!\$([a-zA-Z0-9_]+)\s+and\s+\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if(!$this->_var["\1"] && $this->_var["\2"]){ ?>', $content); } //||运算 //{if $value1 or $value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\s+or\s+\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\$([a-zA-Z0-9_]+)\s+or\s+\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"] || $this->_var["\2"]){ ?>', $content); } //{if !$value1 or !$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\!\$[a-zA-Z0-9_]+\s+or\s+\!\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\!\$([a-zA-Z0-9_]+)\s+or\s+\!\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if(!$this->_var["\1"] || !$this->_var["\2"]){ ?>', $content); } //{if $value1 or !$value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\$[a-zA-Z0-9_]+\s+or\s+\!\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . '{if\s+\$([a-zA-Z0-9_]+)\s+or\s+\!\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if($this->_var["\1"] || !$this->_var["\2"]){ ?>', $content); } //{if !$value1 or $value2} if (preg_match('/\\' . $this->left_delimiter . 'if\s+\!\$[a-zA-Z0-9_]+\s+or\s+\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'if\s+\!\$([a-zA-Z0-9_]+)\s+or\s+\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php if(!$this->_var["\1"] || $this->_var["\2"]){ ?>', $content); } /* 解析{elseif标签} */ //{elseif $value}, $value为普通变量 if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]){ ?>', $content); } //{elseif !$value} if (preg_match('/\\' . $this->left_delimiter . '}elseif\s+\!\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\!\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php elseif(!$this->_var["\1"]){ ?>', $content); } //{elseif $value[key]}, 放入普通一维数组 if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]["\2"]){ ?>', $content); } //{elseif !$value[key]} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\!\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\!\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', '<?php }elseif(!$this->_var["\1"]["\2"]){ ?>', $content); } /* 条件比较只支持普通变量比较, 如果要进行一维数组比较, 可在模板赋值时, 直接传入具体数组值 */ //{elseif $value1==$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\=\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/is', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\=\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]==$this->_var["\2"]){ ?>', $content); } //{elseif $value1!=$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\!\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\!\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]!=$this->_var["\2"]){ ?>', $content); } //{elseif $value1===$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\=\=\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\=\=\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php elseif($this->_var["\1"]===$this->_var["\2"]){ ?>', $content); } //{elseif $value1!==$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\!\=\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\!\=\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]!==$this->_var["\2"]){ ?>', $content); } //{elseif $value1!>$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\>\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\>\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]>$this->_var["\2"]){ ?>', $content); } //{elseif $value1!>=$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\>\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\>\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]>=$this->_var["\2"]){ ?>', $content); } //{elseif $value1<$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\<\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/is', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\<\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]<$this->_var["\2"]){ ?>', $content); } //{elseif $value1<=$value2} if (preg_match('/\\' . $this->left_delimiter . 'elseif\s+\$[a-zA-Z0-9_]+\<\=\$[a-zA-Z0-9_]+\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . 'elseif\s+\$([a-zA-Z0-9_]+)\<\=\$([a-zA-Z0-9_]+)\\' . $this->right_delimiter . '/i', '<?php }elseif($this->_var["\1"]<=$this->_var["\2"]){ ?>', $content); } /* else标签解析 */ if (preg_match('/\{else\}/', $content, $res)) { $content = preg_replace('/\{else\}/', '<?php }else{ ?>', $content); } //解析{/if}标签结束符 if (preg_match('/\\' . $this->left_delimiter . '\/if\\' . $this->right_delimiter . '/is', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . '\/if\\' . $this->right_delimiter . '/', '<?php } ?>', $content); } //print_r($content);die; return $content; } /* 普通一维数组变量 example: {$content[value]} */ protected function _array_var($content) { $content = preg_replace('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', '<?php echo $this->_var["\1"]["\2"]; ?>', $content); return $content; } /* cache标签: 可实现局部缓存 example: {cache}缓存内容{/cache} */ protected function _cache($content) { if (preg_match_all('/\{cache\}(.*)?\{\/cache\}/iU', $content, $res)) { $cache = ''; foreach ($res[1] as $v) { $cache .= $this->_eval($v); } } return preg_replace('/\{cache\}.*?\{\/cache\}/i', $cache, $content); } /* session标签 example: {$_SESSION[key]} */ protected function _session($content) { return preg_replace('/\\' . $this->left_delimiter . '\$_SESSION\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', '<?php echo $_SESSION["\1"]; ?>', $content); } /* cookie标签 example: {$_COOKIE[key]} */ protected function _cookie($content) { return preg_replace('/\\' . $this->left_delimiter . '\$_COOKIE\[([a-zA-Z0-9_]+)\]\\' . $this->right_delimiter . '/i', '<?php echo $_COOKIE["\1"]; ?>', $content); } /* captcha验证码标签 example: {captcha /} or {captcha type=img /} notice: 为了保证静态页面也能使用, 这里采用绝对路径, 可换成域名 */ protected function _captcha($content) { if (preg_match('/\{captcha\s+\/\}/i', $content, $res)) { $content = preg_replace('/\{captcha\s+\/\}/i', '<img src="lib_captcha.php" οnclick=this.src="lib_captcha.php?"+Math.random(); style="cursor:pointer"/>', $content); } if (preg_match('/\{captcha\s+type\=img\s+\/\}/i', $content, $res)) { $content = preg_replace('/\{captcha\s+type\=img\s+\/\}/i', '<img src="lib_captcha.php?type=img" οnclick=this.src="lib_captcha.php?type=img&"+Math.random(); style="cursor:pointer"/>', $content); } return $content; } /* ***************************************** ***************************************** 系统函数标签 ***************************************** ***************************************** */ /* substr标签, 字符串截取 example: {$value: _substr(1,2)} */ protected function _substr($content) { //普通变量截取 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\:\s+_substr\([0-9]+\,\s{0,}[0-9]+\)\\' . $this->right_delimiter . '/i', $content, $res)) { if ($this->tpl_char == 'utf-8') { $content = preg_replace('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\:\s+_substr\(([0-9]+)\,\s{0,}([0-9]+)\)\\' . $this->right_delimiter . '/i', '<?php echo substr($this->_var["\1"],\2,\3*3) . "..."; ?>', $content); } else { $content = preg_replace('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\:\s+_substr\(([0-9]+)\,\s{0,}([0-9]+)\)\\' . $this->right_delimiter . '/i', '<?php echo substr($this->_var["\1"],\2,\3*2) . "..."; ?>', $content); } } //foreach中数组变量截取 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\:\s+_substr\([0-9]+\,\s{0,}[0-9]+\)\\' . $this->right_delimiter . '/i', $content, $res)) { if ($this->tpl_char == 'utf-8') { $content = preg_replace('/\\' . $this->left_delimiter . '(\$[a-zA-Z0-9_]+)\.([a-zA-Z0-9_]+)\:\s+_substr\(([0-9]+)\,\s{0,}([0-9]+)\)\\' . $this->right_delimiter . '/i', '<?php echo substr(\1["\2"],\3,\4*3) . "..."; ?>', $content); } else { $content = preg_replace('/\\' . $this->left_delimiter . '(\$[a-zA-Z0-9_]+)\.([a-zA-Z0-9_]+)\:\s+_substr\(([0-9]+)\,\s{0,}([0-9]+)\)\\' . $this->right_delimiter . '/i', '<?php echo substr(\1["\2"],\3,\4*2) . "..."; ?>', $content); } } //一维数组变量截取 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\:\s+_substr\([0-9]+\,\s{0,}[0-9]+\)\\' . $this->right_delimiter . '/i', $content, $res)) { if ($this->tpl_char == 'utf-8') { $content = preg_replace('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\:\s+_substr\(([0-9]+)\,\s{0,}([0-9]+)\)\\' . $this->right_delimiter . '/i', '<?php echo substr($this->_var["\1"]["\2"],\3,\4*3) . "..."; ?>', $content); } else { $content = preg_replace('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\:\s+_substr\([0-9]+\,\s{0,}[0-9]+\)\\' . $this->right_delimiter . '/i', '<?php echo substr($this->_var["\1"]["\2"],\3,\4*2) . "..."; ?>', $content); } } return $content; } /* ucfirst, strtolower, strtoupper标签, 字符串首字母大写 example: {$value: _ucfirst()} */ protected function english_str($content, $type = 'ucfirst') { //普通变量 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\:\s+_ucfirst\(\)\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\:\s+_' . $type . '\(\)\\' . $this->right_delimiter . '/i', '<?php echo ' . $type . '($this->_var["\1"]); ?>', $content); } //foreach中数组变量 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\:\s+_' . $type . '\(\)\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . '(\$[a-zA-Z0-9_]+)\.([a-zA-Z0-9_]+)\:\s+_' . $type . '\(\)\\' . $this->right_delimiter . '/i', '<?php echo ' . $type . '(\1["\2"]); ?>', $content); } //普通一维数组 if (preg_match('/\\' . $this->left_delimiter . '\$[a-zA-Z0-9_]+\[[a-zA-Z0-9_]+\]\:\s+_' . $type . '\(\)\\' . $this->right_delimiter . '/i', $content, $res)) { $content = preg_replace('/\\' . $this->left_delimiter . '\$([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]\:\s+_' . $type . '\(\)\\' . $this->right_delimiter . '/i', '<?php echo ' . $type . '($this->_var["\1"]["\2"]); ?>', $content); } return $content; } /* date:当前日期格式化函数标签 example: {_date()} */ protected function _date($content) { return preg_replace('/\\' . $this->left_delimiter . '_date\(\)\\' . $this->right_delimiter . '/i', '<?php echo date("Y-m-d H:i:s"); ?>', $content); } /* ******************************** ******************************** 模板插件函数调用功能 ******************************** ******************************** */ protected function _function($content) { include ($this->tpl_plugins_file); return preg_replace('/\\' . $this->left_delimiter . 'function\:\s+([a-zA-Z0-9]+\(\))\\' . $this->right_delimiter . '/i', '<?php function_\1; ?>', $content); } /* ******************************** ******************************** 自定义扩展标签 ******************************** ******************************** */ protected function _extends($content) { include ($this->tag_extends_file); return preg_replace('/\\' . $this->left_delimiter . '(extends\:\s+([a-zA-Z0-9]+))\\' . $this->right_delimiter . '.*?\\' . $this->left_delimiter . '(\/extends\:\s+[a-zA-Z0-9]+)\\' . $this->right_delimiter . '/i', '<?php extends_\2("\1","\3"); ?>', $content); } /* ********************************* ********************************* 缓存控制 ********************************* ********************************* */ /* 清除某个页面的静态文件 */ function clear_static_cache($file) { return @unlink($this->cache_dir . $file . $this->tpl_suffix); } /* 清除编译缓存文件 */ function clear_make_cache($file) { $make_name = $this->cpl_prefix . md5($this->compile_dir . $file) . '.php'; $make = $this->compile_dir . $make_name; return @unlink($make); } /* 清除所有缓存 @type static 默认清除静态文件 make 清除编译文件 */ function clear_all_cache($type = 'static') { if ($type == 'static') $dir = $this->cache_dir; elseif ($type == 'make') $dir = $this->compile_dir; if (is_dir($dir)) { $d = opendir($dir); $filename = array(); while(($file = readdir($d)) !== false) { if ($file != '.' && $file != '..') { $filename[] = $file; } } } foreach ($filename as $f) { if ($type == 'static') @unlink($this->cache_dir . $f); elseif ($type == 'make') @unlink($this->compile_dir . $f); } return true; } /* ************************************ ************************************ 模板表单安全处理 ************************************ ************************************ */ /* 表单随机码生成, 防止跨域提交 */ protected function _hash($content) { if (preg_match('/<form.*?>.*?<\/form>/', $content, $form)) { preg_match_all('/(<form.*?>)(.*?)<\/form>/', $content, $form); $str = array(); foreach ($form[1] as $k => $f) { $str[] = $f . $form[2][$k] . '<input type="hidden" value="<?php echo $this->form_hash; ?>"></form>'; } foreach ($form[0] as $k => $f) { $content = str_replace($f, $str[$k], $content); } $_SESSION['__HASH__'] = $this->form_hash; return $content; } return $content; } } ?>