萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 利用 fopen/fwrite 實作 MySQL 錯誤日誌記錄:除錯利器

應用場景

客戶回報錯誤但無法提供錯誤訊息時,在資料庫查詢類別的錯誤處理處加入日誌記錄,事後可直接檢視日誌檔案定位 SQL 錯誤。

核心寫入函數

<?php
/**
 * 追加寫入日誌檔案
 * @param string $fileName 日誌路徑
 * @param string $message  要記錄的訊息
 */
function putFile($fileName, $message) {
    // a+ 模式:讀寫、指標在末尾、不存在則建立
    if ($fp = fopen($fileName, 'a+')) {
        // 格式:訊息 + 時間戳 + 換行
        $logLine = $message . date('Y-m-d H:i:s') . "\n\r";
        fwrite($fp, $logLine);
        fclose($fp);
    }
}

// 使用範例
$errorSql = 'SELECT * FROM users WHERE id = \' OR 1=1 --';
putFile('logfile.txt', '[SQL ERROR] ' . $errorSql);
?>

整合到資料庫類別 (PDO 範例)

<?php
class Database {
    private $pdo;
    private $logFile = __DIR__ . '/logs/sql_errors.log';
    
    public function __construct($dsn, $user, $pass) {
        $this->pdo = new PDO($dsn, $user, $pass, [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        ]);
    }
    
    public function query($sql, $params = []) {
        try {
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
            return $stmt;
        } catch (PDOException $e) {
            $this->logError($sql, $params, $e);
            throw $e; // 重新拋出讓上層處理
        }
    }
    
    private function logError($sql, $params, $e) {
        $msg = sprintf(
            "[%s] SQL: %s | Params: %s | Error: %s\n",
            date('Y-m-d H:i:s'),
            $sql,
            json_encode($params, JSON_UNESCAPED_UNICODE),
            $e->getMessage()
        );
        // 使用 file_put_contents 簡化 (PHP 5+)
        file_put_contents($this->logFile, $msg, FILE_APPEND | LOCK_EX);
    }
}
?>

日誌檔案管理建議

  • 目錄權限:logs/ 目錄需可寫,建議放在 Web 根目錄外。
  • 日誌輪轉:定期 (如每日) 切割檔案,避免單一檔案過大。可用 logrotate (Linux) 或 PHP 腳本定時搬移。
  • 鎖定機制:LOCK_EX 確保多程序併發寫入不衝突。
  • 敏感資料過濾:記錄前過濾密碼、信用卡號等敏感欄位。
  • 結構化日誌:建議輸出 JSON 格式,便於 ELK、Loki 等日誌系統收集分析。

JSON 格式日誌範例

<?php
function logErrorJson($sql, $params, $errorMsg) {
    $entry = [
        'timestamp' => date('c'),
        'level'     => 'ERROR',
        'sql'       => $sql,
        'params'    => $params,
        'error'     => $errorMsg,
        'trace'     => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)
    ];
    $line = json_encode($entry, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
    file_put_contents('sql_errors.json.log', $line, FILE_APPEND | LOCK_EX);
}
?>

輸出範例:

{"timestamp":"2024-05-20T14:30:00+08:00","level":"ERROR","sql":"SELECT * FROM users WHERE email = ?","params":["test@example.com"],"error":"SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db.users' doesn't exist","trace":[...]}

快速驗證腳本

<?php
// 測試寫入
putFile('test.log', 'Test message ');
echo 'Done. Check test.log content:';
echo '<pre>'; readfile('test.log'); echo '</pre>';
?>
copyright © 萬盛學電腦網 all rights reserved