404 錯誤不僅影響使用者體驗,也可能隱藏斷連結、遷移遺漏、攻擊掃描等問題。本文實作一個 404 錯誤處理器,自動記錄詳細資訊並寄送郵件通知管理員,協助快速發現與修復問題。
404.php<?php
/**
* 404 錯誤處理器
* 需在 Apache .htaccess 或 Nginx 設定指向此檔案
* ErrorDocument 404 /404.php
*/
// ===== 設定區 =====
$config = [
'domain' => 'example.com', // 主域名(不含 www)
'docroot' => 'https://example.com', // 網站根目錄 URL
'font_face' => 'system-ui, sans-serif', // 字體
'font_size' => '1rem',
'bg_color' => '#ffffff',
'text_color' => '#333333',
'report_level' => 2, // 0=不寄信, 1=僅本站連結, 2=全部 404
'email_to' => 'webmaster@example.com', // 通知信箱
'email_from' => 'noreply@example.com', // 寄件者
'log_file' => __DIR__ . '/logs/404.log', // 本地日誌
];
// ====================
// 確保日誌目錄存在
$logDir = dirname($config['log_file']);
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
// 取得請求資訊
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$referer = $_SERVER['HTTP_REFERER'] ?? '直接存取/書籤';
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
$time = date('Y-m-d H:i:s');
// 記錄本地日誌
$logLine = "[$time] IP:$ip | URI:$requestUri | REF:$referer | UA:$ua\n";
file_put_contents($config['log_file'], $logLine, FILE_APPEND | LOCK_EX);
// 判斷是否寄送郵件
$shouldMail = false;
if ($config['report_level'] === 2) {
$shouldMail = true;
} elseif ($config['report_level'] === 1) {
// 僅當 Referer 包含本域名時寄信(疑似站內斷連結)
if (stripos($referer, $config['domain']) !== false) {
$shouldMail = true;
}
}
if ($shouldMail) {
$subject = "[404 Alert] $config[domain] - $requestUri";
$body = "時間: $time\n";
$body .= "IP: $ip\n";
$body .= "請求 URI: {$config['docroot']}$requestUri\n";
$body .= "來源頁面: $referer\n";
$body .= "User-Agent: $ua\n";
$body .= "\n---\n此郵件由 404 監控系統自動發送。\n";
$headers = "From: {$config['email_from']}\r\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
$headers .= "X-Priority: 3\r\n";
@mail($config['email_to'], $subject, $body, $headers);
}
// 輸出友善 404 頁面
http_response_code(404);
?>
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="noindex, nofollow">
<title>404 - 頁面不存在</title>
<style>
body { font-family: <?= htmlspecialchars($config['font_face']) ?>; font-size: <?= htmlspecialchars($config['font_size']) ?>; background: <?= htmlspecialchars($config['bg_color']) ?>; color: <?= htmlspecialchars($config['text_color']) ?>; display:flex; align-items:center; justify-content:center; min-height:100vh; margin:0; padding:2rem; text-align:center; }
.container { max-width: 600px; }
h1 { font-size: 6rem; margin: 0 0 1rem; color: #e74c3c; }
p { line-height: 1.6; margin: 1rem 0; }
.uri { font-family: monospace; background: #f5f5f5; padding: 0.5rem; border-radius: 4px; word-break: break-all; }
a { color: #3498db; text-decoration: none; }
a:hover { text-decoration: underline; }
.btn { display:inline-block; margin-top:1.5rem; padding:0.75rem 1.5rem; background:#3498db; color:white; border-radius:4px; }
</style>
</head>
<body>
<div class="container">
<h1>404</h1>
<p>很抱歉,您尋找的頁面不存在或已移除。</p>
<p>請求路徑:<span class="uri"><?= htmlspecialchars($config['docroot'] . $requestUri) ?></span></p>
<p><a href="<?= htmlspecialchars($config['docroot']) ?>" class="btn">返回首頁</a> <a href="javascript:history.back()" class="btn" style="background:#95a5a6">返回上一頁</a></p>
<?php if ($shouldMail): ?>
<p style="font-size:0.9rem; color:#777; margin-top:2rem">系統已自動通知管理員檢查此問題。</p>
<?php endif; ?>
</div>
</body></html>
ErrorDocument 404 /404.php
error_page 404 /404.php;
location = /404.php {
fastcgi_pass php-fpm;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param HTTP_REFERER $http_referer;
include fastcgi_params;
}
| 功能 | 實作方向 |
|---|---|
| 資料庫記錄 | 建立 404_logs 表,支援儀表板查詢、統計、標記處理狀態 |
| 頻率限制 | 同一 IP/URI 短時間內不重複寄信(Redis 計數器) |
| 智慧分類 | 判斷是爬蟲掃描、站內斷連結、外部錯誤連結、遷移遺漏 |
| 自動修復建議 | 對比網站地圖、資料庫文章 slug、歷史重導向規則,推薦修正路徑 |
| 整合通知 | Slack/Discord/Telegram Webhook、PagerDuty、企業微信 |
noindex, nofollow這個 404 處理器提供即時通知、本地日誌、友善錯誤頁面三合一功能。部署後可持續監控網站健康度,搭配定期審查日誌、修復斷連結、設定 301 重導向,能有效提升 SEO 與使用者體驗。