首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 生產環境錯誤顯示與日志記錄最佳配置

     編輯:PHP 相關知識

核心原則

生產環境絕不向用戶顯示詳細錯誤信息,但必須完整記錄到日志供開發排查。通過 php.ini 配置實現「用戶見友好頁面,開發者見詳細日志」。

關鍵配置項對比

指令開發環境生產環境說明
display_errorsOnOff控制錯誤是否輸出到瀏覽器
display_startup_errorsOnOffPHP 啟動階段錯誤顯示
error_reportingE_ALLE_ALL & ~E_DEPRECATED & ~E_STRICT記錄級別(建議生產也用 E_ALL)
log_errorsOnOn啟用錯誤日志記錄
error_logsyslog/文件獨立文件路徑日志文件具體路徑
error_prepend_string<div class='error'>空錯誤前綴(生產禁用)
error_append_string</div>空錯誤後綴

生產環境推薦配置

; ===== 錯誤顯示 =====
display_errors = Off
display_startup_errors = Off
html_errors = Off

; ===== 錯誤報告級別 =====
; 記錄所有錯誤,包含棄用警告(便於升級排查)
error_reporting = E_ALL

; ===== 錯誤日志 =====
log_errors = On
; 絕對路徑,確保 PHP 進程用戶有寫權限
error_log = /var/log/php/error.log

; 日志最大長度(0 = 無限制)
log_errors_max_len = 0

; 忽略重複錯誤(防止日志洪水)
ignore_repeated_errors = On
ignore_repeated_source = On

; 記錄內存泄漏(開發/測試環境建議開啟)
report_memleaks = On
track_errors = Off  ; $php_errormsg 已棄用 PHP 7.2

; ===== 異常處理 =====
; 將錯誤轉為異常 (PHP 7+)
; zend.exception_ignore_args = On  ; 異常堆棧不包含參數值(安全)
; zend.exception_string_param_max_len = 0  ; 參數字符串長度限制

日志目錄權限設置

# 創建日志目錄
mkdir -p /var/log/php

# 設置擁有者為 PHP-FPM 運行用戶 (如 www-data)
chown www-data:www-data /var/log/php
chmod 755 /var/log/php

# 日志輪轉配置 /etc/logrotate.d/php
/var/log/php/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload php7.4-fpm > /dev/null 2>&1 || true
    endscript
}

代碼層面的錯誤處理增強

1. 自定義錯誤處理器

<?php
// bootstrap.php 或入口文件最早引入
function customErrorHandler(int $severity, string $message, string $file, int $line): bool {
    // 不在 error_reporting 範圍內的錯誤不處理
    if (!(error_reporting() & $severity)) {
        return false; // 交給內置處理器
    }
    
    // 格式化錯誤信息
    $error = [
        'time' => date('c'),
        'type' => getErrorTypeString($severity),
        'message' => $message,
        'file' => $file,
        'line' => $line,
        'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10),
        'request' => [
            'uri' => $_SERVER['REQUEST_URI'] ?? '',
            'method' => $_SERVER['REQUEST_METHOD'] ?? '',
            'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
        ]
    ];
    
    // 寫入日志 (JSON 格式便於 ELK 分析)
    error_log(json_encode($error, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    
    // 生產環境不顯示詳情
    if (ini_get('display_errors')) {
        echo "
" . htmlspecialchars(print_r($error, true)) . "
"; } return true; // 阻止內置處理器 } function getErrorTypeString(int $type): string { $types = [ 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_STRICT => 'STRICT', E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR', E_DEPRECATED => 'DEPRECATED', E_USER_DEPRECATED => 'USER_DEPRECATED' ]; return $types[$type] ?? "UNKNOWN($type)"; } // 註冊處理器 set_error_handler('customErrorHandler'); // 異常處理 set_exception_handler(function(Throwable $e) { customErrorHandler(E_ERROR, $e->getMessage(), $e->getFile(), $e->getLine()); // 顯示友好錯誤頁面 http_response_code(500); include __DIR__ . '/templates/500.html'; exit; }); // 致命錯誤捕獲 (PHP 7+) register_shutdown_function(function() { $error = error_get_last(); if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { customErrorHandler($error['type'], $error['message'], $error['file'], $error['line']); } }); ?>

2. 友好錯誤頁面模板

<!-- templates/500.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>服務器內部錯誤</title>
    <style>
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; 
               display: flex; align-items: center; justify-content: center; 
               min-height: 100vh; margin: 0; background: #f5f5f5; }
        .card { background: white; padding: 3rem; border-radius: 8px; 
                box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; max-width: 400px; }
        h1 { color: #e53e3e; margin-bottom: 1rem; }
        p { color: #4a5568; line-height: 1.6; }
        .ref { font-family: monospace; background: #edf2f7; padding: 0.5rem; 
               border-radius: 4px; display: inline-block; margin-top: 1rem; }
    </style>
</head>
<body>
    <div class="card">
        <h1>😕 服務器開小差了</h1>
        <p>我們已經記錄了這個錯誤,技術團隊正在緊急修復中。</p>
        <p>請稍後重試,或聯繫客服獲得幫助。</p>
        <div class="ref">錯誤參考: <?= date('YmdHis') ?></div>
    </div>
</body>
</html>

日志分析與監控

1. 實時監控腳本

#!/bin/bash
# monitor_php_errors.sh
LOG_FILE="/var/log/php/error.log"
ALERT_KEYWORDS="Fatal|Error|Exception|Out of memory|Maximum execution time"

tail -F "$LOG_FILE" | while read line; do
    if echo "$line" | grep -qE "$ALERT_KEYWORDS"; then
        # 發送告警 (郵件/Slack/鉉釘/企業微信)
        curl -X POST "https://webhook.example.com/alert" \
            -H "Content-Type: application/json" \
            -d "{\"text\":\"PHP 錯誤告警\",\"detail\":\"$line\"}"
    fi
done

2. 結構化日志查詢 (配合 jq)

# 查看最近 100 條錯誤
tail -100 /var/log/php/error.log | jq -r '.time + " " + .type + " " + .message'

# 統計錯誤類型分布
tail -1000 /var/log/php/error.log | jq -r '.type' | sort | uniq -c | sort -rn

# 查找特定文件的錯誤
grep '"file":"\/var\/www\/html\/api\/user.php"' /var/log/php/error.log | jq .

框架集成說明

框架錯誤處理機制配置建議
LaravelApp\Exceptions\Handler + MonologAPP_DEBUG=false, LOG_CHANNEL=stack
SymfonyKernel::handleException + MonologAPP_ENV=prod, kernel.debug=false
ThinkPHPthink\ExceptionHandleapp_debug = false, log 配置
Yii2ErrorHandler + yii\log\DispatcherYII_DEBUG=false, YII_ENV=prod
CodeIgniterExceptions + Log 類ENVIRONMENT=production

框架通常有自己的錯誤處理機制,以框架配置為準,php.ini 作為底層保障。

安全合規清單

  1. ✅ display_errors = Off 防止信息洩露(路徑、SQL、變量值)
  2. ✅ log_errors = On 確保可追溯
  3. ✅ error_log 指向非 Web 可訪問目錄
  4. ✅ 日志文件權限 640,擁有者 PHP 運行用戶
  5. ✅ 配置 logrotate 防止磁盤佔滿
  6. ✅ 異常堆棧不包含敏感參數值 (zend.exception_ignore_args=On)
  7. ✅ 定期審計日志,建立告警機制

總結

PHP 錯誤處理黃金法則:用戶見友好頁,日志見真章。生產環境關閉 display_errors,開啟 log_errors 指定獨立日志文件,配合自定義錯誤處理器輸出結構化 JSON 日志,接入日志分析平台與告警系統,做到「有錯必錄、有錄必查、有查必改」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved