必须用max(1, min($page, $total_pages))约束页码范围,动态计算$start/$end实现居中页码块,intval过滤$_get['page']并http_build_query保留参数,offset应为($page-1)*$per_page。

页码超出总页数还显示怎么办
PHP分页中常见现象:当前页是 $page = 10,但总记录数只有 23 条、每页 10 条,实际最多只有 3 页,却仍渲染出第 10 个页码链接——这是没做边界校验的典型表现。
必须在计算前强制约束 $page 范围:
- 用
max(1, min($page, $total_pages))重置合法页码,避免负数或超限 - 数据库查询时也要同步用该值,否则
OFFSET会越界(如OFFSET 90 LIMIT 10对 23 条数据无意义) - 注意:
$total_pages = ceil($total_count / $per_page)必须用ceil(),不能用round()或整除
页码数字不连续、中间跳号怎么修
这不是数据错,而是分页导航逻辑写死了固定范围(比如“只显示 1~5”),没适配当前页位置。正确做法是动态生成“当前页居中”的页码块。
示例逻辑(每页显示 5 个页码,当前页居中):
立即学习“PHP免费学习笔记(深入)”;
$show_num = 5;
$half = (int)($show_num / 2);
$start = max(1, $page - $half);
$end = min($total_pages, $page + $half);
// 若靠近开头/结尾,平移区间使长度保持 $show_num(除非总页数不足)
if ($page <= $half) {
$end = min($total_pages, $show_num);
} elseif ($page + $half > $total_pages) {
$start = max(1, $total_pages - $show_num + 1);
}
关键点:$start 和 $end 必须每次请求都重新算,不能缓存或硬编码。
URL 参数干扰导致页码解析失败
比如链接是 /list.php?cat=2&page=5&sort=desc,但代码只取 $_GET['page'] 却没过滤非数字,或没保留其他参数拼接下一页链接。
常见问题和对策:
-
intval($_GET['page'])或(int)$_GET['page']强制转整型,防字符串注入(如page=5abc) - 生成页码链接时,用
http_build_query(array_merge($_GET, ['page' => $i]))保留原始参数,别手动拼?cat=2&page= - 若用伪静态(如
/list/5),确保路由规则明确捕获页码并传入$_GET['page'],否则$_GET为空
数据库偏移量 OFFSET 计算错误
页码从 1 开始,但 SQL 的 OFFSET 是从 0 开始——这是最常被忽略的偏移偏差。
错误写法:$offset = $page * $per_page → 第 1 页跳过 10 条,直接查第 11 条起
正确写法:$offset = ($page - 1) * $per_page
同时注意:
- MySQL 8.0+ 支持
LIMIT offset, row_count,但低版本只认LIMIT row_count OFFSET offset,语法要匹配 - 如果用了
SQL_CALC_FOUND_ROWS,记得后续查SELECT FOUND_ROWS(),而不是复用上一次的$total_count - 大数据量慎用
OFFSET,超过 10 万行后性能陡降,应改用游标分页(基于上一页最后 ID)
页码错乱往往不是单一环节的问题,而是参数校验、URL 构造、SQL 偏移、前端渲染四者没对齐。尤其要注意 $page 在进入 SQL 前是否已被重置、是否被恶意篡改、是否参与了多次不同逻辑的计算。










