Home  >  Article  >  Backend Development  >  phpcms 源码解析-模板发动机

phpcms 源码解析-模板发动机

WBOY
WBOYOriginal
2016-06-13 13:25:02997browse

phpcms 源码解析-------模板引擎
PHPCMS 整站代码分析讲解(六)之模板引擎
发布:水水

19 May

/**
函数 template函数是在global.func.php 里面定义的。 在前面的phpcms 的首页 index.php 里就见到了。  用法: include template()    用法很熟, 呵呵其实和 dz 的模板引擎一样的用法。 但DZ的模板引擎比 PHPCMS 的简单很多,因为没有用到模板的标签技术。 大家有空可以研究下DZ的模板引擎。这里不说。  好分析下上面这个 模板的主要函数吧。  他的作用是返回编译好的模板文件路径。也就是把模板 X.html(模板文件) 用正则替换成 x.php(编译后的PHP文件).然后使用 include  函数。懂了吧! php的模板引擎都一个鸟样。 然后剩下的就是正则的东西了。等下再说。
*/
function template($module = 'phpcms', $template = 'index')
{
global $CONFIG;
$compiledtplfile = $CONFIG['templatescachedir'].$module.'_'.$template.'.tpl.php';
/**
因为phpcms是分模块来存放模板文件。所以 template 函数有两个参数: 第一个就是模块目录名,第二个就是此模块里面的模板文件名.
$CONFIG['templatescachedir']  这个是放编译后php文件存放的目录。在config.inc.php 站点配置文件里面定义的自己去看。 这样就取得了模板编译后的php文件路径。
*/
if($CONFIG['templaterefresh']) //$CONFIG['templaterefresh']  在 config.inc.php里面配置了。默认是1  。是更新模板开关。如果你设置为0 那么模板更新了。程序也不会更新。
{
        $tplfile = PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/'.$template.'.html';
  /**
  和上面那句意思差不多。$CONFIG['defaulttemplate'] 是默认模板目录  。这句是获取你要的那个模块和里面的那个模板文件的路径(@@获取没编译前的模板文件)
  */
        if(!file_exists($compiledtplfile) || @filemtime($tplfile) > @filemtime($compiledtplfile))
  {
   /**
   我把文件编译成了php文件。那么模板改变了。 php文件总得也改变吧。要不你修改了模板后。站还是以前那个样子没变那有什么意思呢。
   首先判断模板编译文件是否存在。如果不存在那么后边那个条件不用判断了。 因为编译文件都不存在。程序肯定运行不了拉。(因为其实我们主要是运行编译后的那个php文件,模板文件是html的运行个P呀)
   或  后边那个 @filemtime($tplfile) > @filemtime($compiledtplfile)  很容易就明白:  函数 filetime() 判断文件最近修改的时间,返回Unix 时间戳。 如果模板文件的修改时间 大于 编译文件。 那么证明 模板文件  在 编译文件生成后 还进行了修改。那么我们是不是还要在更新次编译文件呀 ,那是肯定的拉。 所以继续执行下去。
   */
   require_once PHPCMS_ROOT.'/include/template.func.php';   // 加载编译函数
   template_refresh($tplfile, $compiledtplfile);// 这个就是模板的 编译启动函数 ,带动一系列的模板编译函数来最终生成模板编译文件。
  }
}
return $compiledtplfile; // 返回 模板编译后的PHP文件路径。
}

defined('IN_PHPCMS') or exit('Access Denied');
function template_compile($module,$template) //和下面那个一样是编译模板启动函数。不过两函数的参数不一样,按照上下文意思。这个函数是为了配合批量编译模板而写的。第一个是模块目录名,第二是模板文件名,解释同下。请看下面那个
{
global $CONFIG;
$content = file_get_contents(PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/'.$template.'.html');
$content = template_parse($content);
$compiledtplfile = $CONFIG['templatescachedir'].$module.'_'.$template.'.tpl.php';
$strlen = file_put_contents($compiledtplfile, $content);
@chmod($compiledtplfile, 0777);
return $strlen;
}
function template_refresh($tplfile,$compiledtplfile) //模板编译启动函数。 参数 第一个是 模板文件名  第二个是 编译后的php文件名
{
$str = file_get_contents($tplfile); //使用了php5 的最爽函数:file_get_contents() 获取文件的内容 。
$str = template_parse($str); /*然后 使用 template_parse() 函数来对文件内容进行替换。比如把一些我们自己定义的语句:{if xx > xx}  正则替换成 xx){?>具体看下面*/
$strlen = file_put_contents($compiledtplfile, $str);//编译完成后。把内容写到我们的 那个所谓的编译PHP文件。
@chmod($compiledtplfile, 0777);  //别忘了设置下权限。
return $strlen; //返回 写到编译文件里的内容字大小节数,下面我们看下 template_parse() 函数
}
function template_module($module)//这个很有用。批量编译某模块目录下的模板文件
{
global $CONFIG;
$files = glob(PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/*.html');
/*
glob 函数  取得 在此路径下的所有 *.html 以html为扩展名的文件列表。 具体看手册。
**/
if(is_array($files))
{
  foreach($files as $tpl)
  { //开始批量
   $template = str_replace('.html', '', basename($tpl));
   // 获取模板文件名。以次来做编译后的PHP文件名
   template_compile($module, $template); //这个函数上面讲过了。看上面
  }
}
return TRUE;
}
function template_cache() //这个是比上面那个更大批量的生成。因为 $MODULE 里面的所有模块  $MODULE 存在于缓存文件模板。前面已经说了。自己看吧
{
    global $MODULE;
foreach($MODULE as $module=>$m)
    {
        template_module($module);
}
return TRUE;
}
/**
哇,别给它吓到。其实都是些简单的正则。只要知道他们是干什么的就好办了。 在模板里面我们使用了些自己定义的标签呀。语句呀。这些东西不是PHP标准语法。所以根本不可能运行。
那么怎么办呢。通过正则对我们自己定义的语法 。转变成标准的PHP语法。然后写到我们的 PHP文件里。所以下面正则都是对我们自己定义的语法进行编译。
下面讲解下正则。按照本人水平解释。大概的解释了下。不过不懂正则的请自己百度学下。有不对的地方。大家可以讨论下。@@   还没懂 preg_replace() 函数的同学兄弟朋友姐妹。请自己看手册。
*/
function template_parse($str)
{
$str = preg_replace("/([\n\r]+)\t+/s","\\1",$str); 
// 用 \n\r 过滤掉 tab制表符,  \\1 是逆向引用了第一个括号里面\n换行\r换页匹配的文本 (@@解释好要口,最好自己看下正则知识 /s为修正符。自己百度吧)
$str = preg_replace("/\/s", "{\\1}",$str);
// 以 {xx} 来替换 {xx}在下面肯定还要进行第二次正则替换,要不是不能在PHP里面运行的。  .+? 和 .+ 一个是懒惰 一个是贪婪。  看名字就知道。不知道的 百度吧: 正则贪婪。

$str = preg_replace("/\{template\s+(.+)\}/","\n\n",$str);
/* 把模板里面的 {template 'xx','jj'} 编译成PHP标准写法:   大家可能一看就明白了: include template()  这个在那里见过。对了。这个在PHP里也可以运行的。因为 template() 函数不是定义了吗。*/
$str = preg_replace("/\{include\s+(.+)\}/","\n\n",$str);
/* 模板里面的 {include xx.php} 编译成 PHP文件里的 **/
$str = preg_replace("/\{php\s+(.+)\}/","\n\n",$str);
/* 模板里面的 {php xxxx} 编译成   大家也应该明白了。 xxxx 肯定是PHP的标准语法拉。 所以phpcms模板语句: {php } 就是用来给你在模板里写要运行的PHP语句。在smarty 里也有这功能**/
$str = preg_replace("/\{if\s+(.+?)\}/","",$str);
/* 这个就更简单了。 把模板里面的{if xxxx}  编译成   看这样一步一步的把一些自己定义的语句编译成PHP的标准语法。这个就叫模板引擎了。**/
$str = preg_replace("/\{else\}/","",$str);
/* {else } 转 **/
$str = preg_replace("/\{elseif\s+(.+?)\}/","",$str);
/* {elseif } 转 **/
$str = preg_replace("/\{\/if\}/","",$str);
/* {/if} 转   phpcms 模板语法有: {/if}的哦。大家别忘了,要不 php肯定运行不了**/
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/","",$str);
/* 下面就是循环了。模板里用{loop xx jj} 其实编译成了PHP的 foreach(xx AS jj) 这样大家都会用了吧**/
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/","\n \\3) { ?>",$str);
/* 这句和上面也差不多。不过是多了个取出数组的标名  {loop xx jj yy}  成 foreach(xx as jj=> yy)**/
$str = preg_replace("/\{\/loop\}/","\n\n",$str);
/* 循环结束别忘了 {/loop}  对应PHP的 **/
$str = preg_replace("/\{tag_([^}]+)\}/e", "get_tag('\\1')", $str);
/* {tag_xx}  替换为 get_tag('xx')  get_tag()  函数是自己定义的函数,因为phpcms 的模板引擎应用了标签功能。这个函数就是为了调用标签的。**/
$str = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(([^{}]*)\))\}/","",$str);
/* {xxx(jj)}  这么个奇怪的东西。因为奇怪所以我找了下PHPCMS的模板文件。找了几个文件都没发现这个怪物。大家有谁找到的说下我去看下。怕是我理解错了正则。先谢了**/
$str = preg_replace("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(([^{}]*)\))\}/","",$str);
/* {$xxx(wwsd)} 专换成    当然了 xxx() 是程序中定义过的函数**/
$str = preg_replace("/\{([a-zA-Z0-9_\x7f-\xff]*)\}/]\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/","",$str);
/* 把{$xxjj} 转成   当然了是把变量输出**/
$str = preg_replace("/\{(\]\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/es", "addquote('')",$str);
/* 主要是把{$xxx['jj']} 转成   addquote() 函数自己定义的看下面,二次过滤。有代验证,头昏了看太久的黄色字。我昏**/
$str = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s", "",$str);
/* {XXJJ}    XXJJ 是我们定义的常量**/
$str = "".$str;
/* 最后别忘了在自己的每个编译后的文件里加上这个。以前讲过了不明白找前面例子**/
return $str; //最后返回过滤完成的内容
}
function get_tag($tagname) //这个函数在  上面这个编译函数里面看到了。 其实就是获取对应标签的内容,头有点昏,下节再说标签吧。
{
global $tags,$html,$CONFIG;
    if(!$tags) require PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/tags.php';
    if(!$html) require PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/html.php';
if(!isset($tags[$tagname])) return '{tag_'.$tagname.'}';
$code = isset($html[$tagname]) ? 'tag_read('.$html[$tagname].')' : $tags[$tagname];
return "";
}
function addquote($var)
{
return str_replace("[url=]\\\[/url]"", """, preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
}
?>
[size=xx-small][/size]

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn