此內(nèi)容是對(duì)文件 zblogphp1.5.1\zb_system\function\c_system_debug.php 的代碼分析,建議打開(kāi)此文件對(duì)照閱讀琢歇。
該文件包含以下6個(gè)函數(shù)以及一個(gè)類(lèi)支鸡,如下:
function Debug_PrintGlobals 顯示全局變量
function Debug_PrintIncludefiles 打印全局Include文件
function Debug_PrintConstants 打印全局自定義常量
function Debug_Error_Handler 錯(cuò)誤調(diào)度提示
function Debug_Exception_Handler 異常處理
function Debug_Shutdown_Handler 當(dāng)機(jī)錯(cuò)誤處理
class ZBlogException 異常處理類(lèi)
首先講解異常處理類(lèi),位于該文件第238行處湾盗。
類(lèi)的開(kāi)頭定義私有靜態(tài)變量 $_zbe = null意敛,$_isdisable = null (類(lèi)實(shí)例和是否禁用調(diào)度標(biāo)識(shí))
定義公共靜態(tài)變量
$isdisable = false 是否禁用調(diào)度
$isstrict = false 是否嚴(yán)格調(diào)度模式
$iswarning = true 是否警告調(diào)度模式
$error_id = 0 錯(cuò)誤ID
$error_file = null 錯(cuò)誤文件
$error_line = null 錯(cuò)誤行
$islogerror = false 是否寫(xiě)入錯(cuò)誤日志
定義公共變量 $type(錯(cuò)誤類(lèi)型/錯(cuò)誤級(jí)別馅巷,如下17中錯(cuò)誤類(lèi)型,) $message(錯(cuò)誤信息) $messagefull(完整的錯(cuò)誤信息草姻,會(huì)輸出是什么地方出錯(cuò)的) $file(錯(cuò)誤文件) $line(錯(cuò)誤行) 和數(shù)組 $errarray = array()(錯(cuò)誤說(shuō)明數(shù)組)
構(gòu)造函數(shù) __construct() 會(huì)在實(shí)例化該類(lèi)時(shí)自動(dòng)調(diào)用初始化錯(cuò)誤數(shù)組列表
$this->errarray 詳細(xì)信息如下:
0:UNKNOWN 未知錯(cuò)誤
1:E_ERROR 運(yùn)行時(shí)致命錯(cuò)誤
2:E_WARNING 運(yùn)行時(shí)警告
4:E_PARSE 編譯時(shí)語(yǔ)法解析錯(cuò)誤
8:E_NOTICE 運(yùn)行時(shí)通知
16:E_CORE_ERROR 初始化啟動(dòng)過(guò)程中發(fā)生的致命錯(cuò)誤
32:E_CORE_WARNING 初始化啟動(dòng)過(guò)程中發(fā)生的警告
64:E_COMPILE_ERROR 致命編譯時(shí)錯(cuò)誤
128:E_COMPILE_WARNING 編譯時(shí)警告
256:E_USER_ERROR 用戶(hù)產(chǎn)生的錯(cuò)誤信息
512:E_USER_WARNING 用戶(hù)產(chǎn)生的警告信息
1024:E_USER_NOTICE 用戶(hù)產(chǎn)生的通知信息
2048:E_STRICT 啟用PHP對(duì)代碼的修改建議钓猬,以確保代碼具有最佳的互操作性和向前兼容性
4096:E_RECOVERABLE_ERROR 可被捕捉的致命錯(cuò)誤
8192:E_DEPRECATED 運(yùn)行時(shí)通知
16384:E_USER_DEPRECATED 用戶(hù)產(chǎn)生的警告信息
30719:E_ALL E_STRICT除外的所有錯(cuò)誤和警告信息
類(lèi)函數(shù) __get($name) 獲取參數(shù),(暫時(shí)沒(méi)有找到更多信息撩独,從代碼看是返回$this->errarray的錯(cuò)誤級(jí)別)
該函數(shù)首先判斷參數(shù)是否為 typeName 字符串敞曹,如果不是則不執(zhí)行,然后根據(jù)錯(cuò)誤級(jí)別來(lái)返回錯(cuò)誤級(jí)別的字符串說(shuō)明综膀。
類(lèi)函數(shù) GetInstance() 獲得單一實(shí)例澳迫,實(shí)例化異常處理類(lèi)
根據(jù) $_zbe 是否定義來(lái)進(jìn)行實(shí)例,外部使用 ZBlogException::GetInstance() 進(jìn)行實(shí)例化該類(lèi)剧劝。
靜態(tài)類(lèi)函數(shù) SetErrorHook() 設(shè)置錯(cuò)誤處理函數(shù)橄登,該函數(shù)執(zhí)行了下面3個(gè)處理
設(shè)置錯(cuò)誤處理函數(shù)由 Debug_Error_Handler 函數(shù)處理
設(shè)置異常處理函數(shù)由 Debug_Exception_Handler 函數(shù)處理
注冊(cè)一個(gè)函數(shù),這個(gè)函數(shù)會(huì)在PHP執(zhí)行完成后執(zhí)行讥此,這里這個(gè)函數(shù)是 Debug_Shutdown_Handler
靜態(tài)類(lèi)函數(shù) ClearErrorHook() 清除注冊(cè)的錯(cuò)誤處理函數(shù)拢锹,這個(gè)函數(shù)主要執(zhí)行下面的3個(gè)操作
create_function創(chuàng)建匿名函數(shù),參數(shù)為空萄喳。返回值設(shè)置為 false 后卒稳,則因?yàn)檫@個(gè)函數(shù)不處理任何事情且返回false,這會(huì)讓標(biāo)準(zhǔn)的錯(cuò)誤處理程序繼續(xù)調(diào)用他巨。起到清除之前設(shè)置的處理函數(shù)充坑。下面兩個(gè)同理。
靜態(tài)類(lèi)函數(shù) EnableErrorHook() 啟用錯(cuò)誤調(diào)度
該函數(shù)設(shè)置 $isdisable 變量為 false闻蛀,啟用錯(cuò)誤處理標(biāo)記
靜態(tài)類(lèi)函數(shù) DisableErrorHook() 禁止錯(cuò)誤調(diào)度
該函數(shù)設(shè)置 $isdisable 變量為 true匪傍,關(guān)閉錯(cuò)誤處理標(biāo)記
靜態(tài)類(lèi)函數(shù) SuspendErrorHook() 暫停錯(cuò)誤調(diào)度
靜態(tài)類(lèi)函數(shù) ResumeErrorHook() 恢復(fù)錯(cuò)誤調(diào)度
兩個(gè)函數(shù)都是首先判斷 self::$_isdisable 的私有標(biāo)記與 null 的全比較
暫停錯(cuò)誤調(diào)度函數(shù)是不全等跳出,恢復(fù)錯(cuò)誤調(diào)度函數(shù)是全等跳出
然后設(shè)置 $isdisable 和 $_isdisable 的狀態(tài)
理解:?jiǎn)⒂谜{(diào)度后觉痛,$isdisable = false役衡,$_isdisable = null,這時(shí)執(zhí)行恢復(fù)調(diào)度會(huì)直接return薪棒,只能執(zhí)行暫停調(diào)度
執(zhí)行暫停調(diào)度后手蝎,$_isdisable會(huì)更改為false或者true,$isdisable設(shè)置為true禁止調(diào)度俐芯!
這時(shí)因?yàn)?_isdisable不等于null棵介,所以此時(shí)只能執(zhí)行恢復(fù)調(diào)度函數(shù)而無(wú)法再次執(zhí)行暫停調(diào)度。
執(zhí)行恢復(fù)調(diào)度會(huì)再次設(shè)置$_isdisable為null吧史,$isdisable設(shè)置為調(diào)度狀態(tài)邮辽。
總結(jié):調(diào)度狀態(tài)只能先暫停,才能執(zhí)行恢復(fù)。反之不行吨述。
以下4個(gè)函數(shù)分別設(shè)置調(diào)度狀態(tài)級(jí)別
靜態(tài)類(lèi)函數(shù) DisableStrict() 禁用嚴(yán)格模式
靜態(tài)類(lèi)函數(shù) EnableStrict() 打開(kāi)嚴(yán)格模式
靜態(tài)類(lèi)函數(shù) DisableWarning() 禁用警告
靜態(tài)類(lèi)函數(shù) EnableWarning() 打開(kāi)警告
靜態(tài)類(lèi)函數(shù) Trace($s) 日志跟蹤
調(diào)用位于 c_system_common.php 文件中的 Logs 函數(shù) 進(jìn)行記錄日志操作岩睁,內(nèi)容為參數(shù)。Logs函數(shù)不在此處展開(kāi)揣云。
類(lèi)函數(shù) ParseError($type, $message, $file, $line) 解析錯(cuò)誤信息
參數(shù)為:錯(cuò)誤級(jí)別捕儒,內(nèi)容,文件邓夕,行刘莹。
該函數(shù)只做了一件事情就是對(duì) $type,$message,$messagefull,$file,$line進(jìn)行了賦值操作。
$messagefull變量額外添加字符串 ‘(set_error_handler)’焚刚。說(shuō)明是錯(cuò)誤調(diào)度捕捉的錯(cuò)誤点弯,這個(gè)函數(shù)只會(huì)在錯(cuò)誤調(diào)度函數(shù)執(zhí)行,而錯(cuò)誤調(diào)度函數(shù)是被SetErrorHook() 函數(shù)設(shè)置的錯(cuò)誤處理函數(shù)矿咕。
同理
類(lèi)函數(shù) ParseShutdown($error) 解析當(dāng)機(jī)錯(cuò)誤處理蒲拉,參數(shù)是一個(gè)數(shù)組
類(lèi)函數(shù) ParseException($exception) 解析異常處理,參數(shù)有 異常處理函數(shù) Debug_Exception_Handler 獲取并傳遞痴腌,$exception 是PHP拋出的異常對(duì)象,在PHP7以上是Throwable燃领。這里只討論exception
$exception對(duì)象包含屬性
string $message 異常消息內(nèi)容
int $code 異常代碼
string $file 拋出異常的文件名
int $line 拋出異常在該文件中的行號(hào)
$exception對(duì)象包含方法
string getMessage() 獲取異常消息內(nèi)容
Throwable getPrevious() 返回異常鏈中的前一個(gè)異常
int getCode() ?獲取異常代碼
string getFile() 創(chuàng)建異常時(shí)的程序文件名稱(chēng)
int getLine() 獲取創(chuàng)建的異常所在文件中的行號(hào)
array getTrace() 獲取異常追蹤信息
string getTraceAsString() 獲取字符串類(lèi)型的異常追蹤信息
string __toString() 將異常對(duì)象轉(zhuǎn)換為字符串
void __clone() 異呈看希克隆
這里使用了
$exception->getMessage() 異常消息內(nèi)容
$exception->getCode() 異常代碼
$exception->getFile() 異常時(shí)的程序文件名稱(chēng)
$exception->getLine() 異常所在文件中的行
然后判斷 異常類(lèi)的 $error_file 是否有值(是否不等于null),如果是則這個(gè)值賦值給 $this->file
同樣判斷 self::$error_line 不全等于 null猛蔽,將值賦值給 $this->line剥悟。
類(lèi)函數(shù) Display() 輸出錯(cuò)誤信息
使用函數(shù) headers_sent() 判斷 HTTP 標(biāo)頭是否已被發(fā)送以及在哪里被發(fā)送,如果沒(méi)有曼库,執(zhí)行位于 c_system_common.php文件的 Http500() 函數(shù)区岗。清空(擦掉)輸出緩沖區(qū)。
$error = $this 將類(lèi)本身賦值到 $error毁枯。
執(zhí)行 掛載在 Filter_Plugin_Debug_Display 插件中的函數(shù)
加載 zblogphp1.5.1\zb_system\defend\error.php 頁(yè)面慈缔,顯示錯(cuò)誤信息頁(yè)面
執(zhí)行 RunTime() 函數(shù)顯示頁(yè)面執(zhí)行時(shí)間
//``flush()`` and ``exit($errorCode)`` is for HHVM
//https://github.com/zblogcn/zblogphp/issues/32
flush() 函數(shù)刷新輸出緩沖
exit(1) 退出
類(lèi)函數(shù) get_code($file, $line) 獲取出錯(cuò)代碼信息
參數(shù):錯(cuò)誤的文件名和行號(hào)
如果 $file 值是 Unknown,返回空數(shù)組
如果 指定的$file文件名不可讀种玛,返回空數(shù)組
array_slice函數(shù)根據(jù)條件從數(shù)組中取一段值
file($file) 把整個(gè)文件讀入一個(gè)數(shù)組藐鹤,文件中的每一行都是數(shù)組的某一個(gè)元素
max(0, $line - 5) 函數(shù)返回兩個(gè)數(shù)的最大值,這里表示如果參數(shù)行小于5赂韵,則返回0
array_slice 第三個(gè)參數(shù)表示需要獲取的行數(shù)
array_slice 第四個(gè)參數(shù)表示是否重新排序并重置數(shù)組的數(shù)字索引娱节。這里用TRUE來(lái)阻止這個(gè)行為
所以 $aFile = array_slice(file($file), max(0, $line - 5), 10, true);
的結(jié)果為獲得出錯(cuò)文件以錯(cuò)誤所在行前5行開(kāi)始起的10行的內(nèi)容數(shù)組。
然后 foreach 將每一行的字符串使用 htmlspecialchars 將特殊字符轉(zhuǎn)換為 HTML 實(shí)體
源代碼為:
foreach ($aFile as &$sData) {
//&$ = ByRef
$sData = htmlspecialchars($sData);
}
最后 return $aFile;祭示,總之我看不懂 $aFile as &$sData 這個(gè)是什么意思肄满,是將 $aFile 每個(gè)元素追加到 $sData?
類(lèi)函數(shù) possible_causes_of_the_error() 得到可能的錯(cuò)誤原因
global $lang 全局公共語(yǔ)言數(shù)組
global $bloghost 當(dāng)前網(wǎng)站地址
$result = '' 返回結(jié)果
如果 ZBlogException::$error_id 錯(cuò)誤ID不等于0,表示是Z-BlogPHP自身拋出的錯(cuò)誤
然后在判斷 $lang['error_reasons'][ZBlogException::$error_id] 指定的ID值是否定義稠歉,如果定義掰担,將對(duì)應(yīng)結(jié)果(什么系統(tǒng)的哪哪哪錯(cuò)了,環(huán)境啊轧抗,權(quán)限啊什么的)賦值給 $result
否則將默認(rèn)錯(cuò)誤(空)賦值給$result
然后$lowerErrorReason = strtolower($this->message); strtolower函數(shù)將所有字符轉(zhuǎn)換為小寫(xiě)并賦值$this->message是錯(cuò)誤信息恩敌。上面說(shuō)過(guò)。
foreach ($lang['error_reasons']['other'] as $key => $value) 判斷語(yǔ)言包中其他數(shù)組中的各個(gè)數(shù)組元素横媚,看看$lowerErrorReason的值是不是和這里的錯(cuò)誤字符串一樣纠炮,如果一樣,將對(duì)應(yīng)值賦值到$result
$errorId = urlencode(ZBlogException::$error_id); 得到錯(cuò)誤ID URL編碼后賦值
$errorMessage = urlencode($this->message); 得到錯(cuò)誤信息URL編碼后賦值
$moreHelp = $lang['offical_urls']['more_help']; 獲得語(yǔ)言包中的該值灯蝴,是一個(gè)在線幫助鏈接
$moreHelp = str_replace('{%id%}', $errorId, $moreHelp); 將該鏈接的對(duì)應(yīng)字符替換為實(shí)際ID值
$moreHelp = str_replace('{%message%}', $errorMessage, $moreHelp); 同上
$result .= $lang['error_reasons']['end']; 拼接語(yǔ)言包中的對(duì)應(yīng)內(nèi)容
$result = str_replace('{%bloghost%}', $bloghost, $result); 繼續(xù)替換
$result = str_replace('{%morehelp%}', $moreHelp, $result); 繼續(xù)替換
返回結(jié)果恢口。
這個(gè)函數(shù)的執(zhí)行結(jié)果是:
第一段,哪里錯(cuò)了穷躁,哪里權(quán)限有問(wèn)題耕肩。
第二段,如果你是訪客问潭,請(qǐng)聯(lián)系站長(zhǎng)猿诸,如果你是站長(zhǎng),什么什么狡忙。
異常類(lèi)代碼解讀完畢梳虽,講解這個(gè)文件中的幾個(gè)函數(shù),這幾個(gè)函數(shù)可以在任意文件中使用灾茁。
函數(shù) Debug_PrintGlobals() 顯示全局變量
說(shuō)明:使用 foreach 函數(shù)來(lái)獲取 $GLOBALS 的所有內(nèi)容窜觉,返回一個(gè)數(shù)組吧。
函數(shù) Debug_PrintIncludefiles() 打印全局include文件
說(shuō)明:使用 foreach 函數(shù)通過(guò) get_included_files() 來(lái)獲取數(shù)據(jù)北专,返回一個(gè)數(shù)組
函數(shù) Debug_PrintConstants() 打印全局自定義常量
說(shuō)明:函數(shù) get_defined_constants 獲得所有常量的關(guān)聯(lián)數(shù)組禀挫,鍵是常量名,值是常量值
這里只獲取 user的子健內(nèi)容拓颓,所以使用
if (isset($a['user'])) {
$a = $a['user'];
}
獲得语婴,,返回一個(gè)數(shù)組
上面這三個(gè)函數(shù)都是只應(yīng)用在了查看 phpinfo 信息的頁(yè)面里录粱。
函數(shù) Debug_Error_Handler($errno, $errstr, $errfile, $errline) 錯(cuò)誤調(diào)度提示
改函數(shù)4個(gè)參數(shù)分別是錯(cuò)誤級(jí)別腻格,錯(cuò)誤信息,錯(cuò)誤文件名啥繁,錯(cuò)誤行
1.首先判斷錯(cuò)誤調(diào)度是否關(guān)閉菜职,如果是則直接return。 ZBlogException::$isdisable == true
2.然后 執(zhí)行掛載到 Filter_Plugin_Debug_Handler 鉤子上的插件函數(shù)
3.然后對(duì) $_SERVER['_error_count'] 的服務(wù)器指示錯(cuò)誤次數(shù)變量值加1
4.判斷是否寫(xiě)入錯(cuò)誤日志旗闽,如果寫(xiě)入的話調(diào)用 Logs 函數(shù)執(zhí)行寫(xiě)入操作 ZBlogException::$islogerror == true
var_export的第二個(gè)參數(shù)設(shè)置為true將數(shù)組的各個(gè)元素值以字符串拼接后寫(xiě)入文件酬核,Logs函數(shù)第二個(gè)參數(shù)true表示這個(gè)一個(gè)error日志蜜另。
5.判斷給定的文件名是否可讀,如果可以讀取的話嫡意,獲取錯(cuò)誤行的前一行信息
reset 將數(shù)組內(nèi)部指針倒回到第一個(gè)單元并返回第一個(gè)數(shù)組單元的值
判斷該行有沒(méi)有 @ 符號(hào)举瑰,如果沒(méi)有則 return (這里為什么要return?)
6.如果關(guān)閉警告蔬螟,則錯(cuò)誤級(jí)別是警告級(jí)別的話直接return此迅。
7.如果關(guān)閉嚴(yán)格模式,則對(duì) E_STRICT E_NOTICE E_USER_NOTICE 級(jí)別(建議旧巾,運(yùn)行時(shí)通知耸序,用戶(hù)產(chǎn)生的通知信息)直接 return。
//屏蔽屏蔽系統(tǒng)的錯(cuò)誤鲁猩,防ZBP報(bào)系統(tǒng)的錯(cuò)誤坎怪,不過(guò)也有可能導(dǎo)致ZBP內(nèi)的DEPRECATED錯(cuò)誤也被屏蔽了
8.如果錯(cuò)誤級(jí)別是 E_CORE_WARNING (警告性)直接返回return
9.如果錯(cuò)誤級(jí)別是 E_COMPILE_WARNING (警告性)直接返回return
10.如果常量 E_DEPRECATED 已經(jīng)定義且錯(cuò)誤級(jí)別是 E_DEPRECATED (運(yùn)行時(shí)通知)直接返回return
11.如果常量 E_USER_DEPRECATED 已經(jīng)定義且錯(cuò)誤級(jí)別是 E_USER_DEPRECATED (用戶(hù)產(chǎn)生的警告信息)直接返回return
下面的就是 用戶(hù)產(chǎn)生的錯(cuò)誤信息 和 可被撲捉的致命錯(cuò)誤 了
首先 $zbe = ZBlogException::GetInstance(); 獲得唯一異常處理類(lèi)實(shí)例
然后 $zbe->ParseError($errno, $errstr, $errfile, $errline); 解析錯(cuò)誤信息
最后 $zbe->Display(); 輸出錯(cuò)誤信息
函數(shù) Debug_Exception_Handler($exception) 異常處理
1.首先判斷錯(cuò)誤調(diào)度是否關(guān)閉,如果是則直接return廓握。 ZBlogException::$isdisable == true
2.然后 執(zhí)行掛載到 Filter_Plugin_Debug_Handler 鉤子上的插件函數(shù)
3.然后對(duì) $_SERVER['_error_count'] 的服務(wù)器指示錯(cuò)誤次數(shù)變量值加1
4.判斷是否寫(xiě)入錯(cuò)誤日志搅窿,如果寫(xiě)入的話調(diào)用 Logs 函數(shù)執(zhí)行寫(xiě)入操作 ZBlogException::$islogerror == true
var_export的第二個(gè)參數(shù)設(shè)置為true將數(shù)組的各個(gè)元素值以字符串拼接后寫(xiě)入文件,Logs函數(shù)第二個(gè)參數(shù)true表示這個(gè)一個(gè)error日志隙券。
5.$zbe = ZBlogException::GetInstance(); 獲得唯一異常處理類(lèi)實(shí)例
6.$zbe->ParseException($exception); 解析異常處理
7.$zbe->Display(); 輸出錯(cuò)誤信息
函數(shù) Debug_Shutdown_Handler() 當(dāng)機(jī)錯(cuò)誤處理
首先使用 error_get_last函數(shù)獲取最后一個(gè)發(fā)生的錯(cuò)誤的信息男应,如果沒(méi)有,返回NULL娱仔,不執(zhí)行該函數(shù)殉了。
如果獲取到了錯(cuò)誤信息
1.判斷錯(cuò)誤調(diào)度是否關(guān)閉,如果是則直接return拟枚。
2.然后 執(zhí)行掛載到 Filter_Plugin_Debug_Handler 鉤子上的插件函數(shù)
3.然后對(duì) $_SERVER['_error_count'] 的服務(wù)器指示錯(cuò)誤次數(shù)變量值加1
4.判斷是否寫(xiě)入錯(cuò)誤日志,如果寫(xiě)入的話調(diào)用 Logs 函數(shù)執(zhí)行寫(xiě)入操作 ZBlogException::$islogerror == true
var_export的第二個(gè)參數(shù)設(shè)置為true將數(shù)組的各個(gè)元素值以字符串拼接后寫(xiě)入文件众弓,Logs函數(shù)第二個(gè)參數(shù)true表示這個(gè)一個(gè)error日志。
5.如果關(guān)閉警告,則錯(cuò)誤級(jí)別是警告級(jí)別的話直接return裸准。
6.如果關(guān)閉嚴(yán)格模式替劈,則對(duì) E_STRICT E_NOTICE E_USER_NOTICE 級(jí)別(建議,運(yùn)行時(shí)通知滨达,用戶(hù)產(chǎn)生的通知信息)直接 return奶稠。
7.如果錯(cuò)誤級(jí)別是 E_CORE_WARNING (警告性)直接返回return
8.如果錯(cuò)誤級(jí)別是 E_COMPILE_WARNING (警告性)直接返回return
9.如果常量 E_DEPRECATED 已經(jīng)定義且錯(cuò)誤級(jí)別是 E_DEPRECATED (運(yùn)行時(shí)通知)直接返回return
10.如果常量 E_USER_DEPRECATED 已經(jīng)定義且錯(cuò)誤級(jí)別是 E_USER_DEPRECATED (用戶(hù)產(chǎn)生的警告信息)直接返回return
最后
$zbe = ZBlogException::GetInstance(); 獲得唯一異常處理類(lèi)實(shí)例
$zbe->ParseShutdown($error); 解析當(dāng)機(jī)錯(cuò)誤處理
$zbe->Display(); 輸出錯(cuò)誤信息
全文完 2017年4月24日