安全接收并校验每页条数需强转整型+白名单校验,如input('size/d',15)配合in_array;分页URL须透传全部GET参数避免丢失per_page;count查询需显式cache(false)禁用缓存;paginate()中list_rows以数组方式传参优先级高于全局配置。

控制器里怎么安全接收并校验每页条数参数
直接用 $_GET['size'] 或 input('size') 不加限制是危险的——传个 size=0 会导致分页计算异常,size=-100 可能触发底层保底逻辑,size=999999 更可能拖垮数据库查询。
必须做两件事:类型强转 + 白名单校验。
- 用
input('size/d', 15)确保拿到整型,默认值设为业务常用值(如 15) - 再用
in_array($size, [10, 15, 20, 30, 50])判断是否合法,不合法就兜底回默认值 - 校验后的值才传给
paginate(),例如:$list = User::paginate(['list_rows' => $size, 'page' => input('page/d', 1)])
模板下拉框怎么生成带完整参数的 URL
分页器本身不管理“每页数量”这个维度,$page->render() 默认只保留 page 参数。你点完下拉框切到 per_page=30,再点“下一页”,链接却变成 ?page=2,又变回默认条数——这是最常被忽略的坑。
解决办法只有一个:把当前所有筛选参数显式塞进分页链接。
立即学习“PHP免费学习笔记(深入)”;
- 在控制器中,用
'query' => request()->param()透传全部 GET 参数(包括keyword、category_id、per_page等) - 下拉框不能靠 JS 提交表单,得用
location.href拼完整 URL,比如:location.href = '?per_page=' + val + '&keyword=' + encodeURIComponent(keyword) - 如果用了
appends(),注意它会覆盖query中同名键,慎用
为什么改了 URL 参数但总页数没变
常见现象:后台刚删了 20 条数据,前台翻页还显示“共 127 页”,点进去第 127 页却空着——这不是前端缓存,是 ThinkPHP 对 count 查询启用了默认缓存。
分页的总页数由 ceil($count / $listRows) 算出,而 $count 来自一次独立的 COUNT(*) 查询,该查询默认走缓存(尤其开启 data_cache_type 时)。
- 不要全局关缓存,而是精准控制:在调用
paginate()前,对查询构造器加->cache(false) - 或者更稳妥:用
Db::name('user')->cache(false)->paginate(...) - 若用模型,可在模型方法里统一加
->cache(false),避免漏掉
全局配置和局部配置谁优先级更高
config/paginate.php 里的 'list_rows' => 20 是兜底值,只在你完全没传 list_rows 时生效。一旦你在 paginate() 调用里显式写了 list_rows,无论用数组形式还是整数形式,全局配置都会被跳过。
但要注意一个易错点:写法错误会让全局配置“意外生效”。
- 错:
User::paginate(15, false, ['page' => input('page')])—— 这里第一个参数15是当前页码,不是list_rows,实际用了全局配置 - 对:
User::paginate(['list_rows' => 15, 'page' => input('page/d', 1)])或User::paginate(15)(此时15才是list_rows) - 建议始终用数组方式传参,语义清晰,不易出错
动态改每页条数这事,难点不在代码多,而在参数流转的每个环节都得对齐:控制器要校验、查询要禁缓存、模板要透传、URL 要拼全——漏掉任何一环,用户点下去就会“失联”。



















