PHP 預設錯誤報告等級 E_ALL 會輸出所有 Notice、Warning、Deprecated 等訊息,生產環境直接顯示會洩露路徑、資料庫結構等敏感資訊,且干擾正常輸出 (JSON/API/圖片)。本文系統說明 error_reporting、display_errors、log_errors 三大核心配置、層級常數、生產/開發環境最佳實踐與常見失效排查。
| 常數 | 值 | 說明 |
|---|---|---|
E_ERROR | 1 | 嚴重運行錯誤,腳本終止 |
E_WARNING | 2 | 運行警告,腳本繼續 |
E_PARSE | 4 | 編譯時語法解析錯誤 |
E_NOTICE | 8 | 運行期提示 (未定義變數等) |
E_CORE_ERROR | 16 | PHP 啟動過程嚴重錯誤 |
E_CORE_WARNING | 32 | PHP 啟動警告 |
E_COMPILE_ERROR | 64 | 編譯嚴重錯誤 |
E_COMPILE_WARNING | 128 | 編譯警告 |
E_USER_ERROR | 256 | 用戶觸發 trigger_error() |
E_USER_WARNING | 512 | 用戶警告 |
E_USER_NOTICE | 1024 | 用戶提示 |
E_STRICT | 2048 | 編碼標準建議 (PHP 5.4+ 併入 E_ALL) |
E_DEPRECATED | 8192 | 棄用功能警告 |
E_USER_DEPRECATED | 16384 | 用戶棄用警告 |
E_ALL | 32767 | 所有錯誤 (含 STRICT/DEPRECATED) |
位運算組合: E_ALL & ~E_NOTICE (排除 Notice)、E_ALL & ~E_DEPRECATED (排除棄用)。
| 指令 | 預設 | 開發建議 | 生產建議 |
|---|---|---|---|
error_reporting | E_ALL | E_ALL | E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT |
display_errors | On | On | Off |
display_startup_errors | Off | On | Off |
log_errors | Off | On | On |
error_log | NULL | /var/log/php_errors.log | /var/log/php_errors.log |
log_errors_max_len | 1024 | 0 (無限制) | 0 |
ignore_repeated_errors | Off | Off | On |
track_errors | Off | Off (PHP 8 棄用) | Off |
php.ini (全域).user.ini (目錄級,CGI/FPM).htaccess (Apache 模組) php_value error_reporting 32767ini_set() / error_reporting() (腳本運行時,最高優先權)最佳實踐: 在統一入口檔 (index.php) 最頂部設定:
// 開發環境
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
// 生產環境
ini_set('display_errors', '0');
ini_set('display_startup_errors', '0');
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT);
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/../logs/php_errors.log');
php --ini / phpinfo())。log_errors = On 但 error_log 路徑無寫入權限 → PHP 會 fallback 輸出到 stdout。解決:給予權限或設定正確路徑。.user.ini 或 ini_set() 覆蓋。display_errors = On 導致 Warning/Notice 直接輸出。生產必須 Off,並統一由錯誤處理器回傳 JSON。set_error_handler() 不生效E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING、大部分 E_STRICT;這些需在 php.ini 配置。// 1. 關閉顯示,開啟記錄
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php/app_errors.log');
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
// 2. 註冊例外/錯誤處理器 (統一格式)
set_exception_handler(function (Throwable $e) {
$code = $e->getCode() ?: 500;
http_response_code($code);
error_log(json_encode([
'time' => date('c'),
'type' => get_class($e),
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
'request' => ['uri' => $_SERVER['REQUEST_URI'], 'ip' => $_SERVER['REMOTE_ADDR']],
]));
// API 回傳 JSON
if (strpos($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') !== false) {
header('Content-Type: application/json');
echo json_encode(['error' => 'Internal Server Error', 'code' => $code]);
} else {
// 頁面顯示友善錯誤頁
include __DIR__ . '/templates/500.php';
}
});
set_error_handler(function (int $severity, string $message, string $file, int $line) {
if (!(error_reporting() & $severity)) return false; // 尊重 error_reporting
throw new ErrorException($message, 0, $severity, $file, $line);
});
// 3. 致命錯誤捕獲 (register_shutdown_function)
register_shutdown_function(function () {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
// 手動觸發例外處理器
(new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']))->getTraceAsString();
// 這裡可直接複用上述邏輯或寫入日誌
}
});
.env APP_DEBUG=false、config/logging.php 等)。error_log。error_log = /dev/stderr 讓容器日誌驅動收集,或掛載 Volume 到宿主機。