生產環境需區分錯誤等級:致命錯誤立即告警、警告記錄日誌、解析錯誤自動提取問題 XML 片段並建立過濾字典,防止相同錯誤重複觸發。
<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE);
set_error_handler('displayErrorHandler');
echo "time: " . date("Y-m-d H:i:s") . "\n";
function displayErrorHandler($errno, $errstr, $errfile, $errline) {
$errMap = [
E_ERROR => 'ERROR', E_WARNING => 'WARNING', E_PARSE => 'PARSE',
E_NOTICE => 'NOTICE', E_CORE_ERROR => 'CORE_ERROR',
E_CORE_WARNING => 'CORE_WARNING', E_COMPILE_ERROR => 'COMPILE_ERROR',
E_COMPILE_WARNING => 'COMPILE_WARNING', E_USER_ERROR => 'USER_ERROR',
E_USER_WARNING => 'USER_WARNING', E_USER_NOTICE => 'USER_NOTICE',
E_ALL => 'ALL', E_STRICT => 'STRICT'
];
$level = $errMap[$errno] ?? 'UNKNOWN';
$msg = sprintf("%s: %s at %s(%d)", $level, $errstr, $errfile, $errline);
if (in_array($errno, [E_ERROR, E_WARNING, E_PARSE], true)) {
echo $msg . "\n"; // 控制台輸出
// 致命錯誤/警告發送簡訊
if (in_array($errno, [E_ERROR, E_WARNING], true)) {
sendBankMsg($errstr);
}
// XML 解析錯誤自動提取問題片段
if (strpos($errstr, 'xml_parse(): Bytes:') !== false) {
writeFilterFile($errstr);
}
}
}
// 16進位轉二進位
function hex2bin($hex) {
$bin = '';
for ($i = 0; $i < strlen($hex); $i += 2) {
$bin .= chr(hexdec(substr($hex, $i, 2)));
}
return $bin;
}
// 寫入過濾字典
function writeFilterFile($errstr) {
if (strpos($errstr, 'xml_parse(): Bytes:') === false || strpos($errstr, ' 0x') === false) return;
$file = 'filtetext.php';
if (file_exists($file)) include $file; // 載入現有陣列
$clean = str_replace(['xml_parse(): Bytes:', ' 0x'], '', $errstr);
$bin = hex2bin($clean);
$filtetextArr[] = $bin;
$filtetextArr = array_unique($filtetextArr);
$code = "<?php\n\$filtetextArr = array('" . implode("','", $filtetextArr) . "');\n?>";
fileWrite($file, $code);
}
// 簡訊發送(Socket POST)
function sendBankMsg($msg) {
$params = http_build_query(['msg' => $msg, 'posttime' => time()]);
$fp = fsockopen('www.admin.com', 80);
if (!$fp) return;
$header = "POST /action/bank/bankmsg.php HTTP/1.1\r\n";
$header .= "Host: www.admin.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($params) . "\r\n";
$header .= "Connection: Close\r\n\r\n";
$header .= $params . "\r\n";
fwrite($fp, $header);
fclose($fp);
}
// 安全寫檔(檔案鎖 + 忽略用戶中斷)
function fileWrite($file, $content, $mode = 'w') {
ignore_user_abort(true);
$fp = fopen($file, $mode);
if (flock($fp, LOCK_EX)) {
fwrite($fp, $content);
flock($fp, LOCK_UN);
}
fclose($fp);
ignore_user_abort(false);
}
flock(LOCK_EX) 防併發寫入損壞字典