织梦静态模板引擎检测模板缓存LoadCache($filename)
这个函数的功能是在载入模板的时候,要检测一下这个模板有没有缓存文件,若有说明这个模板已经解析过了,就不用解析了,反之,则要重新解析,这个是在载入模板的时候调用的一个函数,刚开始的时候自认为检测模板函数,直接检测一下在data/tplcachde/里面是不是存在这个模板的缓存文件名,不就可以了吗?但是,当读了一下这个函数的代码才知道,原来并没有我们想像的那么简单,这也告诉我们对于研究织梦函数的重要性,如果你研究函数多了,你会发现自己的思考问题会越来越全面,这样不管以后我们做织梦二次开发,还是自己开发一个系统,那么,一定会有很大帮助的。在分析函数的过程中,我们的思维不断的变强大,建议大家平常多分析一些函数,最好像我这样做出教程来,这样你会发现自己不知不觉中你也会写函数了。
这个函数所在文件:/include/dedetag.class.php
代码分析开始:
1.若不缓存文件,则直接返回false,如果你的系统设置连缓存文件都不缓存的话,那么,就没有必要检测了,所以,这一点要考虑。代码如下:
if(!$this->IsCache) { return FALSE; }
2.对模板以及缓存文件作初始化处理,然后,判断缓存文件是否存在,代码如下:
$cdir = dirname($filename); $cachedir = DEDEROOT.$cfg_tplcache_dir; $ckfile = str_replace($cdir,'',$filename).substr(md5($filename),0,16).'.inc'; $ckfullfile = $cachedir.'/'.$ckfile; $ckfullfile_t = $cachedir.'/'.$ckfile.'.txt'; $this->CacheFile = $ckfullfile; $this->TempMkTime = filemtime($filename); if(!file_exists($ckfullfile)||!file_exists($ckfullfile_t)) { return FALSE; }
若系统设置缓存,那么,我们就根据模板进行缓存名的查找并判断。dirname($filename) 就是获得除了模板名外的模板路径,例如,模板路径为:www.dedebae.com/dede/templets/index.htm ,那么,经过dirname('www.dedebae.com/dede/templets/index.htm')后,就得到了www.dedebase.com/dede/templets。
我做了个测试,在test.php文件写入如下代码:
<?php $c="www.dedebae.com/dede/templets/index.htm"; echo dirname($c); ?>
显示的结果如下图所示。
然后,定义缓存路径:$cachedir = DEDEROOT.$cfg_tplcache_dir;也就是$cachedir=/data/tplcache/ 这是织梦系统默认的缓存路径,如果你没有改的话,一般我们也不会改这个,因为,改了没有什么意义。
定义缓存文件名:str_replace($cdir,'',$filename).substr(md5($filename),0,16).'.inc';先把模板路径里面的前面路径都去掉,这样就得到了模板文件名index.htm,然后,再加md5加密后,取前16位,这样我们就得到了index.htmxxx.inc文件了,例如 index.htmab3648abc957b491.inc。
组装缓存文件完整路径:$ckfullfile = /data/tplcache/index.htmab3648abc957b491.inc
组装解析模反后的时间txt文件:也就是在上面的路径后面加个后缀$ckfullfile_t = /data/tplcache/index.htmab3648abc957b491.inc.txt 这个文件里面存放的是缓存文件时间。所以,在解析文件时这二个一起生成的。
$this->CacheFile = $ckfullfile; $this->TempMkTime = filemtime($filename);
这二行分别是设置缓存文件,然后,把模板修改时间放在$this->TempMKTime里面。
以上做的全都是为下面这个判断准备的,判断上面的缓存文件是不是已经存在且缓存时间是不是已经存在,若二者同时存在,则说明模板已经缓存了,若其中任何一个不存在,则表示没有缓存过这个模板解析后的缓存文件,返回flase。
若缓存过了应当返回true 这是我们一般人这样想的,既然,都有这个缓存文件和缓存时间了,说明模板已经缓存了,应当返回true,但是,这样做不够好,如果缓存文件里面是空的,或是里面有问题呢?那模板一样解析不出来,所以,这样考虑不够周全,这也是我分析这个函数的一个重要原因,特别是编写程人员,考虑全面是基本的素养。
3.检测模板最后更新时间: 如果这个缓存文件存在,而模板更新了,这时模板里面的内容可能更新了,这时这个缓存文件可能跟我们更新后的模板的缓存文件不一样,也就是我们的模板有可能增减模板内容,这时就中重新缓存,所以,这是里要检测一下模板缓存时间和模板更新时间是不是相等,若不相等,则返回false,返回false就说明要重新缓存解析后的模板。
代码如下:
$fp = fopen($ckfullfile_t,'r'); $time_info = trim(fgets($fp,64)); fclose($fp); if($time_info != $this->TempMkTime) { return FALSE; }
4.若代码能执行到第四步,说明缓存文件已经存在,且,上面的几种情况都不会出现,也就是缓存文件正常,这时就要分析一下缓存文件内容了,如果缓存文件内容正常,那么,说明缓存文件才是真正的缓存文件,也就不要去再缓存一次解析后的模板了,这样可以减轻服务器压力,特别是对于大型网站来说。
要分析这个缓存文件首先得引入进这个函数里面include($this->CacheFile);然后,对里面的内容进行分析。
这个缓存文件里面存放的是一个数组$z 这是一个二维数组,存放是模板里面的标签,标签属性和值,这个$z的数组格式如下:
$z=array("标记","底层模板","标签开始位置","标签的结束位置",array('name'=>'变量名'))
$z=array("标记","底层模板","标签开始位置","标签的结束位置",array('属性名'=>'属性值','属性名'=>'属性值','属性名'=>'属性值','属性名'=>'属性值'......))
当然,第一个数组时面的并不一定是name,也有可能是filename等,要看具体的标签了。具体数组如下所示,我只截取有代表性的几个:
$z[1]=Array("global","",277,303); $z[1][4]['name']="cfg_webname"; $z[11]=Array("include","",2275,2310); $z[11][4]['filename']="head.htm"; $z[12]=Array("arclist","\r\n <h2><a href=\"[field:arcurl/]\">[field:title/]</a></h2>\r\n <p>[field:info/]...<a href=\"[field:arcurl/]\">[查看全文]</a></p>\r\n ",2455,2653); $z[12][4]['flag']="h"; $z[12][4]['limit']="0,1"; $z[12][4]['infolen']="230";
这些就是模反缓存里面的内容。
下面这段代码就是:把缓冲数组内容读入类
if( isset($z) && is_array($z) ) { foreach($z as $k=>$v) { $this->Count++; $ctag = new DedeTAg(); $ctag->CAttribute = new DedeAttribute(); $ctag->IsReplace = FALSE; $ctag->TagName = $v[0]; $ctag->InnerText = $v[1]; $ctag->StartPos = $v[2]; $ctag->EndPos = $v[3]; $ctag->TagValue = ''; $ctag->TagID = $k; if(isset($v[4]) && is_array($v[4])) { $i = 0; foreach($v[4] as $k=>$v) { $ctag->CAttribute->Count++; $ctag->CAttribute->Items[$k]=$v; } } $this->CTags[$this->Count] = $ctag; } }
如果按照上面的缓存文件内容,进行分析这段就简单了,就是实例化了二个类,然后,把缓存文件里面的内容存入标签数组里面,上面这段对应的$this->Ctags值类似如下所示:
[code]DedeTag Object ( [IsReplace] => [TagName] => lh [InnerText] => [StartPos] => 755 [EndPos] => 870 [CAttribute] => DedeAttribute Object ( [Count] => 7 [Items] => Array ( [tagname] => lh [itemname] => 楼号 [autofield] => 1 [type] => text [isnull] => true [default] => [maxlength] => 250 => ) ) [TagValue] => [TagID] => 6 )[/code]
若$z 不是一个数组并且没有设置,那么,说明这这个模板的没有缓冲数组,那么,直接把标记集合$this->CTags置为空,也就没有标记。但不管有没有缓冲数组$z都表示这个有这个缓存文件了,最后,返回truue 。