核心邏輯
- 取得總筆數
SELECT COUNT(*)
- 計算總頁數
ceil(total / pageSize)
- 當前頁
$page = max(1, min((int)$_GET['page'], $totalPages))
- 偏移量
$offset = ($page - 1) * $pageSize
- 查詢
SELECT * FROM table LIMIT $offset, $pageSize
完整程式碼 (PDO 版,防注入)
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pageSize = 10;
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
// 總筆數
$stmt = $pdo->query('SELECT COUNT(*) FROM users');
$total = $stmt->fetchColumn();
$totalPages = (int)ceil($total / $pageSize);
$page = min($page, $totalPages ?: 1);
// 分頁查詢
$offset = ($page - 1) * $pageSize;
$stmt = $pdo->prepare('SELECT * FROM users ORDER BY id DESC LIMIT :offset, :size');
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->bindValue(':size', $pageSize, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
用戶列表
| ID | 用戶名 | Email |
| = $r['id'] ?> | = htmlspecialchars($r['username']) ?> | = htmlspecialchars($r['email']) ?> |
安全與優化清單
| 項目 | 做法 |
| SQL 注入 | PDO prepared statement + bindValue 整數參數 |
| 頁碼邊界 | max/min 夾擠 $page 於 1~$totalPages |
| 大偏移量效能 | 百萬級資料改用「游標分頁」: WHERE id > $lastId LIMIT $size |
| 總數快取 | Redis 快取 COUNT(*),定期更新 |
| XSS | 輸出用 htmlspecialchars() |
進階:游標分頁 (Keyset Pagination)
// 適合無限捲動、大資料集
$lastId = (int)($_GET['after'] ?? 0);
$stmt = $pdo->prepare('SELECT * FROM users WHERE id > ? ORDER BY id LIMIT ?');
$stmt->execute([$lastId, $pageSize]);
$rows = $stmt->fetchAll();
$nextCursor = $rows ? end($rows)['id'] : null; // 回傳給前端下一次請求
相關專題
- 《PHP 常見資料庫操作技巧匯總》
- 《PHP 陣列操作技巧大全》