dede静态模板引擎写入缓存SaveCache()教程

admin2023-01-171006

当我们实例化dede模板类,即new DedeTagParse后,在这个类里面的构造函数就会初始化,判断一下我们后台的配置是否启用模板缓存,实际上我们安装完织梦系统后,系统默认的这个配置项就是"Y",始下图所示。

微信截图_20200115100543.png

就是说安装完程序后,系统里面的相关操作就会缓存到/data/tplcache/文件夹里面,当实例化dede模板类后,构造函数就会通过下面的代码:

if(!isset($GLOBALS['cfg_tplcache']))
        {
            $GLOBALS['cfg_tplcache'] = 'N';
        }
        if($GLOBALS['cfg_tplcache']=='Y')
        {
            $this->IsCache = TRUE;
        }
        else
        {
            $this->IsCache = FALSE;
        }

来判断,若是你没有去更改的话,那么,$GLOBALS['cfg_tplcache']=='Y'成立,然后,把$this->IsCache设置为TRUE 这样,当程序通过函数ParseTemplet()函数最后,就会判断一下$this->IsCache是否为true若是,则把解析后的标签缓存到对应的模板文件里面。

缓存到模板里面的这个功能就是通过本教程里的函数SaveCache()来实现的,本教程就是讲解这个缓存文件是如何建立的,如何缓存到http://www.dedebase.com/data/tplcache/里面的。

代码分析开始:

如果我们实例化dede模板类后,就要调用LoadSource($str)或调用LoadTemplate()函数了,但是,调用这二个函数生成的缓存文件是不一样的,若是调用LoadSource($str)函数,生成的文件是三个一组即:

  9b6a189e5299fff08b22245bc59890b3.inc
  9b6a189e5299fff08b22245bc59890b3.inc9835c7b6d92d4e7a.inc
  9b6a189e5299fff08b22245bc59890b3.inc9835c7b6d92d4e7a.inc.txt

这三个文件中,第一个文件是模板字符串,是没有解析的标签源码,而第二个文件则是标签解析后的一个数组,第三个是缓存时间;再看一下这三个文件有什么特点? 就是第一个“点”前面的名称完全相同,也就是第一个文件点前面的名称,第一个文件是载入LoadSource($str)函数生成的,而下面二个则是载入缓存文件生成的。

之所以生成这样的长的缓存文件名是因为在函数LodaSource($str)里面定义了这样一句:

$this->taghashfile = $filename = DEDEDATA.'/tplcache/'.md5($str).'.inc';

然后,在检测模板缓存函数LoadCache($filename)里面,定义了这样三行代码:

$ckfile = str_replace($cdir,'',$filename).substr(md5($filename),0,16).'.inc';
$ckfullfile_t = $cachedir.'/'.$ckfile.'.txt';
$this->CacheFile = $ckfullfile;

对比一下,你会发现,前二行不正是生成缓存文件的名吗?是的,只不过此时,虽然,定义了名称,但是,还没有写入解析完模板后的标签。

若实例化dede类后,我们调用的是LoadTemplate()函数,那么,缓存名就是二个一组,而且缓存名也没有这么长,例如:

article_article.htm9f14fb000d9f5eb2.inc
article_article.htm9f14fb000d9f5eb2.inc.txt

这是因为,模反article_article.htm直接用LoadTemplate()载入的,这个没有经过函数LoadSource()所以,所以上面定义的.inc文件前面的文件名只是article_article.htm加16位md5加密的数字。

现在我们再分析写入缓存文件函数就好理解了,代码:

        $fp = fopen($this->CacheFile.'.txt',"w");
        fwrite($fp,$this->TempMkTime."\n");
        fclose($fp);

打开.txt后缀的缓存文件,若没有这个文件(当然前提是这个文件名已经存在,上面我们分析过了已经设置好了)则创建这个文件,这个fopen()函数就这么强大,没有则创建。然后,把模板修改时间$this->TempMKTime写入到.txt文件里面,我们打开这个txt文件会发现里面有一串数字,这串数字就是模板修改时间。然后,关闭文件。

下面一整个大段代码就是对.inc文件,也就是解析后的缓存文件进行写入操作。要理解这段代码,如果我们对照着.inc里面已经写好的内容,进行分析会更有效果,也更容易理解。我们不防打开一个生成的缓存文件.inc,例如,打开article_article.htm9f14fb000d9f5eb2.inc

代码如下:

微信截图_20200115100543.png

由于解析后的模板太多,这里我删除了一部分为方便大家查看,正常是数组索引的数字是连续的,从上图我们可以看出我从9以后的一直删除到49,这二个数字之间的数组我都删除了。

要想把一大篇幅的内容写入到一个文件里面,那么,首先得打开这个文件,然后,锁定这个文件,为什么要锁定,因为写入的内容太多了,以免出错,就锁定,上面写时间时就没有锁定,这是因为,内容太少,不值得多让程序执行一个函数,要知道多执行一个函数相当于执行一大段代码。

然后,写入"<?php" php文件开始符号。然后,判断标记集合是不是一个数组,即if(is_array($this->CTags)),如果这个标记集合都不是一个数组了,那就没有遍历的必要了。因为若标记集合都不是数组的话,可能是模板中本来就没有标签,或载入模板或解析模板出错等,这里只判断是数组的情况,若是,则执行下面的foreach遍历数组。

先把数组里面的第一个标记写进去,因为,如果上面条件成立,肯定数组中有标记,所以,上面条件成立,标记就存在这是肯定的,所以,$arrayValue = 'Array("'.$ctag->TagName.'",';然后,判断一下有没有在底层模板里面被禁止的函数?若有则删除刚刚建立的各个缓存文件名。

然后,执行这么一个吓人的代码:

$arrayValue .= '"'.str_replace('$','\$',str_replace("\r","\\r",str_replace("\n","\\n",str_replace('"','\"',str_replace("\\","\\\\",$ctag->InnerText))))).'"';

从里向外看就是把底层模板里面'\\'进行转义'\\\\',然后,再把里面的双引号转义\" ,然后,把里面的\n 转义\\n 、\r 转义\\r 、$ 转义为\$ 。然后,再把标签的开始和结束位置也存入到$arrayValue里面。然后,把这个

$arrayValue 写入到数组$z里面,这个可参考上图中$z[50]里面的一些转义,当然这个$z[50]并不包含所有上面提到的转义。

下面的代码就是把标签的属性及其值写入到数组Items里面,这个我们可以对照上图中的代码,代码:

if(is_array($ctag->CAttribute->Items))
                {
                    foreach($ctag->CAttribute->Items as $k=>$v)
                    {
                        $v = str_replace("\\","\\\\",$v);
                        $v = str_replace('"',"\\".'"',$v);
                        $v = str_replace('$','\$',$v);
                        $k = trim(str_replace("'","",$k));
                        if($k=="")
                        {
                            continue;
                        }
                        if($k!='tagname')
                        {
                            fwrite($fp,"\$z[$tid][4]['$k']=\"$v\";\n");
                        }
                    }
                }

遍历出来的一个例子为:

$z[53]=Array("arclist","\r\n  <li><a href=\"[field:arcurl/]\">[field:title/]</a></li> \r\n ",9019,9220);
$z[53][4]['flag']="c";
$z[53][4]['titlelen']="42";
$z[53][4]['row']="6";

首先得判断$ctag->CAttribute->Items是不是一个数组,若不是数组,说明这个标签可能是类似{dede:global.cfg_templets_skin/}的标签,也就是没有属性的标签,若是一个数组则说明是一个有属性的标签例如:

{dede:arclist flag="c" titlelen="42" row="6"} <li><a href=\"[field:arcurl/]\">[field:title/]</a></li>{/dede:arclist}

若是上面的这样的标签,则把这个标签里面属性flag,titlelen,row写入到数组$ctag->CAttribute->Items里面。

下面是这个有属性的标签里面的$this->CTags里面的内容,也就是解析模板后的内容:

[53] => DedeTag Object
        (
            [IsReplace] =>
            [TagName] => arclist
            [InnerText] =>[field:title/]

            [StartPos] => 9019
            [EndPos] => 9220
            [CAttribute] => DedeAttribute Object
                (
                    [Count] => 3
                    [Items] => Array
                        (
                            [tagname] => arclist
                            [flag] => c
                            [titlelen] => 42
                            [row] => 6
                        )

                )

            [TagValue] =>
            [TagID] => 53
        )

)

从标签、$z[53]和对应[53]也许你会发现什么?

上面的代码就是这个功能,具体我们不作分析了,因为,这个与动态模板引擎里面的写入缓存文件WriteCache($ctype='all')几乎一样,如果不会请看这个函数。最后,关闭php文件符号?>关闭打开的文件,函数分析结束。


网友评论