第一天,仔细学习了下:common.inc.php(Discuz6.1.0核心文件)01

  1. 云栖社区>
  2. 博客>
  3. 正文

第一天,仔细学习了下:common.inc.php(Discuz6.1.0核心文件)01

技术小胖子 2017-11-09 21:41:00 浏览633
展开阅读全文



  1. <?php 

  1. /* 
  2. April 18,2012 
  3. discuz二次开发学习 
  4. author:xuqin 
  5. 不能为了完成任务去做一件事,要举一反三,融会贯通的去学习。 
  6. */ 
  7. error_reporting(0); 
  8. /* 
  9.  * error_reporting(0); //抑制所有的出错信息 
  10.  * error_reporting(E_ALL);//显示所有的出错信息 
  11.  */ 
  12.  
  13. set_magic_quotes_runtime(0); 
  14. /* 
  15.  * set_magic_quotes_runtime(0); //关闭魔法引用 
  16.  * set_magic_quotes_runtime(1); //开启魔法引用 
  17.  * 什么事魔术引号? 
  18.  * 当打开时,所有的 '(单引号),"(双引号),\(反斜线)和 NULL 字符都会被自动加上一个反斜线进行转义。 
  19.  * 这和 addslashes() 作用完全相同。 
  20.  * 一共有三个魔术引号指令: 
  21.  * magic_quotes_gpc 影响到 HTTP 请求数据(GET,POST 和 COOKIE)。不能在运行时改变。在 PHP 中默认值为 on。 参见 get_magic_quotes_gpc()。 
  22.  * magic_quotes_runtime 如果打开的话,大部份从外部来源取得数据并返回的函数,包括从数据库和文本文件,所返回的数据都会被反斜线转义。该选项可在运行的时改变,在 PHP 中的默认值为 off。 参见 set_magic_quotes_runtime() 和 get_magic_quotes_runtime()。 
  23.  * magic_quotes_sybase 如果打开的话,将会使用单引号对单引号进行转义而非反斜线。此选项会完全覆盖 magic_quotes_gpc。如果同时打开两个选项的话,单引号将会被转义成 ''。而双引号、反斜线 和 NULL 字符将不会进行转义。 如何取得其值参见 ini_get()。 
  24.  */ 
  25.  
  26. $mtime = explode(' ', microtime()); 
  27. /* 
  28.  *  microtime()取得Unix 时间戳和微秒数后使用explode()进行切割并存进数组变量$mtime; 
  29.  *    eg: 
  30.  *    echo microtime(); //将显示 0.29353300 1164349567 (根据时间的不同会显示不同的数字,但格式是一样的 
  31.  *    $mtime[0]="0.29353300"; 
  32.  *    $mtime[1]="1164349567"; 
  33.  */ 
  34. $discuz_starttime = $mtime[1] + $mtime[0];//得到脚本开始运行的时间 
  35.  
  36. define('SYS_DEBUG', FALSE);//关闭debug模式 
  37. /* 
  38.  * 编译方式的本质区别 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。 
  39.  */ 
  40. define('IN_DISCUZ', TRUE);//用于防止非法引用,定义一个常量表示只有DISCUZ才可以使用本脚本 
  41. define('DISCUZ_ROOT'substr(dirname(__FILE__), 0, -7));//定义常量DISCUZ_ROOT的值(即bbs的路径) 
  42. define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());//将魔术引号开启状态存入常量 
  43. !defined('CURSCRIPT') && define('CURSCRIPT''');//这个写法很特别哦!!初始化当前运行的脚本名称为空,CURSCRIPT这个常量在很多页面都有,意思是如果没定义CURSCRIPT常量, 则定义CURSCRIPT为空。 
  44.  
  45. if(PHP_VERSION < '4.1.0') {//php旧版本超全局变量兼容处理,注意是引用赋值"&$" php基础知识哦!去复习下吧! 
  46.     $_GET = &$HTTP_GET_VARS
  47.     $_POST = &$HTTP_POST_VARS
  48.     $_COOKIE = &$HTTP_COOKIE_VARS
  49.     $_SERVER = &$HTTP_SERVER_VARS
  50.     $_ENV = &$HTTP_ENV_VARS
  51.     $_FILES = &$HTTP_POST_FILES
  52. /* 
  53.  *  作用:当PHP版本小于4.1.0 的时候使用传址方式获取内置全局变量 
  54.  *    示例: 
  55.  *    为什么要使用传址而不是传值方式? 
  56.  *    要点:在变量前加 & 符号既是传址 
  57.  *    <?php 
  58.  *    $a=1; 
  59.  *    $b=$a; 
  60.  *    $b++; 
  61.  *    echo "b=".$b." a=".$a; //显示:b=2 a=1 可以看到 b变了,而a 却还是没变 
  62.  *    
  63.  *    echo "<br>"; 
  64.  *    $c=1; 
  65.  *    $d=&$c;  //注意这行  &符号 
  66.  *    $d++; 
  67.  *    echo "d=".$d." c=".$c; //显示: d=2 c=2 可以看到d变了,可是c也变了 
  68.  *    ?> 
  69.  */ 
  70.  
  71. if (isset($_REQUEST['GLOBALS']) OR isset($_FILES['GLOBALS'])) { 
  72.     exit('Request tainting attempted.'); 
  73. /* 
  74.  *  众所周知,当php.ini里面的register_globals=on时,各种变量都被注入代码,例如来自 HTML 表单的请求变量。再加上 PHP 在使用变量之前是无需进行初始化的。那么就有可能导致不安全,假如有人恶意发出这么一个get请求"http://yourdomain /unsafe.php?GLOBALS=",那么就会清除$GLOBALS变量的值而导致不安全。 
  75.  * 
  76.  *  register_globals是php.ini里的一个配置,这个配置影响到php如何接收传递过来的参数,如果你的问题是:为什么我的表单无法传递数据?为什么我的程序无法得到传递过来的变量?等等,那么你需要仔细的阅读以下的内容。 
  77.  *    register_globals的值可以设置为:On或者Off,我们举一段代码来分别描述它们的不同。 
  78.  *    代码:    
  79.  *    <form name="frmTest" id="frmTest" action="URL"> 
  80.  *    <input type="text" name="user_name" id="user_name"> 
  81.  *    <input type="password" name="user_pass" id="user_pass"> 
  82.  *    <input type="submit" value="login"> 
  83.  *    </form>    
  84.  *    当register_globals=Off的时候,下一个程序接收的时候应该用$_GET['user_name'] 和$_GET['user_pass']来接受传递过来的值。(注:当<form>的method属性为post的时候应该用$_POST['user_name']和$_POST['user_pass']) 
  85.  *    当register_globals=On的时候,下一个程序可以直接使用$user_name和$user_pass来接受值。 
  86.  *    顾名思义,register_globals的意思就是注册为全局变量,所以当On的时候,传递过来的值会被直接的注册为全局变量直接使用,而Off的时候,我们需要到特定的数组里去得到它。 
  87.  * 
  88.  */ 
  89.  
  90. require_once DISCUZ_ROOT.'./include/global.func.php';//引入全局函数库,很重要 
  91. /* 
  92.  *  这里复习下:require;require_once();include();incdlue_once()区别 
  93.  * require() 
  94.  *include() 
  95.  *这两一般放在代码前面,功能除了处理失败情况不一样,其它都是一样,如果包含的文件不存在时,require会停止运行发生致命错误提示。而include则是只显示一警告,代码会继续执行。 
  96.  *require_once() 
  97.  *include_once() 
  98.  *这两一个一般放在流程控制中,除了以上错误处理的区别外,功能都是一样的,跟没有once的区别就是包含的文件已经在前包含过,第二次包含不会再被引入。 
  99.  */ 
  100. define('IS_ROBOT', getrobot());//定义IS_ROBOT常量,判断浏览此页面的user-agent是否为搜索引擎蜘蛛,getrobot函数见global.func.php 
  101. if(defined('NOROBOT') && IS_ROBOT) {//如果定义了此页不能被机器人找到,但是发现访问者是搜索引擎蜘蛛,则返回禁止信息。 
  102.     exit(header("HTTP/1.1 403 Forbidden")); 
  103.  
  104. foreach(array('_COOKIE''_POST''_GET'as $_request) {//过滤提交的变量,提高安全性 
  105.     foreach($$_request as $_key => $_value) { 
  106.         $_key{0} != '_' && $$_key = daddslashes($_value);//变量名第一个字母不能为下划线,防止有类似伪造的"$_POST"变量产生 
  107.     } 
  108. /* 
  109.  * addslashes() 函数在指定的预定义字符前添加反斜杠。 
  110.  * [单引号 (')双引号 (")反斜杠 (\)NULL]默认情况下,PHP 指令 magic_quotes_gpc 为 on,对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义。遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。 
  111.  * stripcslashes() 函数 删除 由 addcslashes() 函数添加的反斜杠。(也可删除服务器开启magic_quotes_gpc后自动添加上的反斜杠) 
  112.  */ 
  113.  
  114. if (!MAGIC_QUOTES_GPC && $_FILES) {//转义$_FILES变量,注意这里先要判断MAGIC_QUOTES_GPC常量的状态,如果是关闭的才进行转义,否则会造成多次转义 
  115.     $_FILES = daddslashes($_FILES); 
  116.  
  117. $charset = $dbcharset = $forumfounders = $metakeywords = $extrahead = $seodescription = ''
  118. //全局变量初始化:初始化文件字符集,数据库字符集,版块创建者,SEO的论坛关键字、描述,头部其他信息等变量 
  119. $plugins = $hooks = $admincp = $jsmenu = $forum = $thread = $language = $actioncode = $modactioncode = $lang = array(); 
  120. /* 
  121.  * 初始化插件,钩子,后台管理,js弹出菜单,版块,帖子,语言,动作代码,系统提示信息等数组 
  122.  * [钩子]实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达前台目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。 
  123.  */ 
  124. require_once DISCUZ_ROOT.'./config.inc.php';//引入系统配置文件,内含如数据库连接信息、cookie域、UC信息等 
  125.  
  126. $_DCOOKIE = $_DSESSION = $_DCACHE = $_DPLUGIN = $advlist = array();//初始化cookie,session,缓存,插件,广告列表等数组 
  127.  
  128. $prelength = strlen($cookiepre);//定义(获取)COOKIE前缀长度$prelength为$cookiepre的长度(见config.inc) 
  129.  
  130. foreach($_COOKIE as $key => $val) { 
  131.     if(substr($key, 0, $prelength) == $cookiepre) { 
  132.         $_DCOOKIE[(substr($key$prelength))] = MAGIC_QUOTES_GPC ? $val : daddslashes($val); 
  133.     } 
  134. /* 
  135.  * 从浏览器$_COOKIE得到$_DCOOKIE数组:如果cookie的前缀与系统配置的cookie前缀相同,则填入各cookie的值 
  136.         这里$_DCOOKIE各变量的名称是不包含前缀的(例如$_COOKIE['tmp_cook1']变成了$_DCOOKIE['cook1']),同时对值进行转义 
  137.  */ 
  138. unset($prelength$_request$_key$_value); 
  139. /* 
  140.  * 上面对COOKIE遍历完成后,便立即销毁$prelength等相关变量。 
  141.  * 清空一些无用变量,如临时的$_POST、$_GET等(因为已经在本文件前面处理中得到了很多的单独变量) 
  142.  */ 
  143. $inajax = !emptyempty($inajax);//先定义一个备用的变量吧,与ajax有关吗? 
  144. $timestamp = time();//获得一个当前的时间戳变量,如:1334714617,与前面到microtime不同,time()只会得到毫秒数 
  145.  
  146. if($attackevasive && CURSCRIPT != 'seccode') { 
  147.     require_once DISCUZ_ROOT.'./include/security.inc.php';//防御文件,根据$attackevasive设定的不同级别做相应处理。 
  148. /* 
  149.  * 是否启用攻击防御。$attackevasive默认为0,关闭论坛防御。如果配置文件config.inc定义了论坛防御级别,且当前脚本文件名不是seccode(验证码?),则引入相关防御的文件 
  150.  */ 
  151.  
  152. require_once DISCUZ_ROOT.'./include/db_'.$database.'.class.php';//引入数据库处理类 
  153.  
  154. $PHP_SELF = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];//获得当前执行脚本的文件相对路径 
  155. $BASESCRIPT = basename($PHP_SELF);//返回路径的文件名部分 
  156. $boardurl = htmlspecialchars('http://'.$_SERVER['HTTP_HOST'].preg_replace("/\/+(api|archiver|wap)?\/*$/i"''substr($PHP_SELF, 0, strrpos($PHP_SELF'/'))).'/'); 
  157. /* 
  158.  * 取当前url 返回bbs的url(htmlspecialchars将特殊字符”<>“等转换为”&lt $gt“等)仔细看下substrstrpos那段,看这样是什么效果 
  159.  * strrpos() 函数查找字符串在另一个字符串中最后一次出现的位置 
  160.  * preg_replace() 执行一个正则表达式的搜索和替换 
  161.  */ 
  162.  
  163. if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { 
  164.     $onlineip = getenv('HTTP_CLIENT_IP'); 
  165. elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) { 
  166.     $onlineip = getenv('HTTP_X_FORWARDED_FOR'); 
  167. elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) { 
  168.     $onlineip = getenv('REMOTE_ADDR'); 
  169. elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) { 
  170.     $onlineip = $_SERVER['REMOTE_ADDR']; 
  171. /* 
  172.  * 获得用户到ip地址,存入$onlineip变量 
  173.  * 注意PHP三个获取ip的系统变量。 
  174.  * HTTP_CLIENT_IP 是tcp/ip协议里得到的ip地址,apache收到请求并返回就是要返回到这个ip去。 
  175.  * HTTP_X_FORWARDED_FOR 要想透过代理服务器取得客户端的真实 IP 地址。 
  176.  * REMOTE_ADDR 取得客户端的 IP地址,如果客户端是使用代理服务器来访问,那取到的就是代理服务器的IP地址。 
  177.  */ 
  178.  
  179. preg_match("/[\d\.]{7,15}/"$onlineip$onlineipmatches);//使用正则匹配函数得到符合格式的ip地址,看看ip是不是点分段,7-15个数字之间 
  180. $onlineip = $onlineipmatches[0] ? $onlineipmatches[0] : 'unknown';//如果上面获取到符合ip格式的ip就赋值给$onlineip 
  181. unset($onlineipmatches);//立即清空 IP检查变量,方便下次处理 
  182.  
  183. $cachelost = (@include DISCUZ_ROOT.'./forumdata/cache/cache_settings.php') ? '' : 'settings'
  184. @extract($_DCACHE['settings']); 
  185. /* 
  186.  * 读取论坛设置的缓存文件cache_settings.php 
  187.  * 如果能够正常读到,cachelost为空,既没有lost(丢失),这一步得到$_DCACHE['settings']数组(很重要,很多变量以后都要用到) 
  188.  * 这一段是获得./forumdata/cache/cache_settings.php(即缓存下的设置数组,并展开,方便以后的写法) 
  189.  * 将setting数组变量导入符号表,成为独立变量的形式,前面循环$$_key = $value处理$_POST等也是这个原理吧 
  190.  */ 
  191.  
  192. if($gzipcompress && function_exists('ob_gzhandler') && !in_array(CURSCRIPT, array('attachment''wap')) && !$inajax) { 
  193.     ob_start('ob_gzhandler'); 
  194. else { 
  195.     $gzipcompress = 0; 
  196.     ob_start();//输出缓存(开启输出缓冲) 
  197. /* 
  198.  * $gzipcompress(是否启用gzip)此变量来自@extract($_DCACHE['settings']) 
  199.  * 检查gzip是不是打开了,打开就用ob_gzhandler,没有就用ob_start。 
  200.  * 如果开启了gzip压缩,并且ob_gzhandler函数存在,并且当前脚本不是附件和wap,并且不是ajax,则开始使用ob_gzhandler压缩,否则只进行输出缓存而不压缩 
  201.  */ 
  202.  
  203. if(!emptyempty($loadctrl) && substr(PHP_OS, 0, 3) != 'WIN') { 
  204.     if($fp = @fopen('/proc/loadavg''r')) { 
  205.         list($loadaverage) = explode(' 'fread($fp, 6)); 
  206.         fclose($fp); 
  207.         if($loadaverage > $loadctrl) { 
  208.             header("HTTP/1.0 503 Service Unavailable"); 
  209.             include DISCUZ_ROOT.'./include/serverbusy.htm'
  210.             exit(); 
  211.         } 
  212.     } 
  213. /* 
  214.  * 此段为在linux平台下处理负载平衡 
  215.  * 对于非win平台,进行服务器负载判断并进行操作。$loadctrl为负载临界值。 
  216.  */ 
  217.  
  218. if(in_array(CURSCRIPT, array('index''forumdisplay''viewthread''post''topicadmin''register''archiver'))) { 
  219.     $cachelost .= (@include DISCUZ_ROOT.'./forumdata/cache/cache_'.CURSCRIPT.'.php') ? '' : ' '.CURSCRIPT; 
  220. /* 
  221.  * 继续判断当前dz缓存存在的状况,看看index, forumdisplay, viewthread这些文件是不是缓存了,有的话把它装到$cachelost这个变量中。 
  222.  * 对不同的脚本页面,引入不同的缓存文件 
  223.  */ 
  224.  
  225. $db = new dbstuff; 
  226. $db->connect($dbhost$dbuser$dbpw$dbname$pconnect, true, $dbcharset); 
  227. $dbuser = $dbpw = $dbname = $pconnect = NULL; 
  228. /* 
  229.  * 这里是初始化一个dbstull类的实例,也就是说前面的require_once DISCUZ_ROOT.'./include/db_'.$database.'.class.php';在这里用上了 
  230.  * 然后连接数据库并清理相关变量。由此可见DZ的安全性考虑真是牛到不行了。小气鬼! 呵呵! 
  231.  */ 
  232.  
  233. $sid = daddslashes(($transsidstatus || CURSCRIPT == 'wap') && (isset($_GET['sid']) || isset($_POST['sid'])) ? 
  234.     (isset($_GET['sid']) ? $_GET['sid'] : $_POST['sid']) : 
  235.     (isset($_DCOOKIE['sid']) ? $_DCOOKIE['sid'] : '')); 
  236. /* 
  237.  * 这里是个很长的三元运算符哦!对自定义的回话标识符进行过滤 
  238.  * 开启sid后,即使禁用cookie也可以登陆论坛$transsidstatus也是extract($_DCACHE['setting'])得到的,所以,熟悉cache_setting里面的变量才不会经常一头雾水 
  239.  * 如果开启了$sid且是wap,且从GET或POST传递来$sid,则从GET或者POST中取得,否则从cookie取得 
  240.  */ 
  241.  
  242. $discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']); 
  243. /* 定义验证字符串,验证钥匙。'authkey' => '0ee545SPQKK3jOP2'也是extract($_DCACHE['setting'])定义的。 
  244.  * $_SERVER["HTTP_USER_AGENT"]获取客户端浏览器的型号,这个不是一定准确的,是可以随意伪造的 
  245.  */ 
  246.  
  247. list($discuz_pw$discuz_secques$discuz_uid) = emptyempty($_DCOOKIE['auth']) ? array('''', 0) : daddslashes(explode("\t", authcode($_DCOOKIE['auth'], 'DECODE')), 1); 
  248. /* 
  249.  * 初始化变量:密码,安全问题,用户id,如果$_DCOOKIE['auth']为空,则初始化他们,否则解码并读取相应变量。 
  250.  * 对常用变量进行赋值。$discuz_secques为用户按安全验证回答的哈希值。authcode()根据$authkey对输入参数进行加密解密的操作。 
  251.  * 这一段是用来检查是不是$_DCOOKIE[‘auth’]存在,如果有的话就把其中存放的东西分别给$discuz_pw, $discuz_secques, $discuz_uid这三个变量,分别对应密码,提示问题和uid。 
  252.  */ 
  253.  
  254. $newpm = $newpmexists = $sessionexists = $seccode = 0;//初始化用户的新消息,安全问题,验证码等变量 
  255.  
  256. $membertablefields = 'm.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques, 
  257.     m.adminid, m.groupid, m.groupexpiry, m.extgroupids, m.email, m.timeoffset, m.tpp, m.ppp, m.posts, m.digestposts, 
  258.     m.oltime, m.pageviews, m.credits, m.extcredits1, m.extcredits2, m.extcredits3, m.extcredits4, m.extcredits5, 
  259.     m.extcredits6, m.extcredits7, m.extcredits8, m.timeformat, m.dateformat, m.pmsound, m.sigstatus, m.invisible, 
  260.     m.lastvisit, m.lastactivity, m.lastpost, m.newpm, m.accessmasks, m.editormode, m.customshow, m.customaddfeed'; 
  261. /* 
  262.  * 将用户表中所有需要读取的字段放在一个字符串中,便于后面的sql语句调用 
  263.  */ 
  264.  
  265. if($sid) {//如果变量$sid存在 
  266.     if($discuz_uid) {//如果cookie中有用户uid,则根据uid在数据库session表、member表中查询取出相关字段值 
  267.         $query = $db->query("SELECT s.sid, s.styleid, s.groupid='6' AS ipbanned, s.pageviews AS spageviews, s.lastolupdate, s.seccode, $membertablefields 
  268.             FROM {$tablepre}sessions s, {$tablepre}members m 
  269.             WHERE m.uid=s.uid AND s.sid='$sid' AND CONCAT_WS('.',s.ip1,s.ip2,s.ip3,s.ip4)='$onlineip' AND m.uid='$discuz_uid' 
  270.             AND m.password='$discuz_pw' AND m.secques='$discuz_secques'"); 
  271.     } else {//如果cookie中没有用户uid,则仅仅从session表中取出相关信息 
  272.         $query = $db->query("SELECT sid, uid AS sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, lastolupdate, seccode 
  273.             FROM {$tablepre}sessions WHERE sid='$sid' AND CONCAT_WS('.',ip1,ip2,ip3,ip4)='$onlineip'"); 
  274.     } 
  275.     /* 
  276.      * groupid='6':IP Banned 被禁止的ip 
  277.      * MySQL的几个实用字符串函数 : 
  278.      * concat()可以连接一个或者多个字符串,但是在连接字符串的时候,只要其中一个是NULL,那么将返回NULL 
  279.      * concat_ws()表示concat with separator,即有分隔符的字符串连接,在执行的时候,不会因为NULL值而返回NULL 
  280.      * group_concat()可用来行转列, 
  281.      * repeat()用来复制字符串,如select repeat('ab',2);'ab'表示要复制的字符串,2表示复制的份数 
  282.      */ 
  283.  
  284.     ?> 

 





      本文转自许琴 51CTO博客,原文链接:http://blog.51cto.com/xuqin/882308,如需转载请自行联系原作者




网友评论

登录后评论
0/500
评论
技术小胖子
+ 关注