找回密码
 注册

QQ登录

只需一步,快速开始

查看: 373|回复: 2

Discuz!源代码分析系列(1)--./include/common.inc.php

[复制链接]
发表于 2011-8-15 09:26:15 | 显示全部楼层 |阅读模式
好久没有开始写一篇像样的技术文档了,五一难得有这么多的时间,就早起来写一篇好的文章给大家吧~最近都忙一些自己的事情,没多少机会上网来回答问题,实在抱歉……
好了,言归正传,这次我打算写一个系列的文章,把Discuz的核心文件的源代码一一分解解释出来,大家都知道Discuz的源代码是很经得起时间的考验的,是众多程序员智慧的结晶,我想大家能借鉴一下也是很不错的,唯一一点不好就是,不是OOP(面向对象)的,我最近看了几个框架(framework),也用了一下,感觉OOP的编程让人热血沸腾,大大提高了开发效率,一个小型论坛的开发的话不用像Discuz 这样写这么这么多的代码,很是不错,不过说到面向对象,当然要看看Java,Jsp 或ASP.NET,前两个看得我郁闷,没看了,只学会了ASP.NET,感觉很不错,比PHP先进多了,针对事件、驱动编程,封装,编译,跨平台,听着就觉得很帅了,很适合大型应用,呵呵,扯远了……
申明下版权:
1.这里面的每个中文字都是我打的,code部分是引用的,当然我也加了一点注释在里面了。
2.如果要转载的话请注明
  1. //定义PHP一些环境

  2. error_reporting(0);

  3. set_magic_quotes_runtime(0);



  4. //设置Discuz开始的时间

  5. $mtime = explode(' ', microtime());

  6. $discuz_starttime = $mtime[1] + $mtime[0];



  7. //定义一些常量

  8. define('SYS_DEBUG', FALSE);

  9. define('IN_DISCUZ', TRUE);

  10. define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -7)); //获得绝对目录



  11. //通用性

  12. if(PHP_VERSION < '4.1.0') {

  13.         $_GET = &$HTTP_GET_VARS;

  14.         $_POST = &$HTTP_POST_VARS;

  15.         $_COOKIE = &$HTTP_COOKIE_VARS;

  16.         $_SERVER = &$HTTP_SERVER_VARS;

  17.         $_ENV = &$HTTP_ENV_VARS;

  18.         $_FILES = &$HTTP_POST_FILES;

  19. }复制代码

  20. 这一段基本上就是设置一下错误报告,把magic_quotes这个sick家伙给关了,然后定一个开始的时间,这样我们在论坛底部看到的Process

  21. Time就是通过这个开始的时间和一个结束的时间的差来计算的,然后定义一个IN_DISCUZ为真,这个IN_DISCUZ常量的作用就是在其他inc
  22. 这样的包含文件中防止被非法引用,一旦没有这个常量的话就出现Access
  23. Denied这样的字样然后退出。然后获得Discuz运行的绝对目录。接下来是判断PHP 的版本是4.1
  24. 以下还是以上,因为PHP以4.1为一个分界线,在4.1以下以$HTTP_GET_VARS[‘xx’]这样的方式来得到get过来的值,而以后
  25. 用$_GET来得到get过来的值,这样做的目的是为了无论是什么样的PHP版本,都能用$_GET这样的方式得到,有通用性~!
复制代码


Section Two:
  1. preg_match("/[\d\.]{7,15}/", $onlineip, $onlineipmatches);

  2. $onlineip = $onlineipmatches[0] ? $onlineipmatches[0] : 'unknown';

  3. unset($onlineipmatches);复制代码

  4. 看看ip是不是点分段,7-15个数字之间,用到了一个正则表达式,

  5. $cachelost = (@include DISCUZ_ROOT.'./forumdata/cache/cache_settings.php') ? '' : 'settings';

  6. @extract($_DCACHE['settings']);复制代码

  7. 这一段是获得./forumdata/cache/cache_settings.php(即缓存下的设置数组,并展开,方面以后的写法

  8. if($gzipcompress && function_exists('ob_gzhandler') && CURSCRIPT != 'wap') {

  9.         ob_start('ob_gzhandler');

  10. } else {

  11.         $gzipcompress = 0;

  12.         ob_start();

  13. }复制代码

  14. 检查gzip是不是打开了,打开就用ob_gzhandler,没有就用ob_start。

  15. if(!empty($loadctrl) && substr(PHP_OS, 0, 3) != 'WIN') {

  16.         if($fp = @fopen('/proc/loadavg', 'r')) {

  17.                 list($loadaverage) = explode(' ', fread($fp, 6));

  18.                 fclose($fp);

  19.                 if($loadaverage > $loadctrl) {

  20.                         header("HTTP/1.0 503 Service Unavailable");

  21.                         include DISCUZ_ROOT.'./include/serverbusy.htm';

  22.                         exit();

  23.                 }

  24.         }

  25. }复制代码

  26. 看到了熟悉的service unavailable了吧?呵呵,平衡负载用的。



  27. if(defined('CURSCRIPT')
  28. && in_array(CURSCRIPT, array('index', 'forumdisplay',
  29. 'viewthread', 'post', 'blog', 'pm', 'topicadmin', 'register',
  30. 'archiver'))) {

  31.         $cachelost .= (@include DISCUZ_ROOT.'./forumdata/cache/cache_'.CURSCRIPT.'.php') ? '' : ' '.CURSCRIPT;

  32. }复制代码

  33. 看看是不是index, forumdisplay, viewthread这些文件是不是缓存了,有的话把它装到$cachelost这个变量中。
复制代码

 楼主| 发表于 2011-8-15 09:27:24 | 显示全部楼层
Section Four:
  1. $newpm = $newpmexists = $sessionexists = $seccode = $bloguid = 0;//初始化变量



  2. $membertablefields = 'm.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques,

  3.         m.adminid, m.groupid, m.groupexpiry, m.extgroupids, m.email, m.timeoffset, m.tpp, m.ppp, m.posts, m.digestposts,

  4.         m.oltime, m.pageviews, m.credits, m.extcredits1, m.extcredits2, m.extcredits3, m.extcredits4, m.extcredits5,

  5.         m.extcredits6, m.extcredits7, m.extcredits8, m.timeformat, m.dateformat, m.pmsound, m.sigstatus, m.invisible,

  6.         m.lastvisit, m.lastactivity, m.lastpost, m.newpm, m.accessmasks, m.xspacestatus, m.editormode, m.customshow';

  7. if($sid) {

  8.         if($discuz_uid) {

  9.                 $query = $db->query("SELECT s.sid,
  10. s.styleid, s.groupid='6' AS ipbanned, s.pageviews AS spageviews,
  11. s.lastolupdate, s.seccode, $membertablefields

  12.                         FROM {$tablepre}sessions s, {$tablepre}members m

  13.                         WHERE m.uid=s.uid AND s.sid='$sid' AND
  14. CONCAT_WS('.',s.ip1,s.ip2,s.ip3,s.ip4)='$onlineip' AND
  15. m.uid='$discuz_uid'

  16.                         AND m.password='$discuz_pw' AND m.secques='$discuz_secques'");

  17.         } else {

  18.                 $query = $db->query("SELECT sid, uid AS
  19. sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews,
  20. styleid, lastolupdate, seccode

  21.                         FROM {$tablepre}sessions WHERE sid='$sid' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='$onlineip'");

  22.         }

  23.         if($_DSESSION = $db->fetch_array($query)) {

  24.                 $sessionexists = 1;

  25.                 if(!empty($_DSESSION['sessionuid'])) {

  26.                         $query = $db->query("SELECT $membertablefields

  27.                                 FROM {$tablepre}members m WHERE uid='$_DSESSION[sessionuid]'");

  28.                         $_DSESSION = array_merge($_DSESSION, $db->fetch_array($query));

  29.                 }

  30.         } else {

  31.                 $query = $db->query("SELECT sid, groupid,
  32. groupid='6' AS ipbanned, pageviews AS spageviews, styleid, lastolupdate,
  33. seccode

  34.                         FROM {$tablepre}sessions WHERE sid='$sid' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='$onlineip'");

  35.                 if($_DSESSION = $db->fetch_array($query)) {

  36.                         clearcookies();

  37.                         $sessionexists = 1;

  38.                 }

  39.         }

  40. }复制代码

  41. 这一段是有蛮长的,不过看着长不代表它就难,第一行是初始化变量用的(无论何时用变量都要考虑初始化,要不然安全性不值得一提,一个get就完了)

  42. 接下来是判断是不是有sid,有的话就从cdb_session表中取来,然后连接一下cdb_members表取出一些更具体的东西,具体是哪些东西?
  43. 在$membertablefields这个变量里面已经全面写出来了,对应数据库看吧,不看的话用英语猜猜得出的。。。在这里Discuz标记了一个
  44. sessionexist变量,表示这个会员是在线的。

  45. if(!$sessionexists) {

  46.         if($discuz_uid) {

  47.                 $query = $db->query("SELECT $membertablefields

  48.                         FROM {$tablepre}members m WHERE
  49. m.uid='$discuz_uid' AND m.password='$discuz_pw' AND
  50. m.secques='$discuz_secques'");

  51.                 if(!($_DSESSION = $db->fetch_array($query))) {

  52.                         clearcookies();

  53.                 }

  54.         }复制代码

  55. 要是不存在sid,不存在discuz_uid,那就肯定没有登陆了,清掉cookie,要是有$discuz_uid的话,还是从members表中取出信息存放到$_DSESSION数组中

  56.         if(ipbanned($onlineip)) $_DSESSION['ipbanned'] = 1;



  57.         $_DSESSION['sid'] = random(6);

  58.         $_DSESSION['seccode'] = random(6, 1);

  59. }

  60. $_DSESSION['dateformat'] = empty($_DSESSION['dateformat']) ? $_DCACHE['settings']['dateformat'] : $_DSESSION['dateformat'];

  61. $_DSESSION['timeformat'] = empty($_DSESSION['timeformat']) ?
  62. $_DCACHE['settings']['timeformat'] : ($_DSESSION['timeformat'] == 1 ?
  63. 'h:i A' : 'H:i');

  64. $_DSESSION['timeoffset'] = isset($_DSESSION['timeoffset'])
  65. && $_DSESSION['timeoffset'] != 9999 ? $_DSESSION['timeoffset'] :
  66. $_DCACHE['settings']['timeoffset'];复制代码

  67. 这个是判断ip是不是在被阻止的list里,是的话就标记一下,用$_DSESSION[‘ipbanned’]标记的。再把一个随机的sid和seccode写到$_DSESSION数组。然后接下来是把日期,时间,时差写入$_DSESSION这个变量。

  68. $membertablefields = '';

  69. @extract($_DSESSION);



  70. $lastvisit = empty($lastvisit) ? $timestamp - 86400 : $lastvisit;

  71. $timenow = array('time' => gmdate("$dateformat $timeformat", $timestamp + 3600 * $timeoffset),

  72.         'offset' => ($timeoffset >= 0 ? ($timeoffset == 0 ? '' : '+'.$timeoffset) : $timeoffset));



  73. if(PHP_VERSION > '5.1') {

  74.         @date_default_timezone_set('Etc/GMT'.($timeoffset > 0 ? '-' : '+').(abs($timeoffset)));

  75. }复制代码

  76. 又见变量初始化,然后是把$_DESSION给展开,这样方便多了。接下来判断是不是有上次访问的时间,有的话就没事,没有的话就减去24小时。

  77. 接下来给一个现在的时间,这里有一个时间的问题,所以把时间加上时差乘上3600秒就得到当前时间了。

  78. PHP 5 能处理时差了,所以Discuz在这里也设置了一下,想得真全面!!

复制代码




 楼主| 发表于 2011-8-15 09:27:44 | 显示全部楼层
Section Six:
  1. if(!in_array($adminid, array(1, 2, 3))) {

  2.         $alloweditpost = $alloweditpoll = $allowstickthread = $allowmodpost = $allowdelpost = $allowmassprune

  3.                 = $allowrefund = $allowcensorword = $allowviewip = $allowbanip = $allowedituser = $allowmoduser

  4.                 = $allowbanuser = $allowpostannounce = $allowviewlog = $disablepostctrl = $supe_allowpushthread = 0;

  5. } elseif(isset($radminid) && $adminid != $radminid && $adminid != $groupid) {

  6.         $cachelost .= (@include
  7. DISCUZ_ROOT.'./forumdata/cache/admingroup_'.intval($adminid).'.php') ?
  8. '' : ' admingroup_'.$groupid;

  9. }复制代码

  10. 这里是权限判断,如果你不是admin, moderator, super moderator,那么你的什么权限都没。。。



  11. $forum = array();

  12. $auditstatuson = !empty($mod) && $mod == 'edit'
  13. && in_array($adminid, array(1, 2, 3)) && $allowmodpost ?
  14. true : false;



  15. $tid = isset($tid) && is_numeric($tid) ? $tid : 0;

  16. $fid = isset($fid) && is_numeric($fid) ? $fid : 0;

  17. $typeid = isset($typeid) ? intval($typeid) : 0;



  18. if(!empty($tid) || !empty($fid)) {

  19.         if(empty($tid)) {

  20.                 $query = $db->query("SELECT f.fid, f.*, ff.* $accessadd1 $modadd1, f.fid AS fid

  21.                         FROM {$tablepre}forums f

  22.                         LEFT JOIN {$tablepre}forumfields ff ON ff.fid=f.fid $accessadd2 $modadd2

  23.                         WHERE f.fid='$fid'");

  24.                 $forum = $db->fetch_array($query);

  25.         } else {

  26.                 $query = $db->query("SELECT t.tid,
  27. t.closed,".(defined('SQL_ADD_THREAD') ? SQL_ADD_THREAD : '')." f.*, ff.*
  28. $accessadd1 $modadd1, f.fid AS fid

  29.                         FROM {$tablepre}threads t

  30.                         INNER JOIN {$tablepre}forums f ON f.fid=t.fid

  31.                         LEFT JOIN {$tablepre}forumfields ff ON ff.fid=f.fid $accessadd2 $modadd2

  32.                         WHERE t.tid='$tid'".($auditstatuson ? '' : " AND t.displayorder>='0'")." LIMIT 1");

  33.                 $forum = $db->fetch_array($query);

  34.                 $tid = $forum['tid'];

  35.         }



  36.         if($forum) {

  37.                 $fid = $forum['fid'];

  38.                 $forum['ismoderator'] = !empty($forum['ismoderator']) || $adminid == 1 || $adminid == 2 ? 1 : 0;

  39.                 foreach(array('postcredits', 'replycredits',
  40. 'threadtypes', 'digestcredits', 'postattachcredits', 'getattachcredits',
  41. 'supe_pushsetting') as $key) {

  42.                         $forum[$key] = !empty($forum[$key]) ? unserialize($forum[$key]) : array();

  43.                 }

  44.         } else {

  45.                 $fid = 0;

  46.         }

  47. }复制代码

  48. 得到论坛信息用的,如果你是看forumdisplay页面和看viewthread在数据库中执行的东东不是一样的。这样能得到一点性能上的提升。然后往forum这个数组里面写一些东西进去,比方说:发帖子得到的分数,回复得到的分数,帖子分类的类型等…

  49. $styleid = intval(!empty($_GET['styleid']) ? $_GET['styleid'] :

  50.                 (!empty($_POST['styleid']) ? $_POST['styleid'] :

  51.                 (!empty($_DSESSION['styleid']) ? $_DSESSION['styleid'] :

  52.                 $_DCACHE['settings']['styleid'])));



  53. $styleid = intval(isset($stylejump[$styleid]) ? $styleid : $_DCACHE['settings']['styleid']);



  54. if(@!include DISCUZ_ROOT.'./forumdata/cache/style_'.intval(!empty($forum['styleid']) ? $forum['styleid'] : $styleid).'.php') {

  55.         $cachelost .= (@include
  56. DISCUZ_ROOT.'./forumdata/cache/style_'.($styleid =
  57. $_DCACHE['settings']['styleid']).'.php') ? '' : ' style_'.$styleid;

  58. }复制代码

  59. 这里是得到论坛风格的地方,可以看到第一行的赋值Disuz用尽一切可能得到一个合理的风格styleid,呵呵,然后再来一行,看看是不是你在论坛底部切换了一下风格,有的话就override一下,把这个风格作为你的当前风格。

  60. 如果没有缓存的话,再往cachelost这个里面写点东西。

  61. if($cachelost) {

  62.         require_once DISCUZ_ROOT.'./include/cache.func.php';

  63.         updatecache();

  64.         dexit('Cache List: '.$cachelost.'<br>Caches successfully created, please refresh.');

  65. }复制代码

  66. 如果cachelost中有东西的话,那么就调用include/cache.func.php,并用这个文件里面定义的updatecache();来更新缓存,并强制访问者刷新论坛,使缓存立即生效。

  67. if(!defined('CURSCRIPT') || CURSCRIPT != 'wap') {

  68.         if($nocacheheaders) {

  69.                 @dheader("Expires: 0");

  70.                 @dheader("Cache-Control: private, post-check=0, pre-check=0, max-age=0", FALSE);

  71.                 @dheader("Pragma: no-cache");

  72.         }

  73.         if($headercharset) {

  74.                 @dheader('Content-Type: text/html; charset='.$charset);

  75.         }

  76.         if(empty($_DCOOKIE['sid']) || $sid != $_DCOOKIE['sid']) {

  77.                 dsetcookie('sid', $sid, 604800);

  78.         }

  79. }复制代码

  80. 这里是设置网页的header用的,通过判断是不是wap或者是不是有CURSCRIPT这个常量(注:CURSCRIPT代表了当前执行的
  81. script,比方说forumdisplay.php中就会有define(‘CURSCRIPT’,
  82. ‘forumdisplay’);这样的定义),下一行是说sid过期了,再生成一个,dsetcookie()这个函数是./include
  83. /global.func.php这个文件中定义的。

  84. if($cronnextrun && $cronnextrun <= $timestamp) {

  85.         require_once DISCUZ_ROOT.'./include/cron.func.php';

  86.         runcron();

  87. }



  88. 复制代码

  89. 呵呵,后台的计划任务来了。。。。当然,这种情况是要至少有一个会员访问论坛,如果说没有人访问,你再设置也没有用,PHP的一大痛处,不能自己执行…

  90. if(isset($plugins['include']) && is_array($plugins['include'])) {

  91.         foreach($plugins['include'] as $include) {

  92.                 if(!$include['adminid'] || ($include['adminid'] && $include['adminid'] >= $adminid)) {

  93.                         @include_once DISCUZ_ROOT.'./plugins/'.$include['script'].'.inc.php';

  94.                 }

  95.         }

  96. }复制代码

  97. 这里的加载一些插件的文件。

  98. if((!empty($_DCACHE['advs']) || $globaladvs || $redirectadvs) && !defined('IN_ADMINCP')) {

  99.         require_once DISCUZ_ROOT.'./include/advertisements.inc.php';

  100. }复制代码

  101. 这里是看看是不是在论坛的cache中有广告的存在(注:$_DCACHE这个数组中存放的是论坛的一些设置之类的缓存),有广告的话就引用广告的文件。

  102. if(isset($allowvisit)
  103. && $allowvisit == 0 && !(defined('CURSCRIPT')
  104. && CURSCRIPT == 'member' && $action == 'groupexpiry')) {

  105.         showmessage('user_banned', NULL, 'HALTED');

  106. } elseif(!((defined('CURSCRIPT') && in_array(CURSCRIPT, array('logging', 'wap', 'seccode'))) || $adminid == 1)) {

  107.         if($bbclosed) {

  108.                 clearcookies();

  109.                 $closedreason =
  110. $db->result($db->query("SELECT value FROM {$tablepre}settings
  111. WHERE variable='closedreason'"), 0);

  112.                 showmessage($closedreason ? $closedreason : 'board_closed', NULL, 'NOPERM');

  113.         }

  114.         periodscheck('visitbanperiods');

  115. }复制代码

  116. 论坛的安全访问设置。一个是不允许访问,另一个是访问到了member.php?action=groupexpiry的话,就说用户被ban了。然后就
  117. 是检查是不是论坛关闭了,可以看也论坛关闭对管理员没有影响。接下来检查是不是禁的时间到了…periodscheck()函数就是这个用的。如果没到是
  118. 会被showmessage说没有访问权限的,具体看include/global.func.php这个文件中的定义。当然,下一期我就会分析这个文
  119. 件。

  120. if((!empty($fromuid)
  121. || !empty($fromuser)) && ($creditspolicy['promotion_visit'] ||
  122. $creditspolicy['promotion_register'])) {

  123.         require_once DISCUZ_ROOT.'/include/promotion.inc.php';

  124. }复制代码

  125. 这个当然是推荐注册用的。应该没看错,呵呵。



  126. $rssauth = $rssstatus
  127. && $discuz_uid ? rawurlencode(authcode("$discuz_uid\t".($fid ?
  128. $fid : '')."\t".substr(md5($discuz_pw.$discuz_secques), 0, 8), 'ENCODE',
  129. md5($_DCACHE['settings']['authkey']))) : '0';复制代码

  130. Rss检查
复制代码


好了,到此./include/common.inc.php这个文件就分析完了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|小黑屋|BC Morning Website ( Best Deal Inc. 001 )

GMT-8, 2026-4-12 02:28 , Processed in 0.016329 second(s), 16 queries .

Supported by Weloment Group X3.5

© 2008-2026 Best Deal Online

快速回复 返回顶部 返回列表