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

PHP 自製友善 404 頁面:自定義模板、錯誤記錄、管理員郵件通知與 SEO 最佳實踐

     編輯:PHP 綜合知識

為什麼需要自定義 404?

  • **用戶體驗**:友善提示 + 站內搜尋/網站地圖連結,降低跳出率。
  • **SEO**:回傳正確 `404 Not Found` 狀態碼,避免軟 404 (200 OK 卻顯示錯誤頁) 被搜尋引擎判定為低品質。
  • **監控**:記錄Referer、User-Agent、IP、時間,快速發現死連結、爬蟲異常、攻擊嘗試。
  • **安全**:不洩露伺服器路徑、資料庫結構、堆疊追蹤等敏感資訊。

Apache / Nginx 設定

# Apache (.htaccess 或 VirtualHost)
ErrorDocument 404 /404.php

# Nginx
error_page 404 /404.php;
location = /404.php {
    internal;           # 防止直接訪問
    fastcgi_pass php-fpm;
    fastcgi_param REQUEST_URI $request_uri; # 傳遞原始 URI
}

完整 404.php 實作

<?php
/**
 * 友善 404 頁面
 * 需放在網站根目錄,並由 Web Server 導向
 */
http_response_code(404); // 必須最先發送

// --- 配置區 ---
$config = [
    'site_name'      => 'My Awesome Site',
    'site_url'       => 'https://www.example.com',
    'admin_email'    => 'webmaster@example.com',
    'notify_email'   => true,           // 是否發送郵件
    'notify_level'   => 2,              // 1=僅本域 Referer, 2=全部
    'log_file'       => __DIR__ . '/logs/404.log',
    'template'       => __DIR__ . '/templates/404.html.php', // 可選外部模板
    'search_url'     => '/search?q=',   // 站內搜尋連結前綴
    'sitemap_url'    => '/sitemap',
    'contact_url'    => '/contact',
];
// -----------------

// 記錄基本資訊
$info = [
    'time'      => date('c'),
    'ip'        => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
    'uri'       => $_SERVER['REQUEST_URI'] ?? '/',
    'referer'   => $_SERVER['HTTP_REFERER'] ?? 'direct',
    'ua'        => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
    'method'    => $_SERVER['REQUEST_METHOD'] ?? 'GET',
    'host'      => $_SERVER['HTTP_HOST'] ?? '',
];

// 寫入日誌 (JSON Lines 格式,易於 ELK 收集)
$logLine = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
@file_put_contents($config['log_file'], $logLine, FILE_APPEND | LOCK_EX);

// 判斷是否發送郵件
$shouldMail = $config['notify_email'] &&
    ($config['notify_level'] === 2 ||
     ($config['notify_level'] === 1 && stripos($info['referer'], $config['site_url']) !== false));

if ($shouldMail) {
    $subject = "[404 Alert] {$config['site_name']} - {$info['uri']}";
    $body = "Time: {$info['time']}\n"
          . "IP: {$info['ip']}\n"
          . "URI: {$config['site_url']}{$info['uri']}\n"
          . "Referer: {$info['referer']}\n"
          . "User-Agent: {$info['ua']}\n";
    $headers = "From: {$config['admin_email']}\r\n"
             . "Content-Type: text/plain; charset=UTF-8\r\n";
    // 非阻塞發送 (生產建議用隊列 + worker)
    @mail($config['admin_email'], $subject, $body, $headers);
}

// --- 輸出 HTML ---
// 若有外部模板且可讀,則 include,否則用內建模板
if (is_readable($config['template'])) {
    include $config['template'];
} else {
    // 內建響應式模板
    ?>
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex, nofollow">
  <title>404 - 頁面不存在 | <?= htmlspecialchars($config['site_name']) ?></title>
  <style>
    body{font-family:system-ui,sans-serif;background:#f5f5f5;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:1rem}
    .card{background:#fff;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.1);padding:3rem 2rem;max-width:480px;text-align:center}
    h1{font-size:6rem;margin:0;color:#e74c3c;line-height:1}
    h2{font-size:1.5rem;margin:1rem 0 0.5rem;color:#2c3e50}
    p{color:#7f8c8d;margin:1rem 0}
    .btn{display:inline-block;margin:0.5rem;padding:0.75rem 1.5rem;background:#3498db;color:#fff;text-decoration:none;border-radius:4px;transition:background .2s}
    .btn:hover{background:#2980b9}
    .btn-secondary{background:#95a5a6}
    .btn-secondary:hover{background:#7f8c8d}
  </style>
</head>
<body>
  <div class="card">
    <h1>404</h1>
    <h2>找不到頁面</h2>
    <p>抱歉,您訪問的頁面 <?= htmlspecialchars($info['uri']) ?> 不存在或已移除。</p>
    <p>
      <a class="btn" href="<?= $config['site_url'] ?>">返回首頁</a>
      <a class="btn btn-secondary" href="<?= $config['site_url'] . $config['sitemap_url'] ?>">網站地圖</a>
    </p>
    <p>或嘗試搜尋您想要的內容:</p>
    <form action="<?= $config['site_url'] . $config['search_url'] ?>" method="GET">
      <input type="search" name="q" placeholder="關鍵字..." style="padding:0.5rem;border:1px solid #ddd;border-radius:4px;width:70%;max-width:280px">
      <button type="submit" class="btn">搜尋</button>
    </form>
    <p style="margin-top:2rem;font-size:0.875rem;color:#95a5a6">
      若您認為這是錯誤,請 聯繫我們。
    </p>
  </div>
</body>
</html>
<?php
}
?>

外部模板範例 (templates/404.html.php)

<?php // 變數 $config, $info 已在作用域中 ?>
<!DOCTYPE html>
<html><head><title>404 - <?= $config['site_name'] ?></title></head><body>
  <h1>頁面走失了 😢</h1>
  <p>請求: <code><?= htmlspecialchars($info['uri']) ?></code></p>
  <a href="<?= $config['site_url'] ?>">回首頁</a>
</body></html>

進階:結構化日誌 + ELK / Loki 收集

將 `$logLine` 直接寫入檔案,配合 Filebeat / Promtail 採集,即可在 Kibana / Grafana 建立儀表板:

  • 404 趨勢圖 (每小時/每天)
  • Top 20 404 URI
  • Referer 來源分析 (識別壞連結來源網站)
  • User-Agent 異常檢測 (惡意掃描器)
  • GeoIP 關聯 (攻擊來源國家)

SEO 關鍵檢查清單

  1. HTTP 狀態碼 **必須為 404** (非 200、301、302)。
  2. 頁面包含 ``。
  3. 不自動重導向 (除非有明確 301 對應新 URL)。
  4. 提供站內搜尋、網站地圖、首頁連結,幫助用戶與爬蟲找到有效內容。
  5. 定期從 Search Console / Bing Webmaster Tools 匯出 404 報告,批次修復或設定 301。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved