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

PHP 實現「上一篇 / 下一篇」文章導航的優化方案

     編輯:PHP 相關知識

文章詳情頁常需「上一篇」「下一篇」導航。基本思路:按 ID 排序,找比當前 ID 小的最大一條(上一篇),比當前 ID 大的最小一條(下一篇)。本文在原始代碼基礎上優化 SQL、防注入、兼容 PDO/MySQLi,並補充邊界處理與緩存建議。

優化版實現(PDO + 預處理)

<?php
function getAdjacentPosts(PDO $pdo, int $currentId): array {
    $result = ['prev' => null, 'next' => null];

    // 上一篇:ID < 當前,倒序取第一條
    $stmt = $pdo->prepare("SELECT id, title FROM article WHERE id < ? ORDER BY id DESC LIMIT 1");
    $stmt->execute([$currentId]);
    $result['prev'] = $stmt->fetch(PDO::FETCH_ASSOC);

    // 下一篇:ID > 當前,正序取第一條
    $stmt = $pdo->prepare("SELECT id, title FROM article WHERE id > ? ORDER BY id ASC LIMIT 1");
    $stmt->execute([$currentId]);
    $result['next'] = $stmt->fetch(PDO::FETCH_ASSOC);

    return $result;
}

// 使用示例
$pdo = new PDO("mysql:host=localhost;dbname=blog;charset=utf8", "user", "pass");
$adj = getAdjacentPosts($pdo, (int)$_GET['id']);

echo '<div class="post-nav">';
if ($adj['prev']) {
    echo '<a href="?id=' . $adj['prev']['id'] . '" class="prev">← 上一篇:' . htmlspecialchars($adj['prev']['title']) . '</a>';
} else {
    echo '<span class="disabled">← 沒有上一篇了</span>';
}
if ($adj['next']) {
    echo '<a href="?id=' . $adj['next']['id'] . '" class="next">下一篇:' . htmlspecialchars($adj['next']['title']) . ' →</a>';
} else {
    echo '<span class="disabled">沒有下一篇了 →</span>';
}
echo '</div>';

關鍵改進點

  1. 預處理語句: 徹底防 SQL 注入,原文直接拼接 $id 極不安全。
  2. 明確排序: 上一篇 ORDER BY id DESC 取最近的較小 ID;下一篇 ORDER BY id ASC 取最近的較大 ID。原文下一篇缺少 ORDER BY,依賴默認順序不可靠。
  3. 只查必要欄位: SELECT id, title 而非 SELECT *,減少 I/O。
  4. 類型轉換: (int)$_GET['id'] 強制整數,雙重保險。
  5. 輸出轉義: htmlspecialchars() 防 XSS。

進階優化:大數據量下的性能

  • 索引: 確保 id 為主鍵(聚簇索引),範圍查詢極快。
  • 緩存: 文章發布後導航關係固定,可將結果存入 Redis(Key: adj:{id},Value: JSON),過期時間設為永久,發布/刪除文章時清理相關 Key。
  • 避免 COUNT(*): 原文用 mysql_num_rows 判斷存在性,實際 fetch 直接返回 false 即可,省一次邏輯。
  • 擴展:按發布時間而非 ID 排序

    若業務要求按 created_at 導航:

    $stmt = $pdo->prepare("SELECT id, title FROM article WHERE created_at < (SELECT created_at FROM article WHERE id = ?) ORDER BY created_at DESC LIMIT 1");
    $stmt->execute([$currentId]);

    需在 created_at 上建索引,並處理同一秒發布多篇的邊界情況(可二級排序 id)。

    「上一篇/下一篇」看似簡單,卻是 SQL 基礎、安全習慣、性能意識的綜合體現。養成寫優化版的肌肉記憶,受益無窮。

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