phpcms 源码分析七: 模板引擎实现
这次是逆雪寒对模板引擎实现的分析:
1 /*
函数 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; /*
因为phpcms是分模块来存放模板文件。所以 template 函数有两个参数:
第一个就是模块目录名,第二个就是此模块里面的模板文件名.
$CONFIG['templatescachedir'] 这个是放编译后php文件存放的目录。
在config.inc.php 站点配置文件里面定义的自己去看。 这样就取得了模板编译后的php文件路径。
*/
$compiledtplfile = $CONFIG['templatescachedir'].$module.'_'.$template.'.tpl.php'; // $CONFIG['templaterefresh'] 在 config.inc.php里面配置了。
// 默认是1 。是更新模板开关。如果你设置为0 那么模板更新了。程序也不会更新。
if($CONFIG['templaterefresh'])
{
/*
和下面那句意思差不多。$CONFIG['defaulttemplate'] 是默认模板目录 。
这句是获取你要的那个模块和里面的那个模板文件的路径(@@获取没编译前的模板文件)
*/
$tplfile = PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/'.$template.'.html'; /*
我把文件编译成了php文件。那么模板改变了。 php文件总得也改变吧。
要不你修改了模板后。站还是以前那个样子没变那有什么意思呢。
首先判断模板编译文件是否存在。如果不存在那么后边那个条件不用判断了。
因为编译文件都不存在。程序肯定运行不了拉。(
因为其实我们主要是运行编译后的那个php文件,模板文件是html的运行个P呀)
或 后边那个 @filemtime($tplfile) > @filemtime($compiledtplfile)
很容易就明白: 函数 filetime() 判断文件最近修改的时间,返回Unix 时间戳。
如果模板文件的修改时间 大于 编译文件。 那么证明 模板文件 在 编译文件生成后 还进行了修改。
那么我们是不是还要在更新次编译文件呀 ,那是肯定的拉。 所以继续执行下去。
*/
if(!file_exists($compiledtplfile) || @filemtime($tplfile) > @filemtime($compiledtplfile))
{
// 加载编译函数
require_once PHPCMS_ROOT.'/include/template.func.php'; // 这个就是模板的 编译启动函数 ,带动一系列的模板编译函数来最终生成模板编译文件。
template_refresh($tplfile, $compiledtplfile);
}
} // 返回 模板编译后的PHP文件路径。
return $compiledtplfile;
} 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;
} // 模板编译启动函数。 参数 第一个是 模板文件名 第二个是 编译后的php文件名
function template_refresh($tplfile,$compiledtplfile)
{
// 使用了php5 的最爽函数:file_get_contents() 获取文件的内容 。
$str = file_get_contents($tplfile); /*
* 然后 使用 template_parse() 函数来对文件内容进行替换。
* 比如把一些我们自己定义的语句:{if xx > xx}
* 正则替换成 <?php if(xx > xx){?>具体看下面
*/
$str = template_parse($str); // 编译完成后。把内容写到我们的 那个所谓的编译PHP文件。
$strlen = file_put_contents($compiledtplfile, $str); // 别忘了设置下权限。
@chmod($compiledtplfile, 0777); //返回 写到编译文件里的内容字大小节数,下面我们会看下 template_parse() 函数
return $strlen;
} // 这个很有用。批量编译某模块目录下的模板文件
function template_module($module)
{
global $CONFIG; /*
glob 函数 取得 在此路径下的所有 *.html 以html为扩展名的文件列表。 具体看手册。
*/
$files = glob(PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/*.html'); if(is_array($files))
{
foreach($files as $tpl)
{
//开始批量
$template = str_replace('.html', '', basename($tpl)); // 获取模板文件名。以次来做编译后的PHP文件名
template_compile($module, $template);
}
} return TRUE;
} // 这个是比下面那个更大批量的生成。因为 $MODULE 里面的所有模块
// $MODULE 存在于缓存文件模板。前面已经说了。自己看吧
function template_cache()
{
global $MODULE; foreach($MODULE as $module=>$m)
{
template_module($module);
} return TRUE;
} /*
哇,别给它吓到。其实都是些简单的正则。只要知道他们是干什么的就好办了。 在模板里面我们使用了些自己定义的标签呀。
语句呀。这些东西不是PHP标准语法。所以根本不可能运行。
那么怎么办呢。通过正则对我们自己定义的语法 。转变成标准的PHP语法。
然后写到我们的 PHP文件里。所以下面正则都是对我们自己定义的语法进行编译。
下面讲解下正则。按照本人水平解释。大概的解释了下。不过不懂正则的请自己百度学下。
有不对的地方。大家可以讨论下。@@ 还没懂 preg_replace() 函数的同学兄弟朋友姐妹。请自己看手册。
*/
function template_parse($str)
{
// 用 \n\r 过滤掉 tab制表符, [url=file://\\1]\\1[\url] 是逆向引用了第一个括号里面\n换行\r换页匹配的文本
//(@@解释好要口,最好自己看下正则知识 /s为修正符。自己百度吧)
$str = preg_replace("/([\n\r]+)\t+/s", "[url=file://\\1]\\1", $str[\url]); // 以 {xx} 来替换 <!--{xx}--> {xx}在下面肯定还要进行第二次正则替换,要不是不能在PHP里面运行的。
// .+? 和 .+ 一个是懒惰 一个是贪婪。 看名字就知道。不知道的 百度吧: 正则贪婪。
$str = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}",$str); /*
* 把模板里面的 {template 'xx','jj'} 编译成PHP标准写法:<?php include template('xx','jj') ?>
* 大家可能一看就明白了: include template() 这个在那里见过。对了。这个在PHP里也可以运行的。因为 template() 函数不是定义了吗。
*/
$str = preg_replace("/\{template\s+(.+)\}/","\n<?php include template([url=file://\\1]\\1[\url]); ?>\n",$str); /* 模板里面的 {include xx.php} 编译成 PHP文件里的 <?php include xx.php?>**/
$str = preg_replace("/\{include\s+(.+)\}/","\n<?php include [url=file://\\1]\\1[\url]; ?>\n",$str); /* 模板里面的 {php xxxx} 编译成 <?php xxxx?> 大家也应该明白了。 xxxx 肯定是PHP的标准语法拉。
* 所以phpcms模板语句: {php } 就是用来给你在模板里写要运行的PHP语句。在smarty 里也有这功能**
*/
$str = preg_replace("/\{php\s+(.+)\}/","\n<?php [url=file://\\1?]\\1?>\n",$str[\url]); /* 这个就更简单了。 把模板里面的{if xxxx} 编译成 <?php if(){?>
* 看这样一步一步的把一些自己定义的语句编译成PHP的标准语法。这个就叫模板引擎了。**
*/
$str = preg_replace("/\{if\s+(.+?)\}/","<?php if([url=file://\\1]\\1[\url]) { ?>",$str); /* {else } 转 <?php } else {?>**/
$str = preg_replace("/\{else\}/","<?php } else { ?>",$str); /* {elseif } 转 <?php } elseif {?>**/
$str = preg_replace("/\{elseif\s+(.+?)\}/","<?php } elseif ([url=file://\\1]\\1[\url]) { ?>",$str); /* {/if} 转 <?php }?> phpcms 模板语法有: {/if}的哦。大家别忘了,要不 php肯定运行不了**/
$str = preg_replace("/\{\/if\}/","<?php } ?>",$str); /* 下面就是循环了。模板里用{loop xx jj} 其实编译成了PHP的 foreach(xx AS jj) 这样大家都会用了吧**/
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/",
"<?php if(is_array([url=file://\\1]\\1[\url]))
foreach([url=file://\\1]\\1[\url] AS [url=file://\\2]\\2[\url]) { ?>",$str); /* 这句和上面也差不多。不过是多了个取出数组的标名 {loop xx jj yy} 成 foreach(xx as jj=> yy)**/
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/",
"\n<?php if(is_array([url=file://\\1]\\1[\url]))
foreach([url=file://\\1]\\1[\url] AS [url=file://\\2]\\2[\url] => [url=file://\\3]\\3[\url]) { ?>",$str); /* 循环结束别忘了 {/loop} 对应PHP的 <?php }?>**/
$str = preg_replace("/\{\/loop\}/","\n<?php } ?>\n",$str); /* {tag_xx} 替换为 get_tag('xx') get_tag() 函数是自己定义的函数,
* 因为phpcms 的模板引擎应用了标签功能。这个函数就是为了调用标签的。**
*/
$str = preg_replace("/\{tag_([^}]+)\}/e", "get_tag('\\1')", $str); /* {xxx(jj)} 这么个奇怪的东西。因为奇怪所以我找了下PHPCMS的模板文件。
* 找了几个文件都没发现这个怪物。大家有谁找到的说下我去看下。怕是我理解错了正则。先谢了**
*/
$str = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(([^{}]*)\))\}/",
"<?php echo [url=file://\\1;?]\\1;?>",$str[\url]); /* {$xxx(wwsd)} 专换成 <?php echo xxx(wwsd)?> 当然了 xxx() 是程序中定义过的函数**/
$str = preg_replace("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(([^{}]*)\))\}/",
"<?php echo [url=file://\\1;?]\\1;?>",$str[\url]); /* 把{$xxjj} 转成 <?php echo $xxjj?> 当然了是把变量输出**/
$str = preg_replace("/\{([url=file://\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/]\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/",
"<?php[\url] echo [url=file://\\1;?]\\1;?>",$str[\url]); /* 主要是把{$xxx['jj']} 转成 <?php echo $xxx['jj']?>
* addquote() 函数自己定义的看下面,二次过滤。有代验证,头昏了看太久的黄色字。我昏**
*/
$str = preg_replace("/\{([url=file://\\$[a-zA-Z0-9_\[\]\]\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/es[\url]",
"addquote('<?php echo [url=file://\\1;?]\\1;?>')",$str[\url]); /* {XXJJ} <?php echo XXJJ?> XXJJ 是我们定义的常量**/
$str = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s",
"<?php echo [url=file://\\1;?]\\1;?>",$str[\url]); /* 最后别忘了在自己的每个编译后的文件里加上这个。以前讲过了不明白找前面例子**/
$str = "<?php defined('IN_PHPCMS') or exit('Access Denied'); ?>".$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 "<?php echo $code;?>";
} function addquote($var)
{
return str_replace("[url=]\\\[\url]\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
}
/*
[/php] 下一节讲 phpcms 的模板标签功能,讲得不好.大侠就别笑我了
phpcms 源码分析七: 模板引擎实现的更多相关文章
- [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(1)
[源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(1) 目录 [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(1) 0x00 摘要 ...
- [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(2)
[源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(2) 目录 [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(2) 0x00 摘要 ...
- Nmap源码分析(脚本引擎)
Nmap提供了强大的脚本引擎(NSE),以支持通过Lua编程来扩展Nmap的功能.目前脚本库已经包含300多个常用的Lua脚本,辅助完成Nmap的主机发现.端口扫描.服务侦测.操作系统侦测四个基本功能 ...
- ABP源码分析七:Setting 以及 Mail
本文主要说明Setting的实现以及Mail这个功能模块如何使用Setting. 首先区分一下ABP中的Setting和Configuration. Setting一般用于需要通过外部配置文件(或数据 ...
- vuex 源码分析(七) module和namespaced 详解
当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...
- Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解
先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...
- tair源码分析——leveldb存储引擎使用
分析完leveldb以后,接下来的时间准备队tair的源码进行阅读和分析.我们刚刚分析完了leveldb而在tair中leveldb是其几大存储引擎之一,所以我们这里首先从tair对leveldb的使 ...
- phpcms 源码分析六:index文件
这次是逆雪寒对index.php的分析: /* [/php] [ 本帖最后由 逆雪寒 于 2007-12-25 16:12 编辑 ] 尽量每天都有新的东西每天都能进一小步 现在开始讲 index.ph ...
- phpcms 源码分析五:文件缓存实现
这次是逆雪寒的文件缓存实现代码分析: /* [/php] PHPCMS的文本缓存实现: [php] <?php /* 这个文件里面全是有关生成文本缓存的函数.文本缓存是个好东西.一般的项目,我们 ...
随机推荐
- JAVA线程优化
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- 【HDOJ】1542 Atlantis
离散化+线段树+扫描线,求覆盖面积. /* 1542 */ #include <iostream> #include <string> #include <map> ...
- wcf service library
创建wcf服务库的时候,系统自动生成的代码 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”. [ServiceContract] publ ...
- hdu4666Hyperspace
http://acm.hdu.edu.cn/showproblem.php?pid=4666 先看一个求曼哈顿的帖子http://www.cnblogs.com/lmnx/articles/24797 ...
- mac 修改密码后 频繁输入钥匙串问题修复方法
就一句话就是 清空钥匙串缓存 下面是具体方法 进入硬盘目录-->资源库-->Keychains 删除里面的文件夹(这个文件夹里面有 keychain-2.db keychain-2.db- ...
- 结构体 row_prebuilt_t
typedef struct row_prebuilt_struct row_prebuilt_t; /** A struct for (sometimes lazily) prebuilt stru ...
- DNS----域名解析系统
DNS就是域名解析系统,它可以将IP转换成域名,也可以将域名转换成IP 1. 安装DNS服务 开始—〉设置—〉控制面板—〉添加/删除程序—〉添加/删除Windows组件—〉“网络服务”—〉 ...
- Android ViewPager多页面滑动切换以及动画效果
一.首先,我们来看一下效果图,这是新浪微博的Tab滑动效果.我们可以手势滑动,也可以点击上面的头标进行切换.与此同方式,白色横条会移动到相应的页卡头标下.这是一个动画效果,白条是缓慢滑动过去的.好了, ...
- HDU-1896 Stones
http://acm.hdu.edu.cn/showproblem.php?pid=1896 题意:一个人从0开始走起,遇到偶数个石头就踢.要是同一位置有多个石头,则先扔最重的石头(也就是扔的最近的那 ...
- [liu yanling]软件测试分为哪几个计划过程阶段
a) 计划阶段:编写测试计划,搭建测试环境,准备测试数据b) 设计阶段:编写测试用例(需求分析和测试用例文档)c) 执行阶段:执行测试用例,生成缺陷d) 报告阶段:测试报告,改进意见