好久没有开始写一篇像样的技术文档了,五一难得有这么多的时间,就早起来写一篇好的文章给大家吧~最近都忙一些自己的事情,没多少机会上网来回答问题,实在抱歉……
7J%sdZ;j7A_#jO701201好了,言归正传,这次我打算写一个系列的文章,把Discuz的核心文件的源代码一一分解解释出来,大家都知道Discuz的源代码是很经得起时间的考验的,是众多程序员智慧的结晶,我想大家能借鉴一下也是很不错的,唯一一点不好就是,不是OOP(面向对象)的,我最近看了几个框架(framework),也用了一下,感觉OOP的编程让人热血沸腾,大大提高了开发效率,一个小型论坛的开发的话不用像Discuz 这样写这么这么多的代码,很是不错,不过说到面向对象,当然要看看Java,Jsp 或ASP.NET,前两个看得我郁闷,没看了,只学会了ASP.NET,感觉很不错,比PHP先进多了,针对事件、驱动编程,封装,编译,跨平台,听着就觉得很帅了,很适合大型应用,呵呵,扯远了……
SupeSite/X-Space官方站3ikD(EK Y ]
Section One:
7J%sdZ;j7A_#jO701201好了,言归正传,这次我打算写一个系列的文章,把Discuz的核心文件的源代码一一分解解释出来,大家都知道Discuz的源代码是很经得起时间的考验的,是众多程序员智慧的结晶,我想大家能借鉴一下也是很不错的,唯一一点不好就是,不是OOP(面向对象)的,我最近看了几个框架(framework),也用了一下,感觉OOP的编程让人热血沸腾,大大提高了开发效率,一个小型论坛的开发的话不用像Discuz 这样写这么这么多的代码,很是不错,不过说到面向对象,当然要看看Java,Jsp 或ASP.NET,前两个看得我郁闷,没看了,只学会了ASP.NET,感觉很不错,比PHP先进多了,针对事件、驱动编程,封装,编译,跨平台,听着就觉得很帅了,很适合大型应用,呵呵,扯远了……
QUOTE:
第一个文件当然是分析./include/common.inc.php这个文件,这个是Discuz的核心中的核心,基本上每次操作都include到了这个文件,下面就分七段来分析这个文件: SupeSite/X-Space官方站2m bS.ayk h ]lu申明下版权:
1.这里面的每个中文字都是我打的,code部分是引用的,当然我也加了一点注释在里面了。2.如果要转载的话请注明
CODE:
转自[url]www.discuz.net[/url] 作者:郭鑫
3.由于我个人的能力有限,写这篇文章没有参考一点资料,甚至连本地环境也没有搭建(遇到了白屏问题),所以难免会有错误的地方,大家发现了的话请跟帖或者联系我吧,我会尽快更正。
SupeSite/X-Space官方站3ikD(EK Y ]
Section One:
QUOTE:
Section Two:CODE:
//定义PHP一些环境SupeSite/X-Space官方站2psnx3x
这一段基本上就是设置一下错误报告,把magic_quotes这个sick家伙给关了,然后定一个开始的时间,这样我们在论坛底部看到的Process Time就是通过这个开始的时间和一个结束的时间的差来计算的,然后定义一个IN_DISCUZ为真,这个IN_DISCUZ常量的作用就是在其他inc这样的包含文件中防止被非法引用,一旦没有这个常量的话就出现Access Denied这样的字样然后退出。然后获得Discuz运行的绝对目录。接下来是判断PHP 的版本是4.1 以下还是以上,因为PHP以4.1为一个分界线,在4.1以下以$HTTP_GET_VARS[‘xx’]这样的方式来得到get过来的值,而以后用$_GET来得到get过来的值,这样做的目的是为了无论是什么样的PHP版本,都能用$_GET这样的方式得到,有通用性~!
error_reporting(0);
~(jXP[701201set_magic_quotes_runtime(0);SupeSite/X-Space官方站G5~5YF"n,e6LR5N
_v Bzy _p701201//设置Discuz开始的时间SupeSite/X-Space官方站do}5O zteI$^
$mtime = explode(' ', microtime());
!mZ+S!se8U/B [701201$discuz_starttime = $mtime[1] + $mtime[0];
b5XB#o3Uq j4U701201SupeSite/X-Space官方站B$UOJWZ8]-B0I
//定义一些常量
:b0w.Enw,R701201define('SYS_DEBUG', FALSE);
~!qj*ra'p701201define('IN_DISCUZ', TRUE);SupeSite/X-Space官方站` hs"r/+go4c
define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -7)); //获得绝对目录
q~9_ AaC)]L701201SupeSite/X-Space官方站(PW`O&|'z2YV7Y
//通用性
l}.Td#O701201if(PHP_VERSION < '4.1.0') {SupeSite/X-Space官方站 ?Tt`1~n8mH
$_GET = &$HTTP_GET_VARS;SupeSite/X-Space官方站T q ?H;n_$~
$_POST = &$HTTP_POST_VARS;
Uj!] ~wv701201 $_COOKIE = &$HTTP_COOKIE_VARS;
5B`l2/-zG;T701201 $_SERVER = &$HTTP_SERVER_VARS;SupeSite/X-Space官方站1v2FFA'Y Sm
$_ENV = &$HTTP_ENV_VARS;
u/E @q&E5V t)}701201 $_FILES = &$HTTP_POST_FILES;SupeSite/X-Space官方站+R|QQo m L
}
QUOTE:
Section Three:CODE:
require_once DISCUZ_ROOT.'./include/global.func.php';
把include/global.inc.php引用进来,这个文件是Discuz的核心函数文件,包含了Discuz用到的很多通用的函数,可以说它就是一个大的通用函数库。CODE:
define('ISROBOT', getrobot());
这里是定义一个ISROBOT常量,看看浏览者是什么东东,比方说如果浏览者是一个robot那么就直接来一个 403 Forbidden了……
E1Q+q%F4l-/%V701201if(defined('NOROBOT') && ISROBOT) {
1m*h,aU@.kw701201 exit(header("HTTP/1.1 403 Forbidden"));SupeSite/X-Space官方站I Bd"n)DFZ T
}CODE:
define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());SupeSite/X-Space官方站8fSU ^F7m /6m
此处是过滤提交的变量用的,提高安全性的用法。。
isset($_REQUEST['GLOBALS']) && exit('Access Error');
L1Ko1M%W;w9_g701201foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
k|'o1CA;n c)r:v701201 foreach($$_request as $_key => $_value) {
G(hI+W*}n;t701201 $_key{0} != '_' && $$_key = daddslashes($_value);SupeSite/X-Space官方站'zb'{ R qp*?%H
}
Q`8E G*HS701201}SupeSite/X-Space官方站6v H?9P~!/ y
(!MAGIC_QUOTES_GPC) && $_FILES = daddslashes($_FILES);CODE:
$charset = $dbcharset = $forumfounders = $metakeywords = $extrahead = '';
初始化一些变量,然后引用config.inc.php这个配置文件,这样开始初始化程序的一些东西了。接下来的一个循环把$_COOKIE中的东西取出来存到$_DCOOKIE这个数组中。注意:在登陆的时候Discuz会把登陆信息存放到$_COOKIE中去。在下面一段会有取出的代码。
:rB zu.]8fL701201$plugins = $hooks = $admincp = array();
a;Ng^8`8Y9n.R9Z701201
u~O*Gp/j701201require_once DISCUZ_ROOT.'./config.inc.php';SupeSite/X-Space官方站$ksSJ sb3x
7RZ%jKZ a"n r701201$_DCOOKIE = $_DSESSION = $_DCACHE = $_DPLUGIN = $advlist = array();SupeSite/X-Space官方站 yB XY#wV7{
SupeSite/X-Space官方站F'SG:@@WR1Wj
$prelength = strlen($cookiepre);
~s3EpH*~uI2{;h701201foreach($_COOKIE as $key => $val) {
:gv1mR!N ssK701201 if(substr($key, 0, $prelength) == $cookiepre) {
(mW_5U9F`t%IR*x701201 $_DCOOKIE[(substr($key, $prelength))] = MAGIC_QUOTES_GPC ? $val : daddslashes($val);
IA;[mh4g701201 }
(?ZKt(B+g+/ @(v~M701201}CODE:
unset($prelength, $_request, $_key, $_value);SupeSite/X-Space官方站C!Dhhs
这一部分是如果是提高安全用的,防一些非法的入侵,include/security.inc.php文件中就是这样一些检查。
$timestamp = time();SupeSite/X-Space官方站E)hG |,iR
SupeSite/X-Space官方站pN nDvX s
if($attackevasive) {SupeSite/X-Space官方站0}L+/Zr
require_once DISCUZ_ROOT.'./include/security.inc.php';
/_2Zy/pcC-h{701201}CODE:
require_once DISCUZ_ROOT.'./include/db_'.$database.'.class.php';
第一行是把include/db_mysql.class.php引用进来,这个文件是一个数据库的类。我觉得是不是放在这里太早了点?
kmR*I6G3|701201
G~7J6E*Hs%A0]WY701201SupeSite/X-Space官方站r'`6D8m(Sr _
$PHP_SELF = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];SupeSite/X-Space官方站7N_RfWD'O~
$SCRIPT_FILENAME = str_replace('', '/', (isset($_SERVER['PATH_TRANSLATED']) ? $_SERVER['PATH_TRANSLATED'] : $_SERVER['SCRIPT_FILENAME']));
3/9`0M] ^d'G5k4v701201$boardurl = 'http://'.$_SERVER['HTTP_HOST'].preg_replace("///+(api|archiver|wap)?//*$/i", '', substr($PHP_SELF, 0, strrpos($PHP_SELF, '/'))).'/';
8ge|&d.U2] m.n701201SupeSite/X-Space官方站WG_V(f7xi1R
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {SupeSite/X-Space官方站7I,H$e4y:Yk-]
$onlineip = getenv('HTTP_CLIENT_IP');
4aW7`+QV(i8gK701201} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {SupeSite/X-Space官方站,q@/,f1o:al
$onlineip = getenv('HTTP_X_FORWARDED_FOR');
.U |7YL([e{Vd701201} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {SupeSite/X-Space官方站x.H| ktdJ&Uk[
$onlineip = getenv('REMOTE_ADDR');SupeSite/X-Space官方站/Y7EW? HR!g6L/J
} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {SupeSite/X-Space官方站$h};ea.g
$onlineip = $_SERVER['REMOTE_ADDR'];SupeSite/X-Space官方站E,J7vx7C*W1@g&O
}
GWUq.U701201然后接下的作用就是得到自身的名称$PHP_SELF,自身的文件名字$SCRIPT_FILENAME,论坛的地址$boardurl,得到浏览者的一些信息,比方说ip地址,浏览器类型等等。 SupeSite/X-Space官方站(~+zCV0j"p1s
QUOTE:
CODE:
preg_match("/[/d/.]{7,15}/", $onlineip, $onlineipmatches);SupeSite/X-Space官方站,c6t2]~/l:e4j
看看ip是不是点分段,7-15个数字之间,用到了一个正则表达式,
$onlineip = $onlineipmatches[0] ? $onlineipmatches[0] : 'unknown';SupeSite/X-Space官方站;p J EQ:D]!Z
unset($onlineipmatches);CODE:
$cachelost = (@include DISCUZ_ROOT.'./forumdata/cache/cache_settings.php') ? '' : 'settings';SupeSite/X-Space官方站R$P5K!V[
这一段是获得./forumdata/cache/cache_settings.php(即缓存下的设置数组,并展开,方面以后的写法
@extract($_DCACHE['settings']);CODE:
if($gzipcompress && function_exists('ob_gzhandler') && CURSCRIPT. != 'wap') {SupeSite/X-Space官方站DK A(f6Pmh!nW
检查gzip是不是打开了,打开就用ob_gzhandler,没有就用ob_start。
ob_start('ob_gzhandler');SupeSite/X-Space官方站:Y!~ GV+_3n
} else {
sVr)Qy1t4]7P701201 $gzipcompress = 0;
b:T'HN*?,sy701201 ob_start();
"iD F!n6v ~"p:[h%w701201}CODE:
if(!empty($loadctrl) && substr(PHP_OS, 0, 3) != 'WIN') {SupeSite/X-Space官方站i9E1[tW ?c.V
看到了熟悉的service unavailable了吧?呵呵,平衡负载用的。
if($fp = @fopen('/proc/loadavg', 'r')) {
m ~K0[mO701201 list($loadaverage) = explode(' ', fread($fp, 6));
_w jV*?2K,I)tF}8]701201 fclose($fp);SupeSite/X-Space官方站W,G /YWM*]!B
if($loadaverage > $loadctrl) {SupeSite/X-Space官方站x4|}.WV+ZlI
header("HTTP/1.0 503 Service Unavailable");SupeSite/X-Space官方站%zEP2H X J3]
include DISCUZ_ROOT.'./include/serverbusy.htm';
P(@HZ Y2O /701201 exit();SupeSite/X-Space官方站 `Iw2SLal
}SupeSite/X-Space官方站Q1E} M4I.L r
}SupeSite/X-Space官方站-Cc-zZ2w3RI)p0u
}CODE:
if(defined('CURSCRIPT') && in_array(CURSCRIPT, array('index', 'forumdisplay', 'viewthread', 'post', 'blog', 'pm', 'topicadmin', 'register', 'archiver'))) {SupeSite/X-Space官方站 M9j%p0z J#x5?A#g
看看是不是index, forumdisplay, viewthread这些文件是不是缓存了,有的话把它装到$cachelost这个变量中。
$cachelost .= (@include DISCUZ_ROOT.'./forumdata/cache/cache_'.CURSCRIPT.'.php') ? '' : ' '.CURSCRIPT;SupeSite/X-Space官方站1Q4v?!b G&H4v{4|`A
}