php分页需严格校验$_get['page']:用filter_input(input_get, 'page', filter_validate_int)验证,再max(1, min($page, $total_pages))兜底范围;count(*)与主查询where条件必须完全一致,url分页链接须继承并清理所有非敏感get参数。

PHP分页不是“学会一个函数”就能搞定的事——它是一组必须咬死的逻辑闭环:页码校验、偏移量计算、总数与数据查询分离、URL参数继承、边界兜底。漏掉任意一环,翻页就出错。
怎么校验 $_GET['page'] 才算安全
直接用 $_GET['page'] 拼 SQL 或算偏移量,等于把数据库大门钥匙交给用户。常见错误是只做 (int) 强转,但 (int)"1abc" 会变成 1,(int)"-5" 变成 -5,导致 $offset 为负,MySQL 虽不报错,但行为不可控。
- 必须用
filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT),非法值返回false,再配合默认值处理 - 校验后立刻限制范围:
$page = max(1, min($page, $total_pages)),避免请求第 999 页时查空结果还傻傻渲染页码 - 如果
$total_pages还没算出来(比如先渲染导航),至少先做$page = max(1, (int)$page)防负偏移
LIMIT offset, length 和 LIMIT length OFFSET offset 有啥区别
MySQL 都支持,但语义和风险不同。用 LIMIT $offset, $length 是最直白、最不易出错的写法;而 LIMIT $length OFFSET $offset 容易让人误以为 OFFSET 是可选的,或在拼接时漏掉逗号导致语法混乱。
-
LIMIT 10, 20表示“跳过前 10 条,取接下来 20 条”——这是符合人脑直觉的顺序 -
LIMIT 20 OFFSET 10语义相同,但如果你动态拼字符串,一不小心写成"LIMIT $length OFFSET "$offset(少了个分号或换行),PHP 就可能把$offset当字符串拼进去,触发 SQL 错误 - PDO 绑定时,两个参数都必须显式指定
PDO::PARAM_INT,否则 MySQL 会当成字符串解析,报错类似You have an error in your SQL syntax
为什么 COUNT(*) 和主查询的 WHERE 条件必须完全一致
这是线上最隐蔽的分页错位原因:总数算的是 WHERE status = 1,但主查询漏了这个条件,或者多加了个 AND deleted = 0,结果总页数对不上,翻到某一页突然空白或重复。
- 别手写两遍 WHERE ——抽成变量,例如
$where = "status = ? AND category_id = ?",COUNT 和主查询都复用它 - 如果条件来自用户输入(如搜索关键词),务必对
$search做trim()+htmlspecialchars()+ 参数绑定,空字符串时整个AND title LIKE ?应该被跳过,否则LIKE ''可能匹配所有行 - 大数据量下,
COUNT(*)可能变慢,但不要用SQL_CALC_FOUND_ROWS(MySQL 8.0+ 已废弃),宁可加缓存或异步更新总数
前端页码链接怎么保留 sort、filter 等其他参数
用户按“发布时间倒序”进列表页,点第二页却恢复默认排序,就是因为链接写死了 ?page=2,把原有参数全丢了。
- 用
$params = $_GET;拿全部参数,然后$params['page'] = $i;覆盖,再http_build_query($params) - 记得清理敏感键:
unset($params['token'], $params['debug']);,否则链接里带 token 会被日志或代理记录 - 如果当前 URL 是
/list.php?tag=php&page=1,生成第 3 页链接必须是/list.php?tag=php&page=3,不能是/list.php?page=3&tag=php(顺序无关,但可读性差)
真正卡住人的从来不是“怎么写 LIMIT”,而是当 $page = 0、$per_page = 'abc'、WHERE 条件不一致、URL 参数混杂时,系统是否还能稳住——这些地方没兜底,分页就只是个半成品。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











