资源描述
(word完整版)PHPCMS整站源码分析
/**
代码分析版权所有:逆雪寒
*/
require ’./include/common。inc.php’;
/**
看 common.inc。php 核心启动文件我们已经讲解完了。应该都明白了吧
*/
if($PHPCMS['ishtml'] == 1 && file_exists(PHPCMS_ROOT。'/’。$PHPCMS['index']。’。’.$PHPCMS[’fileext’]))
{
header('location:’。$PHPCMS['index’]。’.'.$PHPCMS['fileext']);
exit;
}
/**
phpcms 允许在后台生静态和使用静态,这里就是先判断 $PHPCMS['ishtml’](从文本缓存弄过来的.应该知道了吧)是否为1 就是开启了。和这个 静态的html文件是否存在。
*/
$channels = array();
$channels['article’] = $channels['down’] = $channels[’picture'] = $channels[’info']= array();
foreach($CHANNEL as $v)
{
$module = $v[’module’];
if($v['islink’] == 0 && $MODULE[$module][’iscopy'] == 1) $channels[$module][$v['channelid']] = $v;
}
//获取频道模块的信息。都是从缓存中取的
$head['title'] = $PHPCMS[’seo_title'];
$head['keywords'] = $PHPCMS[’seo_keywords'];
$head[’description'] = $PHPCMS['seo_description’];
// 这个是网页的SEO (title,keywords,description)信息。这个写好了。网络蜘蛛会找你哦。
include template(’phpcms', 'index’);
// template() 函数是模板函数.这个就是这章的主题。往下会讲模板引擎的制作,大家都看到include 了吧。它的参数是文件地址。那么就可以想到 template()函数其实就是
// 模板编译后的PHP文件地址。
phpcache();
/**
这个函数厉害了。用来自动生缓存页的(这个是页面缓存和数据库信息的文本缓存不是一会事),页面缓存,就是把你所看的页自动生成 XX.html 静态页。请注意前面代码。是不是有个 header()跳转到静态页呀。
那静态页那里来的?就是给这个函数弄出来的.自动静态化了其实。@@是不是很简单呢。上菜先:
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);
@chmod($cachefile, 0777);
}
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’); 这句 session_cache_limiter('private’) 作用差不多.就是用户 点击后退不会出现警告页。十分有用哦。大家别忘了
header('Pragma: no—cache’); 不缓存当前页 。其实和前一句一样意思,这句不过是为了兼容http1。0协议。
echo $contents; //输出内容.
}
首先判断.文件当前文件不是JS问文件和后台打开了页面缓存静态化,。然后使用了OB读写缓冲区系列函数来操作缓冲区。
ob_get_clean() 函数。十分有用.一般我们做整站静态化也是利用OB系列函数来实现。
这个函数就是获取当前缓冲区的HTML内容.然后把将要输出的缓冲区内容清除掉。网页先是一点点读到浏览器的缓冲区。当缓冲区满了以后才会放出来。所以我们
可以用OB系列函数在缓冲区没有输出之前截取内容来做我们要做的过滤等动作。(dz的伪静态有部分就这样实现的。把缓冲区中的所有超级连接地址更改成: thread-46695-1-3。html 形式.然后apache 那边再用.hataccess 来做判断跳转) 这里也是.我们获取将要输出的内容以后 调用 strip_js() 这个函数来过滤HTML内容。 因为比较简单继续上菜:
function strip_js($string, $js = 1)
{
$string = str_replace(array("\n”,”\r”,"\""),array(’’,'',"[url=]\\\""),$string[/url]);
return $js==1 ? ”document。write(\"”。$string."\”);\n” : $string;
}
主要是来过滤内容里面的 \n 换行 、\r 换页符 和 '\’ 具体请百度:制表符
继续我们上个函数strip_js过滤完内容后。 在使用 file_put_contents() 函数 把内容写到文件里面去。也就是那个 HTML静态页,恩完成了。当前页的静态页已经存在了.
但好象不对是吧.因为你刚用了 ob_get_clean() 函数。截取内容后清空了输出的内容.那就是浏览器成了空白页了。所以我们要手动的来 echo 输出内容给客户看。echo 前呢
还有些东西要做就是 header 几个http协议头过去 注释已经给出。详细的百度:http协议,会有详细的参数说明 。其主要目的是:强制用户每次访问这个页面时获取最新资料,而不是使用存在客户端的缓存.
*/
?>
关于phpcms cache原理,探讨
phpcms二次开发 QQ:267014881 长沙php 交流
软件版本 :phpcms2008 Linux王国 www。kinglinux。com 转载请注明原处
a。页面缓存,在后台 网站配置-》性能优化中,配置了启用PHP页面缓存
if(CACHE_PAGE && !defined('IN_ADMIN’)) cache_page_start(); //看是否调用页面缓存
global.func。php 有如下函数
function cache_page_start()
{
define('CACHE_PAGE_ID’, md5(RELATE_URL));
//定义cache文件的id,其中RELATE_URL在,common。inc。php 中
//define('RELATE_URL', isset($_SERVER[’REQUEST_URI’]) ? $_SERVER['REQUEST_URI’] : SCRIPT_NAME.(QUERY_STRING ? ’?’。QUERY_STRING : PATH_INFO));
//把本身的url+它get后的参数,两者md5加密,用来查找和生成cache-id
define('CACHE_PAGE_DIR', CACHE_PAGE_PATH.substr(CACHE_PAGE_ID, 0, 2)。’/');
////页面缓存配置(config.inc。php)
//define(’CACHE_PAGE', 0); //是否开启PHP页面自动缓存功能
//define(’CACHE_PAGE_PATH', PHPCMS_ROOT.'data/cache_page/'); //缓存存储路径
//define('CACHE_PAGE_TTL’, 3600); //秒,缓存默认生命周期
//define(’CACHE_PAGE_INDEX_TTL’, 300); //秒,缓存默认生命周期
//define(’CACHE_PAGE_CATEGORY_TTL’, 600); //秒,缓存默认生命周期
//define('CACHE_PAGE_LIST_TTL’, 900); //秒,缓存默认生命周期
/define(’CACHE_PAGE_CONTENT_TTL', 14400); //秒,缓存默认生命周期
//PHPCMS_ROOT。’data/cache_page/+cacheid的前三位
define('CACHE_PAGE_FILE', CACHE_PAGE_DIR.CACHE_PAGE_ID。’.html'); //加载cache文件
$contents = @file_get_contents(CACHE_PAGE_FILE);
if($contents && intval(substr($contents, 15, 25)) 〉 TIME) //判断是否过期,如果没有,就输出文件29个字符以后的所有文件
{
echo substr($contents, 29);
exit;
}
return true;
}
//生成cahe文件
function cache_page($ttl = CACHE_PAGE_TTL, $isjs = 0)
{
if($ttl == 0 || !defined('CACHE_PAGE_FILE’)) return false;
$contents = ob_get_contents();
if($isjs) $contents = format_js($contents); //读入数据,格式化js
dir_create(CACHE_PAGE_DIR);
$contents = ”〈!—-expiretime:”。(TIME + $ttl)。"-—>\n”.$contents; //加上时间和超时时间,以到后面取的时候好对比
file_put_contents(CACHE_PAGE_FILE, $contents); //写入文件
@chmod(CACHE_PAGE_FILE, 0777);
}
//清除所有的cache文件,也是data/cache_page下的文件
function cache_page_clear()
{
@set_time_limit(600);
$dirs = glob(CACHE_PAGE_PATH。’*');
foreach($dirs as $dir)
{
$files = glob($dir。’/*’);
foreach($files as $file)
{
@unlink($file);
}
@rmdir($dir);
}
}
//统计cache的更新时间和并写到数据库,比如更新时间,更新了多少次
//$M = $TEMP = array();
function cache_count($sql)
{
global $db, $TEMP;
$id = md5($sql);
if(!isset($TEMP[’count'][$id]))
{
if(CACHE_COUNT_TTL)
{
$r = $db->get_one("SELECT `count`,`updatetime` FROM `”。DB_PRE."cache_count` WHERE `id`=’$id’”);
if(!$r || $r['updatetime'] < TIME — CACHE_COUNT_TTL)
{
$r = $db-〉get_one($sql);
$TEMP['count'][$id] = $r['count’];
$db-〉query(”REPLACE INTO `”。DB_PRE."cache_count`(`id`, `count`, `updatetime`) VALUES(’$id', ’”。$r['count'].”’, '”。TIME。”')");
}
}
else
{
$r = $db-〉get_one($sql);
}
$TEMP[’count'][$id] = $r[’count’];
}
return $TEMP[’count'][$id];
}
//用户信息的cache文件,现在我还不知道什么意思
function cache_member()
{
global $db;
$status = $db—〉table_status(DB_PRE。’member_cache');
if($status['Rows'] == 0)
{
@set_time_limit(600);
$db—>query(”INSERT INTO `"。DB_PRE."member_cache` SELECT * FROM `”.DB_PRE。"member`");
return true;
}
return false;
}
//-——--———————--—--—---——-
//以上这些是页面cache的部分函数,其实也就是文本cache的一种方式 ,不过这个要在后台设置开启才行
//phpcms 2008默认是不开启,如上开关的,
//下面来介绍phpcms2008默认的文件cahce 模式
b。文件cahce
//在 global.ini.php中发现如下函数
//它的cache文件的目录是daba/cahce/下的很多x。php的文件,这些文件你可以打开看一下发现是一些生成好的数组文件
//平时在后台,点更新首页,其实也就是更新了这些变量,其中用到的var_export()这个php默认函数,大家可以看一下手册
function cache_read($file, $path = ’’, $iscachevar = 0)
{
if(!$path) $path = CACHE_PATH;
$cachefile = $path.$file;
if($iscachevar) //判断是否cache变量
{
global $TEMP; //temp是全局性的临时变量,记录一些用户信息及配置信息,在commom.ini。php中有定义,
$key = 'cache_’。substr($file, 0, -4); //去掉文件的后四位作为key,这个后四位暂时我也不明白,等后面分析
return isset($TEMP[$key]) ? $TEMP[$key] : $TEMP[$key] = @include $cachefile;
}
return @include $cachefile;
}
//生成cache文件
function cache_write($file, $array, $path = ’')
{
if(!is_array($array)) return false;
$array = ”<?php\nreturn ”.var_export($array, true).";\n?>”;
$cachefile = ($path ? $path : CACHE_PATH).$file;
$strlen = file_put_contents($cachefile, $array);
@chmod($cachefile, 0777);
return $strlen;
}
//删除cache文件
function cache_delete($file, $path = '')
{
$cachefile = ($path ? $path : CACHE_PATH)。$file;
return @unlink($cachefile);
}
这只是文本cache的部分东西
全部函数在 cache.func。php
介强一下这个函数,大至过程就是通过数据库调用数据,生成变量,变量写入文件,文件在调用时被引入到模板文件
function cache_all()
{
@set_time_limit(600);
cache_common();
cache_module();
cache_model();
cache_category();
cache_area();
cache_type();
cache_member_group();
cache_role();
cache_author();
cache_keyword();
cache_copyfrom();
cache_pos();
cache_status();
cache_workflow();
tags_update();
return TRUE;
}
〈?php
/**
mysql数据库类。写得比较简单.也没什么好说的。大家自己看下理解下。
然后就可以跳过了.
*/
defined(’IN_PHPCMS') or exit('Access Denied');
/**
这个东西是不是很熟呀。对了。在上一章已经讲过了。也已经在上一章的common。inc。php 启动文件里面定义了 IN_PHPCMS 所以在以下的PHP文件里都检测下是否是人为”跳墙“进来的。是就中断
*/
/**
* Mysql 数据库类,支持Cache功能
*/
class db_mysql
{
/**
* MySQL 连接标识
* @var resource
*/
var $connid;
/**
* 整型变量用来计算被执行的sql语句数量
* @var int
*/
var $querynum = 0;
/**
* 数据库连接,返回数据库连接标识符
* @param string 数据库服务器主机
* @param string 数据库服务器帐号
* @param string 数据库服务器密码
* @param string 数据库名
* @param bool 是否保持持续连接,1为持续连接,0为非持续连接
* @return link_identifier
*/
function connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect = 0)
{
global $CONFIG;
$func = $pconnect == 1 ? ’mysql_pconnect' : 'mysql_connect’;
/**
mysql_pconnect() 为常连接.它和mysql_connect 的区别是 前者在多进程的WEB服务器上效率比较好。但也有瑕疵就是在有关事务和数据表锁方面。详情请查看自己的手册。
*/
if(!$this-〉connid = @$func($dbhost, $dbuser, $dbpw))
{
$this->halt(’Can not connect to MySQL server’);
}
// 当mysql版本为4.1以上时,启用数据库字符集设置
if($this-〉version() 〉 ’4.1’ && $CONFIG[’dbcharset'])
{
mysql_query("SET NAMES ’".$CONFIG['dbcharset’]。”’” , $this—>connid);
}
// 当mysql版本为5.0以上时,设置sql mode,mysql5数据库带了字符集模式。设置下就好
if($this-〉version() > ’5.0')
{
mysql_query("SET sql_mode=’’” , $this—〉connid);
}
if($dbname)
{
if([email=!@mysql_select_db($dbname]!@mysql_select_db($dbname[/email] , $this-〉connid))
{
$this->halt(’Cannot use database '。$dbname);
}
}
return $this—〉connid;
}
/**
* 选择数据库
* @param string 数据库名
*/
function select_db($dbname)
{
return mysql_select_db($dbname , $this->connid);
}
/**
* 执行sql语句
* @param string sql语句
* @param string 默认为空,可选值为 CACHE UNBUFFERED
* @param int Cache以秒为单位的生命周期
* @return resource
*/
function query($sql , $type = '’ , $expires = 3600, $dbname = ’’)
{
$func = $type == ’UNBUFFERED’ ? 'mysql_unbuffered_query’ : 'mysql_query';
/**
mysql_unbuffered_query 效率更好。节省内存 看手册
*/
if(!($query = $func($sql , $this—〉connid)) && $type != ’SILENT')
{
$this—>halt('MySQL Query Error', $sql);
}
$this—〉querynum++;
return $query;
}
/**
* 执行sql语句,只得到一条记录
* @param string sql语句
* @param string 默认为空,可选值为 CACHE UNBUFFERED
* @param int Cache以秒为单位的生命周期
* @return array
*/
function get_one($sql, $type = ’', $expires = 3600, $dbname = '’)
{
$query = $this->query($sql, $type, $expires, $dbname);
$rs = $this—〉fetch_array($query);
$this-〉free_result($query);
return $rs ;
}
/**
* 从结果集中取得一行作为关联数组
* @param resource 数据库查询结果资源
* @param string 定义返回类型
* @return array
*/
function fetch_array($query, $result_type = MYSQL_ASSOC)
{
return mysql_fetch_array($query, $result_type);
}
/**
* 取得前一次 MySQL 操作所影响的记录行数
* @return int
*/
function affected_rows()
{
return mysql_affected_rows($this—〉connid);
}
/**
* 取得结果集中行的数目
* @return int
*/
function num_rows($query)
{
return mysql_num_rows($query);
}
/**
* 返回结果集中字段的数目
* @return int
*/
function num_fields($query)
{
return mysql_num_fields($query);
}
/**
* @return array
*/
function result($query, $row)
{
return @mysql_result($query, $row);
}
function free_result($query)
{
return mysql_free_result($query);
}
/**
* 取得上一步 INSERT 操作产生的 ID
* @return int
*/
function insert_id()
{
return mysql_insert_id($this—>connid);
}
/**
* @return array
*/
function fetch_row($query)
{
return mysql_fetch_row($query);
}
/**
* @return string
*/
function version()
{
return mysql_get_server_info($this—〉connid);
}
function close()
{
return mysql_close($this->connid);
}
/**
* @return string
*/
function error()
{
return @mysql_error($this—〉connid);
}
/**
* @return int
*/
function errno()
{
return intval(@mysql_errno($this->connid)) ;
}
/**
mysql_errno() 函数也挺好使的哦。自己试下
*/
/**
* 显示mysql错误信息
*/
function halt($message = ’’, $sql = ’')
{
exit("MySQL Query:$sql <br〉 MySQL Error:"。$this-〉error().” 〈br> MySQL Errno:"。$this—>errno()." 〈br> Message:$message”);
}
}
?>
PHPCMS的文本缓存实现:
复制PHP内容到剪贴板
PHP代码:
〈?php
defined(’IN_PHPCMS') or exit('Access Denied’);
/**
这个文件里面全是有关生成文本缓存的函数。文本缓存是个好东西.一般的项目,我们用不着内存缓存 : memcached ,文本搞定.
原理是这样的: 我们在后台是不是可以设置很多有关网站的参数。而这些参数很多都是固定的。就不变化的。都存到咱的数据库上。而我们程序那里呢
每次都要访问数据库读出参数来进行我们程序中的操作.首先数据库查询是个很耗硬盘IO资源的一个东西,所以文本缓存刚好能减轻数据库那边的承重。
我们在程序开始就把数据库里面的配置都转化为数组 等 放到 php文件里面。这样我们可以直接访问php文件而不用每次都访问数据库了。 php文本缓存其实成了
我们程序和数据库的一个中间件。 所以我们自己写自己的文本缓存的时候其实要实现的很简单: 读数据库 —〉 写到PHP文件 —> 程序中include
来吧。开始文本缓存学习
*/
function cache_all() //生成所有缓存的总操作函数
{
cache_table(); //生成所有的数据库表名,表名是根据数据库里面当前的表明而生成。请看这个函数的详细分析
require_once PHPCMS_CACHEDIR.'table.php’; //包含表常量
cache_common();
cache_member_group();
$modules = cache_module();
$channelids = cache_channel(0);
$keyids = array_merge($modules, $channelids);
foreach($keyids as $keyid)
{
$catids = cache_categorys($keyid);
if(is_array($catids))
{
foreach($catids as $catid)
{
cache_category($catid);
}
}
}
cache_type(0);
return TRUE;
}
function cache_common()
{
global $db;
$query = $db->query(”SELECT module,name,iscore,iscopy,isshare,moduledir,moduledomain FROM "。TABLE_MODULE。" WHERE disabled=0”); //查询所有能用的模块
while($r = $db->fetch_array($query))
{
$r[’linkurl'] = ’';
if($r['module'] != ’phpcms' && $r[’iscopy'] == 0) $r[’linkurl’] = linkurl($r[’moduledomain'] ? dir_path($r['moduledomain’]) : $r['moduledir’].'/’);
//如果模块存在目录的就取它目录地址
unset($r[’moduledomain']);
$key = $r[’module’];
$data[$key] = $r;
}
$CACHE[’module'] = $data; //存到缓存数组,等一下一起把 $CACHE 数组写到文本里去
$data = array();
$query = $db—〉query("SELECT channelid,module,channelname,channeldir,channeldomain,channelpic,introduce,style,islink,linkurl,cat_html_urlruleid,item_html_urlruleid,special_html_urlruleid,cat_php_urlruleid,item_php_urlruleid,special_php_urlruleid FROM ”.TABLE_CHANNEL.” WHERE disabled=0 ORDER by listorder”); //罗列能用的频道列表
while($r = $db—>fetch_array($query))
{
$r[’linkurl'] = linkurl($r['linkurl’]);
$key = $r[’channelid’];
$data[$key] = $r;
}
$CACHE['channel’] = $data; //存到缓存数组
$data = array();
$r = $db-〉get_one("SELECT setting FROM ”.TABLE_MODULE.” WHERE module=’phpcms’”);
$CACHE[’phpcms’] = unserialize($r[’setting’]);
//查询 phpcms这个模块的设置信息,大家可以看下数据库这个表内容。setting 字段里面的信息是经过serialize 函数窜行化的.
//所以取出的内容要unserialize 反窜行。我是挺喜欢使用serialize 函数的。他可以实现把一个数组存到数据库或把一个对象存到数据库。或是拿来GET传递都行.
//太强了.大家可以试用下。可能你项目某个地方需要用到哦.
$fields = array();
$result = $db->query("SELECT * FROM ".TABLE_FIELD.” ORDER BY fieldid"); //下栽模块的信息,请自己看下这个表的数据就明白
while($r = $db->fetch_array($result))
{
$tablename = $r[’tablename’];
$fields[$tablename] .= ','.$r['name'];
}
$CACHE[’field’] = $fields;
cache_write('common。php’, $CACHE); //开始把$CACHE 数组写到 common。php 这个文本缓存里。大家可以自己去打开这个文件看下内容.一切了然
return $CACHE;
}
function cache_update($action=’')//更新文本缓存.最好在后台操作使用。因为PHP的文件flock 文件锁在某些平台使用不是很好.会出现多用户同写一个文件从而破坏缓存文件
{
global $db;
$data=array();
switch($action)
{
case ’keylink';
$query=$db->query(”SELECT linktext,linkurl FROM ”。TABLE_KEYLINK." where passed=1”);
while($r=$db->fetch_array($query)){
$data[]=$r;
}
break;
case 'reword';
$query = $db->query("SELECT word,replacement FROM "。TABLE_REWORD。" where passed=1”);
while($r = $db->fetch_array($query))
展开阅读全文