From 71dbdcb8742e109906e2ada91660fb4da6e54e43 Mon Sep 17 00:00:00 2001 From: oldrind <1401019000@qq.com> Date: Fri, 11 Mar 2016 21:58:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E4=BB=A3=E9=83=A8=E5=88=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=9Bblock=E6=A0=87=E7=AD=BE=E5=86=85=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E4=BD=BF=E7=94=A8{=5F=5Fblock=5F=5F}=E6=9D=A5?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E6=89=80=E7=BB=A7=E6=89=BF=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E4=B8=AD=E7=9B=B8=E5=BA=94block=E6=A0=87=E7=AD=BE=E7=9A=84?= =?UTF-8?q?=E5=86=85=E5=AE=B9=EF=BC=9B=20=E6=A8=A1=E6=9D=BF=E5=8C=85?= =?UTF-8?q?=E5=90=AB=E6=96=87=E4=BB=B6=E8=AE=B0=E5=BD=95=E5=8F=8A=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=97=B6=E9=97=B4=E7=9B=B4=E6=8E=A5=E5=86=99=E5=85=A5?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E7=9A=84=E6=A8=A1=E6=9D=BF=E4=B8=AD=EF=BC=9B?= =?UTF-8?q?=E6=94=B9=E8=BF=9B=E6=A0=87=E7=AD=BE=E5=88=AB=E5=90=8D=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=88=AB=E5=90=8D?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E5=AE=9A=E4=B9=89=E6=96=B9=E6=B3=95=EF=BC=9B?= =?UTF-8?q?=20=E5=8E=BB=E9=99=A4include=E6=A0=87=E7=AD=BE=E4=BC=A0?= =?UTF-8?q?=E5=8F=82=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81=EF=BC=9Bcx=E7=B1=BB=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0function=E6=96=B9=E6=B3=95=EF=BC=8C=E7=94=A8=E6=9D=A5?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=8C=BF=E5=90=8D=E5=87=BD=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E7=BB=93=E5=90=88{~$=E5=87=BD=E6=95=B0=E5=90=8D()}=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E9=80=92=E5=BD=92=E7=9A=84=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/think/Template.php | 303 +++++++++--------- library/think/template/TagLib.php | 149 +++------ library/think/template/driver/File.php | 29 +- library/think/template/driver/Sae.php | 30 +- library/think/template/taglib/Cx.php | 230 ++++++------- tests/thinkphp/library/think/extend.html | 4 +- tests/thinkphp/library/think/extend2.html | 3 +- .../library/think/template/taglib/cxTest.php | 29 +- tests/thinkphp/library/think/templateTest.php | 26 +- 9 files changed, 390 insertions(+), 413 deletions(-) diff --git a/library/think/Template.php b/library/think/Template.php index 0c5cdc6b..9c6985ee 100644 --- a/library/think/Template.php +++ b/library/think/Template.php @@ -52,7 +52,6 @@ class Template private $literal = []; private $includeFile = []; // 记录所有模板包含的文件路径及更新时间 - private $md5Key = ''; // 保存当前模板的md5码 protected $storage = null; /** @@ -118,7 +117,7 @@ class Template /** * 模板引擎配置项 * @access public - * @param array $config + * @param array|string $config * @return void|array */ public function config($config) @@ -146,7 +145,7 @@ class Template if (isset($data[$val])) { $data = $data[$val]; } else { - $data = false; + $data = null; break; } } @@ -172,7 +171,7 @@ class Template } $template = $this->parseTemplateFile($template); $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($template) . $this->config['cache_suffix']; - if (!$this->checkCache($template, $cacheFile)) { + if (!$this->checkCache($cacheFile)) { // 缓存无效 重新模板编译 $content = file_get_contents($template); $this->compiler($content, $cacheFile); @@ -204,7 +203,7 @@ class Template $this->data = $vars; } $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($content) . $this->config['cache_suffix']; - if (!$this->checkCache($content, $cacheFile)) { + if (!$this->checkCache($cacheFile)) { // 缓存无效 模板编译 $this->compiler($content, $cacheFile); } @@ -235,30 +234,27 @@ class Template * 检查编译缓存是否有效 * 如果无效则需要重新编译 * @access private - * @param string $template 模板文件名 * @param string $cacheFile 缓存文件名 * @return boolean */ - private function checkCache($template, $cacheFile) + private function checkCache($cacheFile) { if (!$this->config['tpl_cache']) { // 优先对配置设定检测 return false; } - $this->md5Key = md5($template); - $recordFile = $this->config['cache_path'] . md5($this->config['cache_record_file']) . $this->config['cache_suffix']; - if (!is_file($recordFile)) { - return false; - } else { - $this->includeFile = $this->storage->read($recordFile, [], true); - if (!isset($this->includeFile[$this->md5Key])) { - // 缓存记录中无此模板 - return false; - } else { - // 检查编译存储是否有效 - return $this->storage->check($this->includeFile[$this->md5Key], $cacheFile, $this->config['cache_time']); + if (is_file($cacheFile)) { + $handle = @fopen($cacheFile, "r"); + if ($handle) { + preg_match('/\/\*(.+?)\*\//', fgets($handle), $matches); + if (isset($matches[1])) { + $this->includeFile = unserialize($matches[1]); + // 检查编译存储是否有效 + return $this->storage->check($this->includeFile, $cacheFile, $this->config['cache_time']); + } } } + return false; } /** @@ -298,7 +294,7 @@ class Template // 替换布局的主体内容 $content = str_replace($this->config['layout_item'], $content, file_get_contents($layoutFile)); // 记录布局文件的更新时间 - $this->includeFile[$this->md5Key][filemtime($layoutFile)] = $layoutFile; + $this->includeFile[filemtime($layoutFile)] = $layoutFile; } else { throw new Exception('template not exist:' . $layoutFile, 10700); } @@ -307,8 +303,6 @@ class Template // 模板解析 $this->parse($content); - // 添加安全代码 - $content = '' . $content; if ($this->config['strip_space']) { /* 去除html空格与换行 */ $find = ['~>\s+<~', '~>(\s+\n|\r)~']; @@ -320,11 +314,10 @@ class Template // 模板过滤输出 $replace = $this->config['tpl_replace_string']; $content = str_replace(array_keys($replace), array_values($replace), $content); + // 添加安全代码及模板引用记录 + $content = 'includeFile) . '*/ ?>' . "\n" . $content; // 编译存储 $this->storage->write($cacheFile, $content); - // 保存模板更新记录 - $string = "includeFile, true) . ';'; - $this->storage->write($this->config['cache_path'] . md5($this->config['cache_record_file']) . $this->config['cache_suffix'], $string); $this->includeFile = []; return; } @@ -429,7 +422,7 @@ class Template // 替换布局的主体内容 $content = str_replace($replace, $content, file_get_contents($layoutFile)); // 记录布局文件的更新时间 - $this->includeFile[$this->md5Key][filemtime($layoutFile)] = $layoutFile; + $this->includeFile[filemtime($layoutFile)] = $layoutFile; } } } else { @@ -446,8 +439,8 @@ class Template */ private function parseInclude(&$content) { - $regex = $this->getRegex('include'); - $funReplace = function ($template) use (&$funReplace, &$regex, &$content) { + $regex = $this->getRegex('include'); + $func = function ($template) use (&$func, &$regex, &$content) { if (preg_match_all($regex, $template, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $array = $this->parseAttr($match[0]); @@ -455,28 +448,22 @@ class Template unset($array['file']); // 分析模板文件名并读取内容 $parseStr = $this->parseTemplateName($file); - // 替换变量 - $varStr = ""; foreach ($array as $k => $v) { // 以$开头字符串转换成模板变量 if (0 === strpos($v, '$')) { $v = $this->get(substr($v, 1)); } - // 兼容 [var_name] 静态渲染 $parseStr = str_replace('[' . $k . ']', $v, $parseStr); - // 支持 $var_name = value 动态赋值 - $varStr .= "{assign name=\"{$k}\" value=\"{$v}\" /}"; } - $parseStr = $varStr . $parseStr; $content = str_replace($match[0], $parseStr, $content); // 再次对包含文件进行模板分析 - $funReplace($parseStr); + $func($parseStr); } unset($matches); } }; // 替换模板中的include标签 - $funReplace($content); + $func($content); return; } @@ -489,23 +476,23 @@ class Template private function parseExtend(&$content) { $regex = $this->getRegex('extend'); - $array = $blocks = $extBlocks = []; + $array = $blocks = $baseBlocks = []; $extend = ''; - $fun = function ($template) use (&$fun, &$regex, &$array, &$extend, &$blocks, &$extBlocks) { + $func = function ($template) use (&$func, &$regex, &$array, &$extend, &$blocks, &$baseBlocks) { if (preg_match($regex, $template, $matches)) { if (!isset($array[$matches['name']])) { $array[$matches['name']] = 1; // 读取继承模板 $extend = $this->parseTemplateName($matches['name']); // 递归检查继承 - $fun($extend); + $func($extend); // 取得block标签内容 $blocks = array_merge($blocks, $this->parseBlock($template)); return; } } else { // 取得顶层模板block标签内容 - $extBlocks = $this->parseBlock($template); + $baseBlocks = $this->parseBlock($template, true); if (empty($extend)) { // 无extend标签但有block标签的情况 $extend = $template; @@ -513,15 +500,36 @@ class Template } }; - $fun($content); + $func($content); if (!empty($extend)) { - if ($extBlocks) { - foreach ($extBlocks as $name => $v) { - $replace = isset($blocks[$name]) ? $blocks[$name]['content'] : $v['content']; - $extend = str_replace($v['begin']['tag'] . $v['content'] . $v['end']['tag'], $replace, $extend); + if ($baseBlocks) { + $children = []; + foreach ($baseBlocks as $name => $val) { + $replace = $val['content']; + if (!empty($children[$name])) { + // 如果包含有子block标签 + foreach ($children[$name] as $key) { + $replace = str_replace($baseBlocks[$key]['begin'] . $baseBlocks[$key]['content'] . $baseBlocks[$key]['end'], $blocks[$key]['content'], $replace); + } + } + // 带有{__block__}表示与所继承模板的相应标签合并,而不是覆盖 + $replace = !isset($blocks[$name]) ? $replace : str_replace(['{__BLOCK__}', '{__block__}'], $replace, $blocks[$name]['content']); + if (!empty($val['parent'])) { + // 如果不是最顶层的block标签 + $parent = $val['parent']; + if (isset($blocks[$parent])) { + $blocks[$parent]['content'] = str_replace($blocks[$name]['begin'] . $blocks[$name]['content'] . $blocks[$name]['end'], $replace, $blocks[$parent]['content']); + } + $blocks[$name]['content'] = $replace; + $children[$parent][] = $name; + } else { + // 替换模板中的block标签 + $extend = str_replace($val['begin'] . $val['content'] . $val['end'], $replace, $extend); + } } } $content = $extend; + unset($blocks, $baseBlocks); } return; } @@ -540,18 +548,18 @@ class Template if (!$restore) { $count = count($this->literal); // 替换literal标签 - foreach ($matches as $i => $match) { + foreach ($matches as $match) { $this->literal[] = substr($match[0], strlen($match[1]), -strlen($match[2])); $content = str_replace($match[0], "", $content); $count++; } } else { // 还原literal标签 - foreach ($matches as $i => $match) { - $content = str_replace($match[0], $this->literal[$i], $content); + foreach ($matches as $match) { + $content = str_replace($match[0], $this->literal[$match[1]], $content); } - // 销毁literal记录 - unset($this->literal); + // 清空literal记录 + $this->literal = []; } unset($matches); } @@ -562,31 +570,31 @@ class Template * 获取模板中的block标签 * @access private * @param string $content 模板内容 + * @param boolean $sort 是否排序 * @return array */ - private function parseBlock(&$content) + private function parseBlock(&$content, $sort = false) { $regex = $this->getRegex('block'); - $array = []; + $result = []; if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { $right = $keys = []; foreach ($matches as $match) { if (empty($match['name'][0])) { - if (!empty($right)) { - $begin = array_pop($right); - $end = ['offset' => $match[0][1], 'tag' => $match[0][0]]; - $start = $begin['offset'] + strlen($begin['tag']); - $len = $end['offset'] - $start; - $array[$begin['name']] = [ - 'begin' => $begin, - 'content' => substr($content, $start, $len), - 'end' => $end, + if (count($right) > 0) { + $tag = array_pop($right); + $start = $tag['offset'] + strlen($tag['tag']); + $length = $match[0][1] - $start; + $result[$tag['name']] = [ + 'begin' => $tag['tag'], + 'content' => substr($content, $start, $length), + 'end' => $match[0][0], + 'parent' => count($right) ? end($right)['name'] : '', ]; - $keys[] = $begin['offset']; - } else { - continue; + $keys[$tag['name']] = $match[0][1]; } } else { + // 标签头压入栈 $right[] = [ 'name' => $match[2][0], 'offset' => $match[0][1], @@ -595,10 +603,12 @@ class Template } } unset($right, $matches); - // 按blocks标签在模板中的位置排序 - array_multisort($keys, $array); + if ($sort) { + // 按block标签结束符在模板中的位置排序 + array_multisort($keys, $result); + } } - return $array; + return $result; } /** @@ -703,37 +713,37 @@ class Template } elseif (')' == substr($name, -1, 1)) { // $name为对象或是自动识别,或者含有函数 switch ($first) { - case '?': - $str = ''; - break; - case '=': - $str = ''; - break; - default: - $str = ''; + case '?': + $str = ''; + break; + case '=': + $str = ''; + break; + default: + $str = ''; } } else { // $name为数组 switch ($first) { - case '?': - // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx - $str = ''; - break; - case '=': - // {$varname?='xxx'} $varname为真时才输出xxx - $str = ''; - break; - case ':': - // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx - $str = ''; - break; - default: - if (strpos($str, ':')) { - // {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b - $str = ''; - } else { - $str = ''; - } + case '?': + // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx + $str = ''; + break; + case '=': + // {$varname?='xxx'} $varname为真时才输出xxx + $str = ''; + break; + case ':': + // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx + $str = ''; + break; + default: + if (strpos($str, ':')) { + // {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b + $str = ''; + } else { + $str = ''; + } } } } else { @@ -836,9 +846,10 @@ class Template return; } static $_varFunctionList = []; + $_key = md5($varStr); //如果已经解析过该变量字串,则直接返回变量值 - if (isset($_varFunctionList[$varStr])) { - $varStr = $_varFunctionList[$varStr]; + if (isset($_varFunctionList[$_key])) { + $varStr = $_varFunctionList[$_key]; } else { $varArray = explode('|', $varStr); // 取得变量名称 @@ -876,6 +887,7 @@ class Template } } } + $_varFunctionList[$_key] = $name; $varStr = $name; } return; @@ -988,7 +1000,7 @@ class Template // 获取模板文件内容 $parseStr .= file_get_contents($template); // 记录模板文件的更新时间 - $this->includeFile[$this->md5Key][filemtime($template)] = $template; + $this->includeFile[filemtime($template)] = $template; } } return $parseStr; @@ -1019,55 +1031,56 @@ class Template */ private function getRegex($tagName) { - $begin = $this->config['taglib_begin']; - $end = $this->config['taglib_end']; - $single = strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1 ? true : false; $regex = ''; - switch ($tagName) { - case 'block': - if ($single) { - $regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?[\w\/\:@,]+)\\1(?>[^' . $end . ']*)|\/' . $tagName . ')' . $end; - } else { - $regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?[\w\/\:@,]+)\\1(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end; - } - break; - case 'literal': - if ($single) { - $regex = '(' . $begin . $tagName . '\b(?>[^' . $end . ']*)' . $end . ')'; - $regex .= '(?:(?>[^' . $begin . ']*)(?>(?!' . $begin . '(?>' . $tagName . '\b[^' . $end . ']*|\/' . $tagName . ')' . $end . ')' . $begin . '[^' . $begin . ']*)*)'; - $regex .= '(' . $begin . '\/' . $tagName . $end . ')'; - } else { - $regex = '(' . $begin . $tagName . '\b(?>(?:(?!' . $end . ').)*)' . $end . ')'; - $regex .= '(?:(?>(?:(?!' . $begin . ').)*)(?>(?!' . $begin . '(?>' . $tagName . '\b(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end . ')' . $begin . '(?>(?:(?!' . $begin . ').)*))*)'; - $regex .= '(' . $begin . '\/' . $tagName . $end . ')'; - } - break; - case 'restoreliteral': - $regex = ''; - break; - case 'include': - $name = 'file'; - case 'taglib': - case 'layout': - case 'extend': - if (empty($name)) { - $name = 'name'; - } - if ($single) { - $regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?[\$\w\-\/\.\:@,\\\\]+)\\1(?>[^' . $end . ']*)' . $end; - } else { - $regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?[\$\w\-\/\.\:@,\\\\]+)\\1(?>(?:(?!' . $end . ').)*)' . $end; - } - break; - case 'tag': - $begin = $this->config['tpl_begin']; - $end = $this->config['tpl_end']; - if (strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1) { - $regex = $begin . '((?:[\$]{1,2}[a-wA-w_]|[\:\~][\$a-wA-w_]|[+]{2}[\$][a-wA-w_]|[-]{2}[\$][a-wA-w_]|\/[\*\/])(?>[^' . $end . ']*))' . $end; - } else { - $regex = $begin . '((?:[\$]{1,2}[a-wA-w_]|[\:\~][\$a-wA-w_]|[+]{2}[\$][a-wA-w_]|[-]{2}[\$][a-wA-w_]|\/[\*\/])(?>(?:(?!' . $end . ').)*))' . $end; - } - break; + if ('tag' == $tagName) { + $begin = $this->config['tpl_begin']; + $end = $this->config['tpl_end']; + if (strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1) { + $regex = $begin . '((?:[\$]{1,2}[a-wA-w_]|[\:\~][\$a-wA-w_]|[+]{2}[\$][a-wA-w_]|[-]{2}[\$][a-wA-w_]|\/[\*\/])(?>[^' . $end . ']*))' . $end; + } else { + $regex = $begin . '((?:[\$]{1,2}[a-wA-w_]|[\:\~][\$a-wA-w_]|[+]{2}[\$][a-wA-w_]|[-]{2}[\$][a-wA-w_]|\/[\*\/])(?>(?:(?!' . $end . ').)*))' . $end; + } + } else { + $begin = $this->config['taglib_begin']; + $end = $this->config['taglib_end']; + $single = strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1 ? true : false; + switch ($tagName) { + case 'block': + if ($single) { + $regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?[\$\w\-\/\.]+)\\1(?>[^' . $end . ']*)|\/' . $tagName . ')' . $end; + } else { + $regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?[\$\w\-\/\.]+)\\1(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end; + } + break; + case 'literal': + if ($single) { + $regex = '(' . $begin . $tagName . '\b(?>[^' . $end . ']*)' . $end . ')'; + $regex .= '(?:(?>[^' . $begin . ']*)(?>(?!' . $begin . '(?>' . $tagName . '\b[^' . $end . ']*|\/' . $tagName . ')' . $end . ')' . $begin . '[^' . $begin . ']*)*)'; + $regex .= '(' . $begin . '\/' . $tagName . $end . ')'; + } else { + $regex = '(' . $begin . $tagName . '\b(?>(?:(?!' . $end . ').)*)' . $end . ')'; + $regex .= '(?:(?>(?:(?!' . $begin . ').)*)(?>(?!' . $begin . '(?>' . $tagName . '\b(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end . ')' . $begin . '(?>(?:(?!' . $begin . ').)*))*)'; + $regex .= '(' . $begin . '\/' . $tagName . $end . ')'; + } + break; + case 'restoreliteral': + $regex = ''; + break; + case 'include': + $name = 'file'; + case 'taglib': + case 'layout': + case 'extend': + if (empty($name)) { + $name = 'name'; + } + if ($single) { + $regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?[\$\w\-\/\.\:@,\\\\]+)\\1(?>[^' . $end . ']*)' . $end; + } else { + $regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?[\$\w\-\/\.\:@,\\\\]+)\\1(?>(?:(?!' . $end . ').)*)' . $end; + } + break; + } } return '/' . $regex . '/is'; } diff --git a/library/think/template/TagLib.php b/library/think/template/TagLib.php index 036f20c5..254407ea 100644 --- a/library/think/template/TagLib.php +++ b/library/think/template/TagLib.php @@ -87,15 +87,15 @@ class TagLib public function parseTag(&$content, $lib = '') { $tags = []; + $_lib = $lib ? $lib . ':' : ''; foreach ($this->tags as $name => $val) { - $close = !isset($val['close']) || $val['close'] ? 1 : 0; - $_key = $lib ? $lib . ':' . $name : $name; - $tags[$close][$_key] = $name; + $close = !isset($val['close']) || $val['close'] ? 1 : 0; + $tags[$close][$_lib . $name] = $name; if (isset($val['alias'])) { // 别名设置 - foreach (explode(',', $val['alias']) as $v) { - $_key = $lib ? $lib . ':' . $v : $v; - $tags[$close][$_key] = $v; + $array = (array) $val['alias']; + foreach (explode(',', $array[0]) as $v) { + $tags[$close][$_lib . $v] = $name; } } } @@ -117,8 +117,6 @@ class TagLib 'begin' => array_pop($right[$name]), // 标签开始符 'end' => $match[0], // 标签结束符 ]; - } else { - continue; } } else { // 标签头压入栈 @@ -136,9 +134,10 @@ class TagLib // 标签替换 从后向前 foreach ($nodes as $pos => $node) { // 对应的标签名 - $name = $tags[1][$node['name']]; + $name = $tags[1][$node['name']]; + $alias = $_lib . $name != $node['name'] ? ($_lib ? strstr($node['name'], $_lib) : $node['name']) : ''; // 解析标签属性 - $attrs = $this->parseAttr($node['begin'][0], $name); + $attrs = $this->parseAttr($node['begin'][0], $name, $alias); $method = '_' . $name; // 读取标签库中对应的标签内容 replace[0]用来替换标签头,replace[1]用来替换标签尾 $replace = explode($break, $this->$method($attrs, $break)); @@ -171,11 +170,12 @@ class TagLib // 自闭合标签 if (!empty($tags[0])) { $regex = $this->getRegex(array_keys($tags[0]), 0); - $content = preg_replace_callback($regex, function ($matches) use (&$tags) { + $content = preg_replace_callback($regex, function ($matches) use (&$tags, &$_lib) { // 对应的标签名 - $name = $tags[0][$matches[1]]; + $name = $tags[0][$matches[1]]; + $alias = $_lib . $name != $matches[1] ? ($_lib ? strstr($matches[1], $_lib) : $matches[1]) : ''; // 解析标签属性 - $attrs = $this->parseAttr($matches[0], $name); + $attrs = $this->parseAttr($matches[0], $name, $alias); $method = '_' . $name; return $this->$method($attrs, ''); }, $content); @@ -192,14 +192,10 @@ class TagLib */ private function getRegex($tags, $close) { - $begin = $this->tpl->config('taglib_begin'); - $end = $this->tpl->config('taglib_end'); - $single = strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1 ? true : false; - if (is_array($tags)) { - $tagName = implode('|', $tags); - } else { - $tagName = $tags; - } + $begin = $this->tpl->config('taglib_begin'); + $end = $this->tpl->config('taglib_end'); + $single = strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1 ? true : false; + $tagName = is_array($tags) ? implode('|', $tags) : $tags; if ($single) { if ($close) { // 如果是闭合标签 @@ -218,98 +214,45 @@ class TagLib return '/' . $regex . '/is'; } - /** - * TagLib标签属性分析 返回标签属性数组 - * @access public - * @param string $attr 标签属性字符串 - * @param string $tag 标签名 - * @return array - * @throws Exception - * @internal param string $tagStr 标签内容 - */ - public function parseXmlAttr($attr, $tag) - { - if ('' == trim($attr)) { - return []; - } - //XML解析安全过滤 - $attr = str_replace('&', '___', $attr); - if (substr($attr, 0, 1) == '<' && substr($attr, -1, 1) == '>') { - $xml = '' . $attr . ''; - } else { - $xml = ''; - } - $xml = simplexml_load_string($xml); - if (!$xml) { - throw new Exception('_XML_TAG_ERROR_ : ' . $attr); - } - $xml = (array) ($xml->tag->attributes()); - if (isset($xml['@attributes']) && $result = array_change_key_case($xml['@attributes'])) { - $tag = strtolower($tag); - if (!isset($this->tags[$tag])) { - // 检测是否存在别名定义 - foreach ($this->tags as $key => $val) { - if (isset($val['alias']) && in_array($tag, explode(',', $val['alias']))) { - $item = $val; - break; - } - } - } else { - $item = $this->tags[$tag]; - } - if (!empty($item['attr'])) { - if (isset($item['must'])) { - $must = explode(',', $item['must']); - } else { - $must = []; - } - $attrs = explode(',', $item['attr']); - foreach ($attrs as $name) { - if (isset($result[$name])) { - $result[$name] = str_replace('___', '&', $result[$name]); - } elseif (false !== array_search($name, $must)) { - throw new Exception('_PARAM_ERROR_:' . $name); - } - } - } - return $result; - } else { - return []; - } - } - /** * 分析标签属性 正则方式 * @access public * @param string $str 标签属性字符串 - * @param string $tag 标签名 + * @param string $name 标签名 + * @param string $alias 别名 * @return array */ - public function parseAttr($str, $tag) + public function parseAttr($str, $name, $alias = '') { - if (ini_get('magic_quotes_sybase')) { - $str = str_replace('\"', '\'', $str); - } - $regex = '/\s+(?>(?\w+)\s*)=(?>\s*)([\"\'])(?(?:(?!\\2).)*)\\2/is'; + $regex = '/\s+(?>(?[\w-]+)\s*)=(?>\s*)([\"\'])(?(?:(?!\\2).)*)\\2/is'; $result = []; if (preg_match_all($regex, $str, $matches)) { foreach ($matches['name'] as $key => $val) { $result[$val] = $matches['value'][$key]; } - $tag = strtolower($tag); - if (!isset($this->tags[$tag])) { + if (!isset($this->tags[$name])) { // 检测是否存在别名定义 foreach ($this->tags as $key => $val) { - if (isset($val['alias']) && in_array($tag, explode(',', $val['alias']))) { - $item = $val; - break; + if (isset($val['alias'])) { + $array = (array) $val['alias']; + if (in_array($name, explode(',', $array[0]))) { + $tag = $val; + $type = !empty($array[1]) ? $array[1] : 'type'; + $result[$type] = $name; + break; + } } } } else { - $item = $this->tags[$tag]; + $tag = $this->tags[$name]; + // 设置了标签别名 + if (!empty($alias) && isset($tag['alias'])) { + $type = !empty($tag['alias'][1]) ? $tag['alias'][1] : 'type'; + $result[$type] = $alias; + } } - if (!empty($item['must'])) { - $must = explode(',', $item['must']); + if (!empty($tag['must'])) { + $must = explode(',', $tag['must']); foreach ($must as $name) { if (!isset($result[$name])) { throw new Exception('_PARAM_ERROR_:' . $name); @@ -318,18 +261,18 @@ class TagLib } } else { // 允许直接使用表达式的标签 - if (!empty($this->tags[$tag]['expression'])) { + if (!empty($this->tags[$name]['expression'])) { static $_taglibs; - if (!isset($_taglibs[$tag])) { - $_taglibs[$tag][0] = strlen(ltrim($this->tpl->config('taglib_begin'), '\\') . $tag); - $_taglibs[$tag][1] = strlen(ltrim($this->tpl->config('taglib_end'), '\\')); + if (!isset($_taglibs[$name])) { + $_taglibs[$name][0] = strlen(ltrim($this->tpl->config('taglib_begin'), '\\') . $name); + $_taglibs[$name][1] = strlen(ltrim($this->tpl->config('taglib_end'), '\\')); } - $result['expression'] = substr($str, $_taglibs[$tag][0], -$_taglibs[$tag][1]); + $result['expression'] = substr($str, $_taglibs[$name][0], -$_taglibs[$name][1]); // 清除自闭合标签尾部/ $result['expression'] = rtrim($result['expression'], '/'); $result['expression'] = trim($result['expression']); - } elseif (empty($this->tags[$tag]) || !empty($this->tags[$tag]['attr'])) { - throw new Exception('_XML_TAG_ERROR_:' . $tag); + } elseif (empty($this->tags[$name]) || !empty($this->tags[$name]['attr'])) { + throw new Exception('_XML_TAG_ERROR_:' . $name); } } return $result; @@ -345,7 +288,7 @@ class TagLib { $condition = str_ireplace(array_keys($this->comparison), array_values($this->comparison), $condition); $this->tpl->parseVar($condition); - $this->tpl->parseVarFunction($condition); // XXX: 此句能解析表达式中用|分隔的函数,但表达式中如果有|、||这样的逻辑运算就产生了歧异 + // $this->tpl->parseVarFunction($condition); // XXX: 此句能解析表达式中用|分隔的函数,但表达式中如果有|、||这样的逻辑运算就产生了歧异 return $condition; } diff --git a/library/think/template/driver/File.php b/library/think/template/driver/File.php index 35f7c802..9d9c9266 100644 --- a/library/think/template/driver/File.php +++ b/library/think/template/driver/File.php @@ -38,42 +38,37 @@ class File * 读取编译编译 * @string $cacheFile 缓存的文件名 * @array $vars 变量数组 - * @boolean $isReturn 是否返回内容 - * @return void|array + * @return void */ - public function read($cacheFile, $vars = [], $isReturn = false) + public function read($cacheFile, $vars = []) { if (!empty($vars) && is_array($vars)) { // 模板阵列变量分解成为独立变量 extract($vars, EXTR_OVERWRITE); } - if ($isReturn) { - //载入模版缓存文件 - include $cacheFile; - } else { - return include $cacheFile; - } + //载入模版缓存文件 + include $cacheFile; } /** * 检查编译缓存是否有效 - * @array $template 用到的模板更新时间列表 + * @array $templates 用到的模板更新时间列表 * @string $cacheFile 缓存的文件名 * @int $cacheTime 缓存时间 * @return boolean */ - public function check($files, $cacheFile, $cacheTime) + public function check($templates, $cacheFile, $cacheTime) { - foreach($files as $time => $path) { - if (is_file($path) && filemtime($path) > $time) { - // 模板文件如果有更新则缓存需要更新 - return false; - } - } if (0 != $cacheTime && time() > filemtime($cacheFile) + $cacheTime) { // 缓存是否在有效期 return false; } + foreach($templates as $time => $path) { + if (is_file($path) && filemtime($path) > $time + $cacheTime) { + // 模板文件如果有更新则缓存需要更新 + return false; + } + } return true; } } diff --git a/library/think/template/driver/Sae.php b/library/think/template/driver/Sae.php index 610569a9..e6209303 100644 --- a/library/think/template/driver/Sae.php +++ b/library/think/template/driver/Sae.php @@ -57,43 +57,37 @@ class Sae * 读取编译编译 * @string $cacheFile 缓存的文件名 * @array $vars 变量数组 - * @boolean $isReturn 是否返回内容 - * @return void|array + * @return void */ - public function read($cacheFile, $vars = [], $isReturn = false) + public function read($cacheFile, $vars = []) { if (!empty($vars) && is_array($vars)) { extract($vars, EXTR_OVERWRITE); } - if ($isReturn) { - return $this->get($cacheFile, 'content'); - } else { - eval('?>' . $this->get($cacheFile, 'content')); - } + eval('?>' . $this->get($cacheFile, 'content')); } /** * 检查编译缓存是否有效 - * @array $template 用到的模板更新时间列表 + * @array $templates 用到的模板更新时间列表 * @string $cacheFile 缓存的文件名 * @int $cacheTime 缓存时间 * @return boolean */ - public function check($template, $cacheFile, $cacheTime) + public function check($templates, $cacheFile, $cacheTime) { - foreach($template as $time => $path) { - if (is_file($path) && filemtime($path) > $time) { - // 模板文件如果有更新则缓存需要更新 - return false; - } - } $mtime = $this->get($cacheFile, 'mtime'); if (0 != $cacheTime && time() > $mtime + $cacheTime) { // 缓存是否在有效期 return false; - } else { - return true; } + foreach($templates as $time => $path) { + if (is_file($path) && filemtime($path) > $time + $cacheTime) { + // 模板文件如果有更新则缓存需要更新 + return false; + } + } + return true; } /** diff --git a/library/think/template/taglib/Cx.php b/library/think/template/taglib/Cx.php index e3add2fb..cab26867 100644 --- a/library/think/template/taglib/Cx.php +++ b/library/think/template/taglib/Cx.php @@ -35,23 +35,27 @@ class Cx extends Taglib 'switch' => ['attr' => 'name', 'expression' => true], 'case' => ['attr' => 'value,break', 'expression' => true], 'default' => ['attr' => '', 'close' => 0], - 'compare' => ['attr' => 'name,value,type', 'alias' => 'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'], - 'range' => ['attr' => 'name,value,type', 'alias' => 'in,notin,between,notbetween'], + 'compare' => ['attr' => 'name,value,type', 'alias' => ['eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq', 'type']], + 'range' => ['attr' => 'name,value,type', 'alias' => ['in,notin,between,notbetween', 'type']], 'empty' => ['attr' => 'name'], 'notempty' => ['attr' => 'name'], 'present' => ['attr' => 'name'], 'notpresent' => ['attr' => 'name'], 'defined' => ['attr' => 'name'], 'notdefined' => ['attr' => 'name'], - 'import' => ['attr' => 'file,href,type,value,basepath', 'close' => 0, 'alias' => 'load,css,js'], + 'import' => ['attr' => 'file,href,type,value,basepath', 'close' => 0], + 'load' => ['attr' => 'file,href,type,value,basepath', 'close' => 0, 'alias' => ['css,js', 'type']], 'assign' => ['attr' => 'name,value', 'close' => 0], 'define' => ['attr' => 'name,value', 'close' => 0], 'for' => ['attr' => 'start,end,name,comparison,step'], 'url' => ['attr' => 'link,vars,suffix,domain', 'close' => 0, 'expression' => true], + 'function' => ['attr' => 'name,vars,use,call'], ]; /** * php标签解析 + * 格式: + * {php}echo $name{/php} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -66,10 +70,10 @@ class Cx extends Taglib /** * volist标签解析 循环输出数据集 * 格式: - * + * {volist name="userList" id="user" empty=""} * {user.username} * {user.email} - * + * {/volist} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -117,6 +121,10 @@ class Cx extends Taglib /** * foreach标签解析 循环输出数据集 + * 格式: + * {foreach name="userList" id="user" key="key" index="i" mod="2" offset="3" length="5" empty=""} + * {user.username} + * {/foreach} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -192,10 +200,10 @@ class Cx extends Taglib /** * if标签解析 * 格式: - * - * - * - * + * {if condition=" $a eq 1"} + * {elseif condition="$a eq 2" /} + * {else /} + * {/if} * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || && * @access public * @param array $tag 标签属性 @@ -211,7 +219,7 @@ class Cx extends Taglib } /** - * else标签解析 + * elseif标签解析 * 格式:见if标签 * @access public * @param array $tag 标签属性 @@ -228,6 +236,7 @@ class Cx extends Taglib /** * else标签解析 + * 格式:见if标签 * @access public * @param array $tag 标签属性 * @return string @@ -241,11 +250,11 @@ class Cx extends Taglib /** * switch标签解析 * 格式: - * - * 1 - * 2 - * other - * + * {switch name="a.name"} + * {case value="1" break="false"}1{/case} + * {case value="2" }2{/case} + * {default /}other + * {/switch} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -292,7 +301,7 @@ class Cx extends Taglib /** * default标签解析 需要配合switch才有效 - * 使用: ddfdf + * 使用: {default /}ddfdf * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -307,18 +316,17 @@ class Cx extends Taglib /** * compare标签解析 * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq - * 格式: content + * 格式: {compare name="" type="eq" value="" }content{/compare} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 - * @param string $type 比较类型 * @return string */ - public function _compare($tag, $content, $type = 'eq') + public function _compare($tag, $content) { $name = $tag['name']; $value = $tag['value']; - $type = isset($tag['type']) ? $tag['type'] : $type; + $type = isset($tag['type']) ? $tag['type'] : 'eq'; // 比较类型 $name = $this->autoBuildVar($name); $flag = substr($value, 0, 1); if ('$' == $flag || ':' == $flag) { @@ -326,77 +334,34 @@ class Cx extends Taglib } else { $value = '\'' . $value . '\''; } + switch($type) { + case 'equal': + $type = 'eq'; + break; + case 'notequal': + $type = 'neq'; + break; + } $type = $this->parseCondition(' ' . $type . ' '); $parseStr = '' . $content . ''; return $parseStr; } - public function _eq($tag, $content) - { - return $this->_compare($tag, $content, 'eq'); - } - - public function _equal($tag, $content) - { - return $this->_compare($tag, $content, 'eq'); - } - - public function _neq($tag, $content) - { - return $this->_compare($tag, $content, 'neq'); - } - - public function _notequal($tag, $content) - { - return $this->_compare($tag, $content, 'neq'); - } - - public function _gt($tag, $content) - { - return $this->_compare($tag, $content, 'gt'); - } - - public function _lt($tag, $content) - { - return $this->_compare($tag, $content, 'lt'); - } - - public function _egt($tag, $content) - { - return $this->_compare($tag, $content, 'egt'); - } - - public function _elt($tag, $content) - { - return $this->_compare($tag, $content, 'elt'); - } - - public function _heq($tag, $content) - { - return $this->_compare($tag, $content, 'heq'); - } - - public function _nheq($tag, $content) - { - return $this->_compare($tag, $content, 'nheq'); - } - /** * range标签解析 * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外 - * 格式: content - * example: content + * 格式: {range name="var|function" value="val" type='in|notin' }content{/range} + * example: {range name="a" value="1,2,3" type='in' }content{/range} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 - * @param string $type 比较类型 * @return string */ - public function _range($tag, $content, $type = 'in') + public function _range($tag, $content) { $name = $tag['name']; $value = $tag['value']; - $type = isset($tag['type']) ? $tag['type'] : $type; + $type = isset($tag['type']) ? $tag['type'] : 'in'; // 比较类型 $name = $this->autoBuildVar($name); $flag = substr($value, 0, 1); @@ -418,32 +383,10 @@ class Cx extends Taglib return $parseStr; } - // range标签的别名 用于in判断 - public function _in($tag, $content) - { - return $this->_range($tag, $content, 'in'); - } - - // range标签的别名 用于notin判断 - public function _notin($tag, $content) - { - return $this->_range($tag, $content, 'notin'); - } - - public function _between($tag, $content) - { - return $this->_range($tag, $content, 'between'); - } - - public function _notbetween($tag, $content) - { - return $this->_range($tag, $content, 'notbetween'); - } - /** * present标签解析 * 如果某个变量已经设置 则输出内容 - * 格式: content + * 格式: {present name="" }content{/present} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -460,7 +403,7 @@ class Cx extends Taglib /** * notpresent标签解析 * 如果某个变量没有设置,则输出内容 - * 格式: content + * 格式: {notpresent name="" }content{/notpresent} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -477,7 +420,7 @@ class Cx extends Taglib /** * empty标签解析 * 如果某个变量为empty 则输出内容 - * 格式: content + * 格式: {empty name="" }content{/empty} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -491,6 +434,15 @@ class Cx extends Taglib return $parseStr; } + /** + * notempty标签解析 + * 如果某个变量不为empty 则输出内容 + * 格式: {notempty name="" }content{/notempty} + * @access public + * @param array $tag 标签属性 + * @param string $content 标签内容 + * @return string + */ public function _notempty($tag, $content) { $name = $tag['name']; @@ -501,7 +453,7 @@ class Cx extends Taglib /** * 判断是否已经定义了该常量 - * 已定义 + * {defined name='TXT'}已定义{/defined} * @param array $tag * @param string $content * @return string @@ -513,6 +465,13 @@ class Cx extends Taglib return $parseStr; } + /** + * 判断是否没有定义了该常量 + * {notdefined name='TXT'}已定义{/notdefined} + * @param array $tag + * @param string $content + * @return string + */ public function _notdefined($tag, $content) { $name = $tag['name']; @@ -521,8 +480,8 @@ class Cx extends Taglib } /** - * import 标签解析 - * + * import 标签解析 {import file="Js.Base" /} + * 格式:{import file="Css.Base" type="css" /} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -530,9 +489,10 @@ class Cx extends Taglib * @param string $type 类型 * @return string */ - public function _import($tag, $content, $isFile = false, $type = '') + public function _import($tag, $content, $isFile = false) { $file = isset($tag['file']) ? $tag['file'] : $tag['href']; + $type = isset($tag['type']) ? strtolower($tag['type']) : ($isFile ? null : 'js'); $parseStr = ''; $endStr = ''; // 判断是否存在加载条件 允许使用函数判断(默认为isset) @@ -544,8 +504,6 @@ class Cx extends Taglib $endStr = ''; } if ($isFile) { - // 根据文件名后缀自动识别 - $type = $type ? $type : (!empty($tag['type']) ? strtolower($tag['type']) : null); // 文件方式导入 $array = explode(',', $file); foreach ($array as $val) { @@ -565,8 +523,7 @@ class Cx extends Taglib } } } else { - // 命名空间导入模式 默认是js - $type = $type ? $type : (!empty($tag['type']) ? strtolower($tag['type']) : 'js'); + // 命名空间导入模式 $basepath = !empty($tag['basepath']) ? $tag['basepath'] : '/Public'; // 命名空间方式导入外部文件 $array = explode(',', $file); @@ -584,7 +541,7 @@ class Cx extends Taglib $parseStr .= ''; break; case 'php': - $parseStr .= ''; + $parseStr .= ''; break; } } @@ -598,22 +555,10 @@ class Cx extends Taglib return $this->_import($tag, $content, true); } - // import别名使用 导入css文件 - public function _css($tag, $content) - { - return $this->_import($tag, $content, true, 'css'); - } - - // import别名使用 导入js文件 - public function _js($tag, $content) - { - return $this->_import($tag, $content, true, 'js'); - } - /** * assign标签解析 * 在模板中给某个变量赋值 支持变量赋值 - * 格式: + * 格式: {assign name="" value="" /} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -635,7 +580,7 @@ class Cx extends Taglib /** * define标签解析 * 在模板中定义常量 支持变量赋值 - * 格式: + * 格式: {define name="" value="" /} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -656,7 +601,10 @@ class Cx extends Taglib /** * for标签解析 - * 格式: + * 格式: + * {for start="" end="" comparison="" step="" name=""} + * content + * {/for} * @access public * @param array $tag 标签属性 * @param string $content 标签内容 @@ -721,4 +669,38 @@ class Cx extends Taglib $domain = isset($tag['domain']) ? $tag['domain'] : 'false'; return ''; } + + /** + * function标签解析 匿名函数,可实现递归 + * 使用: + * {function name="func" vars="$data" call="$list" use="&$a,&$b"} + * {if is_array($data)} + * {foreach $data as $val} + * {~func($val) /} + * {/foreach} + * {else /} + * {$data} + * {/if} + * {/function} + * @access public + * @param array $tag 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _function($tag, $content) + { + $name = !empty($tag['name']) ? $tag['name'] : 'func'; + $vars = !empty($tag['vars']) ? $tag['vars'] : ''; + $call = !empty($tag['call']) ? $tag['call'] : ''; + $use = ['&$' . $name]; + if (!empty($tag['use'])) { + foreach (explode(',', $tag['use']) as $val) { + $use[] = '&' . ltrim(trim($val), '&'); + } + } + $parseStr = '' . $content . '' : '?>'; + return $parseStr; + } } diff --git a/tests/thinkphp/library/think/extend.html b/tests/thinkphp/library/think/extend.html index 9aa9a58b..922192dc 100644 --- a/tests/thinkphp/library/think/extend.html +++ b/tests/thinkphp/library/think/extend.html @@ -1,4 +1,2 @@ {extend name="extend2" /} -{block name="mainbody"} - mainbody -{/block} \ No newline at end of file +{block name="head"}header{/block} \ No newline at end of file diff --git a/tests/thinkphp/library/think/extend2.html b/tests/thinkphp/library/think/extend2.html index ab08b984..eb22e1da 100644 --- a/tests/thinkphp/library/think/extend2.html +++ b/tests/thinkphp/library/think/extend2.html @@ -1,5 +1,6 @@ {layout name="layout2" replace="[__REPLACE__]" /} -
+{block name="head"}{/block} +
{include file="include" name="info" value="$info.value" /} {block name="main"} {block name="side"} diff --git a/tests/thinkphp/library/think/template/taglib/cxTest.php b/tests/thinkphp/library/think/template/taglib/cxTest.php index 7621e9f4..96ceaf15 100644 --- a/tests/thinkphp/library/think/template/taglib/cxTest.php +++ b/tests/thinkphp/library/think/template/taglib/cxTest.php @@ -469,7 +469,7 @@ EOF; {import file="base,common" type="php" /} EOF; $data = << + EOF; $cx->parseTag($content); $this->assertEquals($content, $data); @@ -563,4 +563,31 @@ EOF; $this->expectOutputString('123456789'); } + public function testFunction() + { + $template = new template(); + $data = [ + 'list' => ['language' => 'php', 'version' => ['5.4', '5.5']], + 'a' => '[', + 'b' => ']', + ]; + + $content = <<\$val} +{if is_array(\$val)} +{~\$func(\$val)} +{else} +{if !is_numeric(\$key)} +{\$key.':'.\$val.','} +{else} +{\$a.\$val.\$b} +{/if} +{/if} +{/foreach} +{/function} +EOF; + $template->fetch($content, $data); + $this->expectOutputString("language:php,[5.4][5.5]"); + } } diff --git a/tests/thinkphp/library/think/templateTest.php b/tests/thinkphp/library/think/templateTest.php index 4e6aae0f..9ba071b2 100644 --- a/tests/thinkphp/library/think/templateTest.php +++ b/tests/thinkphp/library/think/templateTest.php @@ -216,6 +216,16 @@ EOF; $template->parse($content); $this->assertEquals($data, $content); + $content = << +EOF; + $data = <<a)) echo 'test'; ?> +EOF; + + $template->parse($content); + $this->assertEquals($data, $content); + $content = << EOF; @@ -332,17 +342,29 @@ EOF; $content = << -
+header +
value: +main + + + side value: @@ -360,6 +382,8 @@ value: EOF; $template->fetch($content); $this->expectOutputString($content2); +// $template->parse($content); +// var_dump($content); } public function testVarAssign()