`

phpcms使用的缓存方式总结

    博客分类:
  • php
 
阅读更多
原文地址:http://blog.csdn.net/painsonline/article/details/7683182



phpcms使用的缓存方式总结
a.模板编译缓存
参考文件include/global.func.php及include/template.func.php
模板编译缓存的原理其实很简单,如果模板是第一次编译,则直接编译它,如果不是第一次编译,则比较模板文件($tplfile)及模板缓存文件 ($compiledtplfile)的修改时间,如果模板文件的修改时间大于编译过的模板缓存文件,则编译模板,否则不编译模板,提高了程序的执行效率。
function template($module = 'phpcms', $template = 'index')
{
    global $CONFIG;
    $compiledtplfile = $CONFIG['templatescachedir'].$module.'_'.$template.'.tpl.php';
    if($CONFIG['templaterefresh'])
    {
        $tplfile = PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/'.$template.'.html';
        if(!file_exists($compiledtplfile) || @filemtime($tplfile) > @filemtime($compiledtplfile))
        {
            require_once PHPCMS_ROOT.'/include/template.func.php';
            template_refresh($tplfile, $compiledtplfile);
        }
    }
    return $compiledtplfile;
}

b.在动态页面里面产生静态的缓存文件
与c的缓存原理类似,只是此处生成的文件名相对固定
以问吧模块为例进行说明
用http://www.chf.com/opensource/phpcms2007_sp6_gbk/phpcms/wenba/进行访问
此目录下有个index.php文件,判断当前目录下是否存在名为index_cache.html的文件,如果有没有过失效期,则直接包含此文件,否则动态地读取完数据后保存为index_cache.html文件,以备下次使用。
文件index.php中的内容:
<?php
require_once './include/common.inc.php';
$lastedittime = @filemtime('index_cache.html');
$lastedittime = $PHP_TIME-$lastedittime;
$autoupdatetime = intval($MOD['autoupdate']); //$MOD['autoupdate']来自缓存文件data/cache/wenba_setting.php中的内容
if(file_exists('index_cache.html') && $lastedittime<$autoupdatetime)
{   
    echo "include cache file";
    include 'index_cache.html';
}
else
{
    echo "read dynamic page";
...
?>
怎么判断文件是否失效呢,文件data/cache/wenba_setting.php中有如下的设置,其中字段autoupdate的值就是文件失效的时间,单位是秒,在后台可以进行设置
文件wenba_setting.php是从哪儿来的呢,进行安装时自动把各种模块的数据保存到数据库中了,安装时就生成缓存数据了,在include/common.inc.php中函数cache_all也可以生成缓存,后台进行设置时cache会自动更新的
<?php
return array (
  'higth_score' => '100',
  'anybody_score' => '2',
  'answer_give_credit' => '5',
  'vote_give_credit' => '1',
  'highscore' => '2',
  'vote_give_actor' => '公司白领

魔法师

科举夺魁

武将

江湖奇侠',
  'autoupdate' => '10',
  'name' => '问吧',
  'moduledir' => 'wenba',
  'moduledomain' => '',
  'linkurl' => '/opensource/phpcms2007_sp6_gbk/phpcms/wenba/',
);
?>

include/global.func.php
更新模块设置函数
function module_setting($module, $setting)
{
    global $db,$MODULE,$LANG;
    if(!is_array($setting) || !array_key_exists($module,$MODULE)) return FALSE;
    if(isset($setting['moduledomain']))
    {
        $moduledomain = $setting['moduledomain'];
        $db->query("UPDATE ".TABLE_MODULE." SET moduledomain='$moduledomain' WHERE module='$module'");
        unset($setting['moduledomain']);
    }
    $setting = addslashes(serialize(new_stripslashes($setting)));
    //将某个模块的多个设置的值经数组序列化以后保存在一个字段setting中
    $db->query("UPDATE ".TABLE_MODULE." SET setting='$setting' WHERE module='$module'");
    cache_module($module);
    cache_common();
    return TRUE;
}

c.在动态页面里面产生静态的缓存文件
与b的缓存原理类似,只是此处生成的文件名是根据计算$PHP_SELF与$PHP_QUERYSTRING的md5值生成的文件名,相对于所有php动态页面来说都是一样的,这个思想比较精典,值得借签
以问吧模块为例进行说明
文件调用顺序为:index.php -> js.php -> ad.php -> global.func.php
用http://www.chf.com/opensource/phpcms2007_sp6_gbk/phpcms/wenba/进行访问
此目录下有个index.php文件,判断当前目录下是否存在名为index_cache.html的文件,如果有,则直接包含此文件,如果不存在此文件,则动态地读取完数据后保存在index_cache.html文件,以备下次使用

用上述的url访问时,页面里面包含有如下的一行js代码
<script language="javascript" src="/opensource/phpcms2007_sp6_gbk/phpcms/data/js.php?id=1"></script>
此js代码其实就是动态调用php页面的内容
http://www.chf.com/opensource/phpcms2007_sp6_gbk/phpcms/data/js.php?id=1

js.php文件的内容:
<?php
chdir('../ads/');
require './ad.php';
?>

ad.php的内容:
<?php
define('SHOWJS', 1);
require './include/common.inc.php';
require MOD_ROOT.'/include/global.func.php';

$placeid = intval($id);

$query ="SELECT * FROM ".TABLE_ADS." AS a LEFT JOIN ".TABLE_ADS_PLACE." AS p ON (a.placeid=p.placeid) WHERE a.placeid=".$placeid." AND a.fromdate<=UNIX_TIMESTAMP() AND a.todate>=UNIX_TIMESTAMP() AND p.passed=1 AND a.passed=1 AND a.checked=1 ORDER BY a.addtime";
$ads = $db->get_one($query, "CAHCE", 10240);
if(!$ads) exit('document.write("")');

$db->query("UPDATE ".TABLE_ADS." SET views=views+1 WHERE adsid=".$ads['adsid']);

$content = ads_content($ads);
$templateid = $ads['templateid'] ? $ads['templateid'] : 'ads';
include template('ads', $templateid);
phpcache();
?>

ad.php里面调用了phpcache函数,参考文件include/global.func.php
function phpcache($is_js = 0)
{
    global $CONFIG,$cachefiledir,$cachefile;
    if(!$is_js && $CONFIG['phpcache'] != '2') return FALSE;
    $contents = ob_get_clean(); //读取缓冲区里面的内容
    if($is_js) $contents = strip_js($contents);
    if($CONFIG['phpcache'] == '2' && $cachefiledir && $cachefile)
    {
        dir_create($cachefiledir);
        file_put_contents($cachefile, $contents); //在这儿生成一个.html格式的文件,当下次以同样的url访问时,会直接读取缓存了,参见include/common.inc.php中的代码,这儿的代码是非常非常精典的,大家好好借鉴、好好模仿吧
        @chmod($cachefile, 0777);
    }
    /*
    向浏览器发送http header,跟浏览器说,此页面不缓存,还告诉浏览器页面的最后修改时间
    第一次访问js.php?id=1时向浏览器发送http header,第二次或以后再访问此url时,由于上次已经生成了缓存,所以在include/common.inc.php中直接调用缓存文件了,直到 缓存失效后再次执行此处的动态代码。此处发送的header控制缓存是相对于浏览器来说的;而通过file_put_contents生成的缓存是相对于 电脑硬盘来说的,是不一样的。
    */
    header('Expires: Mon, 26 Jul 2000 05:00:00 GMT');
    header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
    header('Cache-Control: no-cache, must-revalidate');
    header('Pragma: no-cache');
    echo $contents;
}

上面的phpcache函数中的全局变量$cachefiledir,$cachefile是从哪里来的呢,从这儿来的
文件include/common.inc.php中的内容
if(!defined('IN_ADMIN'))
{
    if($CONFIG['dbiscache']) $db_file .= '_cache';
    if($CONFIG['phpcache'] == '2')
    {
        $cachefileid = md5($PHP_SELF.'?'.$PHP_QUERYSTRING);
        $cachefiledir = PHPCMS_ROOT.'/data/phpcache/'.substr($cachefileid, 0, 2).'/';
        $cachefile = $cachefiledir.$cachefileid.'.html';
        //echo "cachefile:$cachefile";
        if(file_exists($cachefile) && ($PHP_TIME < @filemtime($cachefile) + $CONFIG['phpcacheexpires']))
        {
            require $cachefile;
            exit;
        }
    }
    if($PHP_QUERYSTRING && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", $PHP_QUERYSTRING, $urlvar))
    {
        parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1]));
    }
  
}

d.数据库查询结果缓存
下面是include/common.inc.php中的几行代码
$db_file = $db_class = 'db_'.$CONFIG['database']; //$CONFIG['database']位于config.inc.php中,配置可以使用自己的数据库,如mysql,sqlite,sqlserver等
require PHPCMS_ROOT.'/include/'.$db_file.'.class.php';
$db = new $db_class;
$db->connect($CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpw'], $CONFIG['dbname'], $CONFIG['pconnect']);
$db->iscache = $CONFIG['dbiscache']; //是否启用 sql cache (只对前台起作用,建议在不生成html并且访问量过大时开启)
$db->expires = $CONFIG['dbexpires']; //sql cache 过期时间(秒)

db_mysql_cache.class.php中的代码
function query($sql , $type = '' , $expires = 3600, $dbname = '')
    {
        if($this->isclient)
        {
            $dbname = $dbname ? $dbname : $this->dbname;
            $this->select_db($dbname);
        }
        /*
        $this->iscache表示是否启动了数据库查询缓存
        如果启用了数据库查询缓存且$type为CACHE且是select语句,则启用查询缓存
        个人感觉这儿$type参数用strtoupper处理一下更好了
        */
        if($this->iscache && $type == 'CACHE' && stristr($sql, 'SELECT'))
        {
            $this->caching = 1; //成员变量caching标识启用了数据库查询缓存,用在下面的fetch_array,num_rows,free_result函数中,其实用iscache就可以判断了,没有必要再用一个成员变量了
            $this->expires = $expires; //数据库缓存数据的失效期
            return $this->_query_cache($sql); //然后调用_query_cache方法
        }
        $this->caching = 0;
        $func = $type == 'UNBUFFERED' ? 'mysql_unbuffered_query' : 'mysql_query';
        if(!($query = $func($sql , $this->connid)) && $type != 'SILENT')
        {
            $this->halt('MySQL Query Error', $sql);
        }
        $this->querynum++;
        return $query;
    }

function _query_cache($sql)
    {
        $this->cache_id = md5($sql); //计算$sql的md5值,然后作为cache_id
        $this->result = array();
        $this->cursor = 0;
        $this->cache_file = $this->_get_file(); //得到cache文件名
        //如果cache数据已经过期,则重新从数据库中取得查询结果,然后保存在数据库中
        if($this->_is_expire())
        {
            $this->result = $this->_get_array($sql); //从数据库中取结果
            $this->_save_result(); //保存结果到缓存数据中
        }
        else
        {
            $this->result = $this->_get_result(); //缓存没过期直接取缓存数据
        }
        return $this->result;
    }

    function _get_file()
    {
        global $CONFIG;
        //cache文件的主目录一般是data/dbcache
        return $CONFIG['dbcachedir'].substr($this->cache_id, 0, 2).'/'.$this->cache_id.'.php';
    }

function _is_expire()
    {
        global $PHP_TIME;
        return !file_exists($this->cache_file) || ( $PHP_TIME > @filemtime($this->cache_file) + $this->expires );
    }

/*
由于方法_get_array只是被方法_query_cache调用,所以在此方法里面直接用函数mysql_unbuffered_query了,因为mysql_unbuffered性能好一点,参考
http://bbs.chinaunix.net/viewthread.php?tid=958067&extra=page%3D4
*/
function _get_array($sql)
    {
        $this->cursor = 0;
        $arr = array();
        $result = mysql_unbuffered_query($sql, $this->connid);
        while($row = mysql_fetch_assoc($result))
        {
            $arr[] = $row;
        }
        $this->free_result($result);
        $this->querynum++;
        return $arr;
    }

function _save_result()
    {
        if(!is_array($this->result)) return FALSE;
        dir_create(dirname($this->cache_file));
        file_put_contents($this->cache_file, "<?php\n return ".var_export($this->result, TRUE).";\n?>");
        @chmod($this->cache_file, 0777);
    }

    function _get_result()
    {
         return include $this->cache_file;
    }

function fetch_array($query, $result_type = MYSQL_ASSOC)
    {
        return $this->caching ? $this->_fetch_array($query) : mysql_fetch_array($query, $result_type);
    }

//从数据库中获取查询的结果
function _fetch_array($result = array())
    {
        if($result) $this->result = $result;
        return isset($this->result[$this->cursor]) ? $this->result[$this->cursor++] : FALSE;
    }

function num_rows($query)
    {
        return $this->caching ? $this->_num_rows($query) : mysql_num_rows($query);
    }

function free_result($query)
    {
        if($this->caching==1) $this->result = array();
        else @mysql_free_result($query);
    }

如果把上述的文件存储改为用memcached、eaccelerator、shm等来进行存储的话效率会更高,改动起来也不是太难,后台可以加一个设置选项,如分别是
文件,memcached,eaccelerator,shm等让管理员进行设置,然后调用相应的存储系统进行存储
分享到:
评论

相关推荐

    phpcms模板标签总结

    总结了phpcms中的默认模板的标签使用,适合新手学习

    phpcms缓存使用总结(memcached、eaccelerator、shm)

    主要介绍了phpcms中memcached、eaccelerator、shm缓存使用方法,需要的朋友可以参考下

    phpcms 二次开发总结

    phpcms 二次开发总结所有的文件都在根目录下(例如apache下的htdocs),此时,默认访问地址应该是http://localhost/, 则‘web_path’=&gt;'/',若网站默认的访问地址不是根目录,则需要将变量‘web_path’的值改为新的...

    PHPCMS V9使用手册

    PHPCMS V9使用手册

    PHPCMS安装与使用

    PHPCMS安装与使用 PHPCMS安装与使用

    phpcms标签调用总结

    phpcms v9常用标签、一、二级栏目标签调用、组图调用

    PHPCMS自己总结

    PHPCMS自己总结

    PHPCMS系统后台的使用

    PHPCMS系统后台的使用

    phpcms系统使用手册

    phpcms系统使用手册 PHPCMS V9(简称V9)是由国内知名CMS管理系统开发商PHPCMS 独立自主研发的新一代网站内容管理系统,该系统采用PHP5+MYSQL做为技术基础迚行开发。采用最为流行的OOP(面向对象)斱式迚行多层架极...

    phpcmsV9后台模板

    说“由于官方后台不好看,而且对客户来说使用过程中容易起各种纠纷,该后台模板全新黑色后台,去除了官方版权等,而且全新的登录页面,给客户一种视觉享受。”不要下。 说“喜欢用phpcms 开发网站的对默认后台界面看...

    PHPCMS后台模板 美化PHPCMS后台

    PHPCMS后台模板,用于美化PHPCMS原始后台,直接把文件压根上传网站根目录,可替换原来后台模板。

    Phpcms X (原PHPCMS)长期维护版

    如您使用PHPCMS X,并需要一些新的功能模块,您可以访问我们的在线模块市场或联系我们定制开发; 主要完善和优化项如下: 支持HTTPS环境 支持php7.4+ 支持MySQL8+ (支持 MariaDB 10.5 +) 支持后台更新提示和一键...

    phpcms_gbk留言板插件

    4、本安装包含模板文件,如果你使用的不是官方默认模板,请自行修改样式。 本版本为亦佳网的phpcms v9 留言板插件2.0版本的gbk修改版 如果安装后后台菜单为英文名,那么请打开phpcms/languages/zh-cn目录下的...

    phpcms短信插件_phpcms短信接口开发_phpcms短信发送设置

    phpcms短信插件_phpcms短信接口开发_phpcms短信发送设置

    phpcms v9 评分模块 测试可以使用

    phpcms v9 评分模块 测试可以使用

    PHPCMS_V9.2.5

    PHPCMS

    phpcmsV9 用户手册

    V9采用OOP(面向对象)方式进行基础运行框架搭建。模块化开发方式做为功能开发形式。框架易于功能扩展,代码维护,优秀的二次开发能力,可满足所有网站的应用需求。 5年开发经验的优秀团队,在掌握了丰富的WEB开发...

    PHPCMS整站代码分析讲解.doc

    PHPCMS整站代码分析讲解

    PHPCMS V9 数据结构

    PHPCMS V9 数据结构

    phpcms v9手册(pdf)

    本文档的读者为PHPCMS V9 的使用者。使用者应具备以下基础知识: 熟悉Microsoft Internet Explorer 戒Mozilla Firefox 的使用; 熟悉Windows 戒Linux/Unix 操作系统; 熟悉Mysql 数据库,及数据库相关知识 . ...

Global site tag (gtag.js) - Google Analytics