在 MySQL 資料庫應用中,分頁技術的教學資源相當豐富;但針對文字檔(Flat-file)資料儲存模式的分頁實作,卻鮮少見到系統性的介紹。本文將詳細解析以文字檔為基礎的分頁核心邏輯,涵蓋留言本與文字論壇兩種常見應用場景,並提供可直接部署的 PHP 程式碼範例。
以留言本為例,資料檔 Data.dat 採用每行一筆記錄、欄位以 Tab 鍵(\t)分隔的格式:
[ID]\t[發文者]\t[標題]\t[內容]\t[發文時間]\t[IP]
範例資料:
[1]\tuser01\t歡迎光臨\t這是第一則留言\t2023-10-01 12:00\t192.168.1.1 [2]\tuser02\t不錯喔\t內容很充實\t2023-10-01 12:05\t192.168.1.2
其中方括號內的數字為人工添加的流水號,方便教學辨識,實際儲存時可由程式自動管理。
以下為 index.php 完整原始碼,已修正原始片段中的語法錯誤(如 file_exits → file_exists、pirnt → print、變數拼寫一致性),並加入詳細註解:
<?php
// 設定資料檔路徑
$file = "data.dat";
// 容錯:若檔案不存在則建立空檔
if (!file_exists($file)) {
$fp = fopen($file, "w+");
fclose($fp);
unset($fp);
}
// 每頁顯示筆數
$listNumber = 20;
// 將整個檔案讀入陣列,每行為一個元素
$fp = file($file);
$totalRecords = count($fp); // 總筆數
$totalPages = floor($totalRecords / $listNumber) + 1; // 總頁數
// 無資料時的處理
if ($totalRecords < 1) {
print "暫時無記錄,歡迎留言";
// 此處可插入留言表單 HTML
} else {
// 取得目前頁碼(相容 PHP 4.2+ register_globals=Off)
$page = empty($_POST["page"]) ? 0 : (int)$_POST["page"];
// 邊界檢查:頁碼不得小於 0 或大於總頁數
if ($page < 0 || $page >= $totalPages) {
$page = 0;
}
// 計算陣列切片範圍(0-based index)
$start = $page * $listNumber;
$end = $start + $listNumber - 1;
if ($end >= $totalRecords) $end = $totalRecords - 1;
// 輸出表格標頭
print "<table border='1' cellpadding='3' cellspacing='0'>";
print "<tr><th>ID</th><th>發文者</th><th>標題</th><th>內容</th><th>時間</th><th>IP</th></tr>";
// 逆序顯示(最新留言在最上方),模擬 DESC 排序
for ($i = $end; $i >= $start; $i--) {
// 以 Tab 切分欄位
$fields = explode("\t", trim($fp[$i]));
// 欄位對應:[0]=ID, [1]=發文者, [2]=標題, [3]=內容, [4]=時間, [5]=IP
print "<tr>";
print "<td>{$fields[0]}</td>";
print "<td>{$fields[1]}</td>";
print "<td>{$fields[2]}</td>";
print "<td>{$fields[3]}</td>";
print "<td>{$fields[4]}</td>";
print "<td>{$fields[5]}</td>";
print "</tr>";
}
// 分頁導覽列
$prevPage = $page - 1;
$nextPage = $page + 1;
print "<tr><td colspan='6' align='center'>";
// 首頁
print "<a href='{$_SERVER['PHP_SELF']}?page=0'>首頁</a> | ";
// 上一頁(若非第一頁)
if ($page > 0) {
print "<a href='{$_SERVER['PHP_SELF']}?page={$prevPage}'>上一頁</a> | ";
}
// 下一頁(若非最後一頁)
if ($page < $totalPages - 1) {
print "<a href='{$_SERVER['PHP_SELF']}?page={$nextPage}'>下一頁</a> | ";
}
// 尾頁
print "<a href='{$_SERVER['PHP_SELF']}?page=" . ($totalPages - 1) . "'>尾頁</a>";
print "</td></tr>";
print "</table>";
}
?>
file() 將文字檔每行轉為陣列元素,適合中小型資料量(建議 1 萬行以內)。大量資料建議改用 fseek() 配合固定長度記錄,或遷移至資料庫。
陣列索引從 0 開始,故第 1 頁($page=0)對應索引 0~19,第 2 頁($page=1)對應 20~39,以此類推。floor($total/$listNumber)+1 可正確計算總頁數(無條件進位)。
文字檔預設為舊資料在前、新資料在後(APPEND 模式)。透過 for ($i=$end; $i>=$start; $i--) 即可不需額外排序即呈現「最新留言在最上」的效果。
程式碼中針對「首頁/尾頁/上一頁/下一頁」連結皆做邊界判斷,避免產生 page=-1 或 page=總頁數 等無效連結,提升使用者體驗與系統穩定度。
論壇分頁邏輯與留言本大同小異,差異在於:
建議採用「索引檔 + 內容檔」雙檔架構:索引檔僅存主題鍵值與位移,內容檔存完整文章,可大幅降低記憶體佔用。
file() I/O。文字檔分頁雖不如資料庫靈活,但對於輕量級應用(個人留言本、小型公告欄、靜態內容管理)具有「零安裝、零設定、易備份」的優勢。掌握陣列切片、邊界檢查、逆序輸出三大核心技巧,即可輕鬆實作穩定可用的分頁功能。