phpcms分析
踩踩 0作者:qiyun 发表日期:2008-10-30 复制链接 收藏
require PHPCMS_ROOT.'/include/'.$db_file.'.class.php'; // 包含数据库操作类,下章详说 RV$Vt4 &
require PHPCMS_ROOT.'/include/tag.func.php'; //遇到再说 <q0";X"p8
require PHPCMS_ROOT.'/include/extension.inc.php'; //遇到再说 l )o!/ M,
$db = new $db_class; // 实例化数据库类 f &<Jp\
$db->connect($CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpw'], $CONFIG['dbname'], $CONFIG['pconnect']); //连接数据库@_@ 8z\-%WL3
$db->iscache = $CONFIG['dbiscache']; //是否开启SQL缓存 *J4\xvWK@
$db->expires = $CONFIG['dbexpires']; //缓存时间 X2-06, 5#
if(!cache_read('table.php')) w tWE7
{ PzbTf Z+I
require_once PHPCMS_ROOT.'/include/cache.func.php'; nv-th&%Cb
cache_all(); //生成所有缓存 gHa.aK"
} ~?0.<bNg
/** ;FqoFk
cache_read() 函数 读缓存文件函数存在 global.func.php 里面.上菜先: x!&+ N&fL
function cache_read($file, $mode = 'i') f.uc7z
{ 'Gm[f%k
$cachefile = PHPCMS_CACHEDIR.$file; cApL(*As
if(!file_exists($cachefile)) return array(); j81>hHNs)!
return $mode == 'i' ? include $cachefile : file_get_contents($cachefile); BRcN9t#$#
} URSc:tC
就这么简单.文本缓存,在一些大的开源的PHP项目中经常见到.主要是为了减轻数据库的负荷的. 比如在程序启动文件里面,就把一些后台配置的常用信息缓存到php文件里面.然后在以后的程序就可以直接使用而不用每次都访问数据库了.但对经常要更新的信息.最好不要用文本缓存这形式,因为PHP文件内置的文件锁flock()不是很好用.大系统中多用户同时写访问的时候有可能会把缓存文件破坏.大系统建议使用 memcached mysql5.1 分区 mysql 主从 来实现负载均衡 @=@ 废话太多了. 这个函数很简单.自己看下就明白了.如果缓存和模式变量 $mode 是否为 i 是就include 不是就 把文件以字符窜形式读到内存中. kg@+)!H'
如果 cache_read()找不到缓存文件'table.php'就会返回false,那么就 加栽 cache.func.php 文件.它里面是些创建缓存的一些函数. 然后呢执行 cache_all()函数生成所有的常用信息缓存. 9 ryr
关于phpcms 的缓存更详细包括生成原理.打算在弄完启动文件common.inc.php 后再开篇写个详细的. qHcccaMgo~
*/ Uw1A6NnB
$CACHE = cache_read('common.php'); :NTqh%u?"
/** en@i$ wk2
加载 common.php 缓存文件里面的变量(数据) 这样我们不用从数据库读了每次.是吧 L!/v8<b%
common.php 文件里面是什么来的呢?上菜: ^ i PPC
<?php 5K=Wyemo
return array ( UZkkeT[)
'module' => :^yJRTEHF
array ( d,K~kw_yU
'phpcms' => 2SwPIiSu
array ( >>z/8o -s
'module' => 'phpcms', YmmZ"xPX
'name' => 'phpcms', IJR`F hm
'iscore' => '1', qMAZ+#UOg
'iscopy' => '0', \,0( ID|
'isshare' => '0', W4F"XgWX
'moduledir' => '', Y\YEV!nO
'linkurl' => '', zy?3+x
), T7Dw&&)M
'member' => w5gBR0e1/
array ( >gGoH#{$TE
'module' => 'member', F7EI& 8
'name' => '会员', 4&-bp)E
'iscore' => '1', r"/} I}E
'iscopy' => '0', jO4b A
'isshare' => '0', f UX%
'moduledir' => 'member', =4_[(M}V|
'linkurl' => '/phpcms/member/', -SH15vSVIr
), -S^oMST
'article' => 0RIQw M8
array ( nE<//!
'module' => 'article', C^TqV{
'name' => '文章', a 80cT
'iscore' => '0', ='QWM-q
'iscopy' => '1', CH !9k-
'isshare' => '0', $p"k}"jt
'moduledir' => 'article', ]<, iNa
'linkurl' => '', w2:> Z
) '2 iH&#$`Z
?> 02ZZWn|8>
看到了吧.这个就是全部从数据库里面生成的文本缓存信息.我们不用每次都连接数据库读数据库.而只要访问里面的数组就可以得到一些配置信息. NMP;l
这个就是文本缓存的作用了,至于怎么会生成这个文本缓存文件的.我会另外开一篇来介绍。 I4 `?
*/ cy p^vW
$MODULE = $CACHE['module']; //缓存中的数据 ,@P* z
$CHANNEL = $CACHE['channel']; .-HW [@
$PHPCMS = $CACHE['phpcms']; n]T'FI4
$FIELD = $CACHE['field']; u.h^Z?&c!
unset($CACHE, $ipmatches, $CONFIG['timezone'], $CONFIG['cachedir'], $CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpw'], $CONFIG['pconnect'], $CONFIG['dbiscache'], $CONFIG['dbexpires']); &vp>]5~
/** #0DX1 q
unset 掉不需要用的变量. d, f+?S
*/ FFYNB|
if($PHPCMS['enablebanip'] && ip_banned($PHP_IP)) showmessage($LANG['administrator_banned_this_IP']); \a{SLOk
/** <5NGq
$PHPCMS['enablebanip'] 是什么.不用说应该知道了吧.这个就是后台里面设置是否开启过滤IP访问的功能.(因为我没用过phpcms,我是按照代码猜的,不对的请指出)从这里就看出了文本缓存也有他的作用的。 ip_banned()函数是什么呢.上菜再说: bpFUG8
function ip_banned($ip) _,8 YoCw
{ -UXB?z`E5
global $PHP_TIME; //前面定义过的.当前的时间 I /fz(%ux
$ipbanneds = cache_read('banip.php'); 98"\* 7b
if(!is_array($ipbanneds)) return FALSE; 0& !{q2<y
foreach($ipbanneds as $v) 5 N-=+Bn
{ XE.26cr<
if($v['overtime'] < $PHP_TIME) return FALSE; z/x)b
if($ip == $v['ip'] || preg_match("/^".str_replace('.', '[.]', $v['ip'])."$/", $ip)) return TRUE; =#i!rvc|K
} ,@/.CxVdp
} g:Co\q?OC
里面也用到了 cache_read() 这个函数,还是读banip.php 这个文件.banip.php这个文件里面存着你在后台甚至的要过滤的IP列表. E$tK[4/H+
里面的逻辑比较简单.自己消化下了.不明白跟帖问 0~ell8
showmessage() 函数是提示出错信息封装好的一个函数. 国家化的 $LANG['administrator_banned_this_IP']这个看到了吧.这个就是读语言包里面的.这样我们就可以出好多个语言版本的程序拉. AVgWnbg
*/ Fj~.u^vk2
$TEMP = $MOD = $CHA = $CATEGORY = $CAT = array(); `D2s Z
$ftp = $enableftp = $tags = $html = 0; DyeHXP#A
/** w#>@Dc
初始化变量.这个是好习惯我们要模仿. fcQl+RklH%
*/ EB ^]Sh\%1
if(!isset($mod)) K\]^ ?
{ )ORYWI%
$mod = 'phpcms'; //phpcms 是默认加载的模块 pnEeo8q
} l&[5IN"
elseif($mod != 'phpcms') ~00u""s;
{ dbA+dd#
isset($MODULE[$mod]) or exit($LANG['module_not_exists']); // 从缓存中读加载的模块是否开启 (CwRhm Wb
/** %d=D:-\
这个写法,我十分喜欢,平时也用. xx && dd ; xx and dd ;与运算要同时两边都为真整个公式才为真,就是利用这个原理. ; xx || dd ; xx or dd 或运算只要一个条件满足就不会执行下一个条件而继续执行下去. 这样写是不是很酷. Zk]Ik(I
*/ _nGHX`9T
$MOD = cache_read($mod.'_setting.php'); //开始加载这个模块的一些常用配置数值。 phpcms 对应的每个模块都有一个缓存配置文件。@@ 怪不得速度那么快 `Cg9>cL
@include PHPCMS_ROOT.'/languages/'.(defined('IN_ADMIN') ? $CONFIG['adminlanguage'].'/'.$mod.'_admin.lang.php' : $CONFIG['language'].'/'.$mod.'.lang.php'); k "*$Jh
/** >.{-h,12 0
加载想对应的模块语言包. Rfe|xmIU
*/ a;J-WSPt
} nDj2%T.YP1
if(!isset($forward)) $forward = $PHP_REFERER; //记录前一个URL地址。估计以后下面程序有需要用这个变量 =M"HRBa]0
$dosubmit = isset($dosubmit) ? 1 : 0; //记录是否有表单提交过.也是以后有用 NHW!9t8T
$channelid = isset($channelid) ? intval($channelid) : 0; //记录当前频道的id 如果$channelid 没有 isset 那么就为 0. intval() 十分有用。数字和数字的比较加减速度会快很多。记得哦 $Beg>r1hR
$skindir = PHPCMS_PATH.'templates/'.$CONFIG['defaulttemplate'].'/skins/'.$CONFIG['defaultskin']; //加载默认phpcms皮肤 nqqV7_;1
if($PHPCMS['enablegzip'] && function_exists('ob_gzhandler')) DF[06c?
{ !FvTA:Ows
($CONFIG['phpcache'] || defined('SHOWJS')) ? ob_start() : ob_start('ob_gzhandler'); *`nzSh7`
} aR 9@\?7
else \qn E1
{ 7y][ w!(
$PHPCMS['enablegzip'] = 0; b 6 !; \f
ob_start(); 7t5{97nSS
} FHX$.SX
/** W0<4xX]-1
$PHPCMS['enablegzip'] 这个变量就是存在于 phpcms_setting.php 文件里。上面已经说过了。每个模块都有相对应的模块配置缓存文件(是从数据库copy过来的信息) 这个变量标致 是否开启 压缩传输。 Xz[y@J
压缩传输,听名字就知道。就是把数据按照一定的算法压缩小罗。然后再传送到客户端。这样就可以在有限的带宽中传输更大的数据拉。当然速度快了不少。压缩的数据到了你的浏览器,它就自动解压缩,老版本的一些浏览器不支持解压缩哦。不过现在还有谁用很久的浏览器呢。用法很简单的:看上面就知道: *<T2
首先判断下,看客户老大们是否在后台选择了这个模块的压缩传输(如果是的话。自然的已经加载到了相对应的文本缓存文件里面拉) 标致:$PHPCMS['enablegzip'] 和 判断 回调函数 ob_gzhandler 是否开启, ob_gzhandler 其实不算是个函数。看手册说明。 就这么简单。它只是一个专门给 ob_start() 做回调使用的一个参数函数。详细请看下手册。别偷懒哦,在程序开头ob_start('ob_gzhandler')就算是开始压缩传输了;判断完了 如果为真。就继续下面的代码: H*l 9jV
$_)[=~P :|
($CONFIG['phpcache'] || defined('SHOWJS')) ? ob_start() : ob_start('ob_gzhandler'); / }t m*M
看代码phpcms 是这样的: 如果用户在后台开启了压缩传输。而用户又开启了 页面缓存。那么就默认不使用压缩传输了。我也不知道为什么这样设计。我测试了下。后台开启压缩传输。又同时又使用页面缓存。没发现有什么问题。@@ ^"+Ux`>,
如果没开启压缩传输,那么我们就ob_start(); 使用session 之前必须要 ob_start() ; 而且在ob_start() 之前不能有任何的 头文件发送和输出。比如:echo header等要不会出错的哦。 lv=uDM;~g
*/ ^8#-;J\F0
$_userid = 0; 0eObF;Kj
$_username = ''; }"p9O!7@X
$_groupid = 3; J5Y9pYRy
$_arrgroupid = array(); ].UIVEau
$phpcms_auth = getcookie('auth'); x=qi^er
/** ' M750L
$_userid,$_username,$_groupid 这几个记录用户信息的变量初始化,不初始化危险就太大了。@@ 如果给人家$_GET一个 _userid 变量过来。那么就会把我们这个变量覆盖。但是我们如果给这几个变量一个值, D 1\
那么按照就近原则。就算你GET个变量过来。你也一样改不了我原来的变量值。大家好好自己想下。就会明白了。 FVEt$eA$
getcookie() 这个自定义函数在 global.func.php文件里定义的。上菜: vbo:sw,!dH
function getcookie($var) 5apt R}
{ lvMrLQ1
global $CONFIG; dMo^4HLf
$var = $CONFIG['cookiepre'].$var; *:/lGt:9J
return isset($_COOKIE[$var]) ? $_COOKIE[$var] : FALSE; 32xzVsJnm
} Q=9xC~E$
这个函数用来提取我们设置的cookie 值. $CONFIG['cookiepre'] 在 config.inc.php 文件里面设置,cookie 名的前缀. 函数很简单。一看就明白不说了。 ;@=q,|
*/ B,K:^{t3
if($phpcms_auth) Hj9 i+S(J
{ F`"kh}D
$phpcms_auth_key = md5($PHPCMS['authkey'].$_SERVER['HTTP_USER_AGENT']); s#}F;.
list($_userid, $_password, $_answer) = $phpcms_auth ? explode("\t", phpcms_auth($phpcms_auth, 'DECODE')) : array(0, '', ''); a6ZRFTv
/** C`8pA:^nb
list() = array(); 用户大家自己试下。 意会下 bQOiF36
phpcms_auth() 是加密和解密 函数, 因为cookie 是存在于客户端。十分危险呀。 你看连用户的密码也存在cookie 不加密能行吗。但是呢加密后又要能解密。因为用户名和用户密码我们往下操作要 Yz O4=
获取的。 这个函数存在于 global.func.php 文件里面。大家想了解这个算法的自己去看下吧。挺简单的。 其实就是围绕着 $phpcms_auth_key 这个变量来加密解密和discuz 的cookie 机制差不。 ]rX*oD2Q}N
$phpcms_auth_key = md5($PHPCMS['authkey'].$_SERVER['HTTP_USER_AGENT']); 看$PHPCMS['authkey'],估计后台有个 cookie 加密值让你填,然后以这个值和 $_SERVER['HTTP_USER_AGENT'](系统信息) PqX@+}S<
*/ 9E{-gN
$_userid = intval($_userid); 2ACkW~]V
if($_userid < 0) $_userid = 0; //读出的cookie 的用户id 如果是 小于0 mXJ|k
if($_userid) //如果 cookie 保存的这个uid 存在,那么开始按照这个ID来查数据库用户表 来取出用户信息 )vz$o #
{ -84g~_I6
$memberinfo = $db->get_one("SELECT username,password,groupid,arrgroupid,email,chargetype,begindate,enddate,money,point,credit,newmessages FROM ".TABLE_MEMBER." WHERE userid=$_userid LIMIT 0,1"); MXB.;9l&M
/** f:7> G-
phpcms 封装好的数据库类,下篇开讲这个大家就大概看行了。 大家看下 select sql语句。 也可以学习下。 首先最好不要使用 select * from xx 的 * 形式,除非你想获取所有字段的记录。只罗列你要的字段。这样在数据量大的查询中。速度明显上去。 常量: TABLE_MEMBER 定义了表名。这样做有什么好处呢?想都知道了,为了以后变更表名方便而定义为常量。这个东西那里来的。估计在一个文件里面定义好的。遇到了再讲吧懒得找了。 )rw0NNR
*/ csrc Dw'I
if($memberinfo && $memberinfo['password'] == $_password) //用查询出来的密码和 cookie 中存在的密码想对比.为了在效率: 在比较前 先判断查询是否成功先。很多phper往往忽略。 > 0S+TN2v"
{ F?6-X7
if($memberinfo['groupid'] == 2) //如果用户属于的组的ID 为 2 那么这个用户是被管理员禁止访问的了。 AKqU? 6z8
{ T)5q\Xl
mkcookie('auth', ''); // 清除cookie _BVG L$*
showmessage($LANG['userid_banned_by_administrator']); //提示出错菜单 j{5@C"Gv
} e?9'Hq$08
@extract($memberinfo, EXTR_PREFIX_ALL, ''); //又来这招,应该明白了吧各位老大:把字段 变成 我们能直接使用的变量 Df@p:,
unset($memberinfo, $_password, $_answer); zp/U
$_arrgroupid = $_arrgroupid ? array_filter(explode(',', $_arrgroupid)) : array(); //把 字段为 arrgroupid 值为 FALSE 过滤掉。array_filter()不带回调参数的用法,请看手册。 u Z3+41
} Y:_SsU
else =8-^J'RX
{ G LHhi 9Cu
mkcookie('auth', ''); +i@4P|j
} ;^EO%6T{D
/** %h[ybeqC
经过上面的读cookie 和查数据库用户信息后。当确定这个用户信息是合法以后。就会自动登陆了。比如phpchina论坛。当你登陆后没注销。下次访问的时候还是登陆状态。就是这个原理。记得模仿哦 Zk@jt}Q
这里详细解释下 mkcookie ()函数 上菜: t\} x) :
function mkcookie($var, $value = '', $time = 0) 2`<O`FkHA
{ Z$D@$YVrB
global $CONFIG,$PHP_TIME; /n[,$dX-t
$time = $time > 0 ? $time : (empty($value) ? $PHP_TIME - 3600 : 0); p\pK 'sff
$s = $_SERVER['SERVER_PORT'] == '443' ? 1 : 0; _SS9K
$var = $CONFIG['cookiepre'].$var; {e mm$r?!
return setcookie($var, $value, $time, $CONFIG['cookiepath'], $CONFIG['cookiedomain'], $s); 0Kk &z=j
} Fe~{o=yW$
$time 为cookie 的存活时间: 如果为 0 就是关闭浏览器 cookie 就自动失效 , $PHP_TIME 在前面定义了:当前时间。 $PHP_TIME -3600 减去3600秒。就是一个小时前的意思,那肯定是设置cookie 失效的意思了。 ycY(MDw6"
$s 变量是 获取 是否开启SSL安全传输的标致。 cookie 有一个参数是ssl传输的。如果服务器已经opensll 了那么我们肯定不能浪费这么好的安全资源了。 Z:ITy,Xt
$var cookie名的前缀,主要防止混淆。 - ?{uV$`K
$CONFIG['cookiedomain'] 这个家伙在 config.inc.php里面已经配置的了。定义为: '/' 意思就是说 在当前域 的所有目录的PHP程序都能访问这个COOKIE ,还有限制目录访问COOKIE 的弄法。具体请看 setcookie () 函数手册上说明。 ~0ms xZ
*/ W"iXji
r2z]0,h^
} GpRKQbLT(t
} z~?7`jaH;
unset($db_class, $db_file, $phpcms_auth, $phpcms_auth_key, $memberinfo); <RRt(>ZKU^