本類針對**舊項目維護**、**教學演示**、**快速原型**場景,封裝 mysql_* 系列函數實現分頁。**生產新項目嚴禁使用**,應改用 PDO / MySQLi / MySQLnd,具備預處理、事務、異步、更好性能與安全性。
<?php
class PageUtil4MySQL {
private $pageSize = 10;
public $currPageNum = 1;
public $countOfCurrPage = 0;
private $resultList = [];
public $totalPageNum = 0;
public $totalRecordNum = 0;
public $startRowNum = 0;
public $errorMsg = '';
public function __construct($pageSize = 10) {
$this->pageSize = max(1, (int)$pageSize);
}
public function setPageSize($pageSize) {
$this->pageSize = max(1, (int)$pageSize);
return $this;
}
/**
* 獲取指定頁數據
* @param int $pageNum 頁碼(從 1 開始)
* @param string $selectStr 完整 SELECT 語句(不含 LIMIT)
* @param int $fetchStyle MYSQL_ASSOC | MYSQL_NUM | MYSQL_BOTH
* @return array 指定頁的記錄數組
*/
public function resultListOfPage($pageNum, $selectStr, $fetchStyle = MYSQL_ASSOC) {
$this->resultList = [];
$this->currPageNum = (int)$pageNum;
// 1. 計算總行數(子查詢替換 SELECT 列表為 COUNT(*))
$totalRowNum = $this->getRowCount($selectStr);
$this->totalRecordNum = $totalRowNum;
if ($totalRowNum > 0) {
$this->totalPageNum = (int)ceil($totalRowNum / $this->pageSize);
// 2. 頁碼邊界修正
if ($this->currPageNum < 1 || $this->currPageNum > $this->totalPageNum) {
$this->currPageNum = 1;
}
// 3. 拼接 LIMIT 子句
$this->startRowNum = ($this->currPageNum - 1) * $this->pageSize;
$selectStr .= " LIMIT {$this->startRowNum}, {$this->pageSize}";
// 4. 執行查詢
$rs = @mysql_query($selectStr);
if (!$rs) {
$this->errorMsg = mysql_error();
return [];
}
while ($row = mysql_fetch_array($rs, $fetchStyle)) {
$this->resultList[] = $row;
}
mysql_free_result($rs);
$this->countOfCurrPage = count($this->resultList);
}
return $this->resultList;
}
/**
* 通過正則將 SELECT ... FROM 轉為 SELECT COUNT(*) FROM,並移除 ORDER BY
*/
private function getRowCount($selectStr) {
$selectStr = trim($selectStr);
// 替換 SELECT 列表
$selectStr = preg_replace('/^SELECT\s+.*?\s+FROM/is', 'SELECT COUNT(*) FROM', $selectStr);
// 移除 ORDER BY
$selectStr = preg_replace('/\s+ORDER\s+BY\s+.*$/is', '', $selectStr);
$rs = @mysql_query($selectStr);
if (!$rs) return 0;
$row = mysql_fetch_array($rs, MYSQL_NUM);
mysql_free_result($rs);
return (int)$row[0];
}
}
?>
<?php
require_once 'PageUtil4MySQL.php';
$pageSize = isset($_GET['pageSize']) ? (int)$_GET['pageSize'] : 10;
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$selectStr = "SELECT * FROM users ORDER BY id DESC";
$pageUtil = new PageUtil4MySQL($pageSize);
$rsltList = $pageUtil->resultListOfPage($page, $selectStr);
$totalPage = $pageUtil->totalPageNum;
$currPageNum = $pageUtil->currPageNum;
$totalRecordNum = $pageUtil->totalRecordNum;
$countOfCurrPage= $pageUtil->countOfCurrPage;
?>
<!-- 分頁導航 -->
<?php if ($totalPage > 1): ?>
<div style="text-align:center;margin:10px;">
共 =$totalPage?> 頁,當前第 =$currPageNum?> 頁,共 =$totalRecordNum?> 條
<a href="?page=1&pageSize==$pageSize?>">首頁
<a href="?page==$currPageNum-1?>&pageSize==$pageSize?>">上一頁
<a href="?page==$currPageNum+1?>&pageSize==$pageSize?>">下一頁
<a href="?page==$totalPage?>&pageSize==$pageSize?>">尾頁
</div>
<?php endif; ?>
<!-- 數據列表 -->
<table>
<?php foreach ($rsltList as $user): ?>
<tr>
<td>=$user['id']?></td>
<td>=$user['name']?></td>
<td>=$user['email']?></td>
</tr>
<?php endforeach; ?>
</table>
mysql_real_escape_string 或強制要求預處理(需升級 MySQLi/PDO)。getRowCount() 正則局限:不支援巢狀子查詢、UNION、CTE、帶別名的複雜 SELECT。複雜查詢建議手動傳入 COUNT(*) SQL 或單獨查總數。LIMIT 100000, 10 仍會掃描前 10 萬行。大數據量必須改用游標分頁(WHERE id > last_id LIMIT 10)或覆蓋索引優化。mysql_pconnect() 建立連接池效果,減少握手開銷。mysql_query("SET NAMES utf8mb4"),防止中文亂碼。| 當前 | 目標 | 關鍵改動 |
|---|---|---|
| mysql_* | MySQLi (面向過程) | 函數名加 i、連接對象前置、預處理 prepare/bind_param |
| mysql_* | PDO | 統一介面、支援多庫、異常處理、命名佔位符 |
| mysql_* | MySQLnd (原生驅動) | PHP 5.3+ 內建,替換 libmysqlclient,內存更少、功能更全 |
本分頁類作為**過渡期維護工具**或**教學樣本**有其價值,展示了分頁核心邏輯:總數統計 → 邊界修正 → LIMIT 拼接 → 結果集封裝。但請牢記:新項目零容忍 mysql_*,技術債務最終都要還。