大量資料分頁顯示是 Web 開發基礎技能。核心在於 MySQL LIMIT offset, count 配合 PHP 動態計算偏移量、總頁數、上下頁連結。
<?php
header("Content-Type: text/html; charset=utf-8");
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$user = 'root';
$pass = '';
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$pageSize = 15; // 每頁筆數
$pageNum = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
// 1. 取得總筆數
$stmt = $pdo->query("SELECT COUNT(*) FROM t1");
$totalRows = $stmt->fetchColumn();
$totalPages = ceil($totalRows / $pageSize);
// 2. 修正頁碼邊界
if ($pageNum > $totalPages) $pageNum = max(1, $totalPages);
$offset = ($pageNum - 1) * $pageSize;
// 3. 分頁查詢
$sql = "SELECT * FROM t1 ORDER BY id LIMIT :offset, :pageSize";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->bindValue(':pageSize', $pageSize, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll();
// 4. 輸出表格
?>
<h1>用戶信息表</h1>
<table border="1" cellpadding="5" cellspacing="0" width="700">
<tr><th>ID</th><th>用戶名</th><th>密碼</th></tr>
<?php foreach ($rows as $row): ?>
<tr>
<td><?= htmlspecialchars($row['id']) ?></td>
<td><?= htmlspecialchars($row['username']) ?></td>
<td><?= htmlspecialchars($row['password']) ?></td>
</tr>
<?php endforeach; ?>
</table>
<h2>
<?php if ($pageNum > 1): ?>
<a href="?page=<?= $pageNum - 1 ?>">上一頁</a>
<?php endif; ?>
<span>第 <?= $pageNum ?> / <?= $totalPages ?> 頁 (共 <?= $totalRows ?> 筆)</span>
<?php if ($pageNum < $totalPages): ?>
<a href="?page=<?= $pageNum + 1 ?>">下一頁</a>
<?php endif; ?>
</h2>
<?php
// 5. 釋放連線 (PDO 物件銷毀自動關閉)
?>
| 關鍵點 | 說明 |
|---|---|
| LIMIT 语法 | LIMIT offset, row_count:offset 從 0 開始,row_count 為每頁筆數。MySQL 也支援 LIMIT row_count OFFSET offset。 |
| 總頁數計算 | ceil(totalRows / pageSize):向上取整,PHP ceil() 函數。 |
| 頁碼邊界修正 | 防止 page 參數超出範圍 (負數、超過總頁數),強制 clamp 到合法區間。 |
| SQL 注入防護 | 使用 Prepared Statement 綁定 :offset、:pageSize 參數,不可直接拼接變數。 |
| XSS 防護 | 輸出變數用 htmlspecialchars() 轉義 HTML 實體。 |
| 效能優化 | 大偏移量 (如 page 10000) LIMIT 掃描成本高,改用游標分頁 WHERE id > last_id LIMIT 15。 |