完整類別實作
<?php
class DBLogger {
private $logFile;
public function __construct($logFile = 'error.dat') {
$this->logFile = $logFile;
}
// 記錄 MySQL 錯誤
public function logError() {
if (!mysql_errno()) return; // 無錯誤直接返回
$fp = @fopen($this->logFile, 'a+');
if (!$fp) return;
$time = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'CLI';
$uri = $_SERVER['PHP_SELF'] ?? 'UNKNOWN';
$user = $_SESSION['user'] ?? 'GUEST';
$errMsg = mysql_error();
$errNo = mysql_errno();
$msg = "{Time:$time} {IP:$ip} {ErrNo:$errNo} {ErrMsg:$errMsg} {File:$uri} {User:$user}\n";
@fwrite($fp, $msg);
@fclose($fp);
}
}
// 使用方式:在每個執行 SQL 的頁面尾部或統一錯誤處理器中調用
$dbLogger = new DBLogger();
mysql_query("SELECT * FROM not_exist_table");
$dbLogger->logError(); // 自動記錄上一條 SQL 的錯誤
?>
輸出範例
{Time:2024-05-09 14:43:56} {IP:127.0.0.1} {ErrNo:1146} {ErrMsg:Table 'db.not_exist_table' doesn't exist} {File:/var/www/html/test.php} {User:admin}
進階建議
- 避免敏感資訊洩露:生產環境關閉
display_errors,僅記錄日誌。
- 加入堆疊追蹤:
debug_backtrace() 取得呼叫鏈,定位具體行號。
- 日誌輪轉:配合
logrotate 或自建大小/日期切割,防單一檔案過大。
- 統一錯誤處理:
set_error_handler() + register_shutdown_function() 捕獲所有未處理錯誤。
- 現代化替代:採用 Monolog、Laravel Log、Symfony Logger 等成熟庫,支援多通道、格式化、告警整合。
關於 __LINE__ 的補充
include 引入檔案:不要 加 __LINE__(行號會指向 include 行)。
require 引入:建議 加 __LINE__,錯誤行號更精確。