最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
thinkphp排序如何配合模型使用 开发教程分享
时间:2026-07-10 10:08:52 编辑:袖梨 来源:一聚教程网
ThinkPHP排序需白名单校验字段和方向,优先用关联数组语法order(['field' => 'asc']),关联表排序须显式join并映射别名,分页时order必须前置且appends透传参数。
ThinkPHP 的排序不是模型自带的“开关”,而是查询时动态附加的行为。模型本身不保存排序逻辑,真正起作用的是你在 调用查询方法前 传给 order() 的参数。用得好,它能灵活响应用户选择;用错,轻则排序失效,重则触发 SQL 注入。
排序字段必须白名单校验,不能信任任何用户输入
用户传来的 sort=price&dir=desc 看似干净,但攻击者可能发 sort=id%20DESC,%20(SELECT%20password%20FROM%20user)%20--。ThinkPHP 的 order() 默认不做字段合法性检查,字符串拼接等于裸奔。
- 在控制器或服务层定义明确的可排序字段列表,例如:
['id', 'name', 'create_time', 'status', 'price'] - 用
in_array()严格判断用户请求的字段是否在此列表中,不在就 fallback 到默认字段(如'id') - 方向参数同样只允许
'asc'或'desc',其他值一律转为'asc' - 禁止使用
Db::raw()或字符串拼接方式传参,例如order($field . ' ' . $dir)是高危写法
优先用数组语法,让框架自动转义字段名
ThinkPHP 6.0+ 推荐且安全的写法是数组形式:order(['field' => 'asc'])。它会自动给字段加反引号,避免字段名为保留字(如 order、group)时报错,也防止大小写或下划线引发歧义。
- 正确示例:
UserModel::order(['price' => 'desc', 'id' => 'asc'])->select() - 多字段排序统一用关联数组,不要混用字符串和数组
- 避免一维数组
['price', 'desc']这种旧式写法,易被版本兼容性问题坑到 - 别依赖
parseOrder()自动识别——它只认模型$schema中存在的字段,不处理关联路径或别名
关联字段排序要手动映射,不能直接写 user.address.city
想按地址城市排序?withCount() 或 with() 加 order('address.city') 是无效的。TP 不会解析点号路径,也不会自动补 JOIN 条件,SQL 直接报错 Unknown column 'address.city'。
立即学习“PHP免费学习笔记(深入)”;
- 必须显式使用
join()并设定表别名,例如:->join('address a', 'user.id = a.user_id') - 排序字段写成别名形式:
order(['a.city' => 'asc']) - 如果多个关联字段需支持排序,提前建好映射表:
['city' => 'a.city', 'province' => 'a.province'],再根据用户选择取对应值 - 用
withCount()统计后参与排序?不行——统计字段不在主 SELECT 中,得改用join + group + count()显式构造
分页时 order 必须前置,且 URL 参数要透传
调用 paginate() 时,如果你先写了 order(),但没把 sort 和 dir 带进分页链接,第二页就会回到默认排序——因为 paginate 生成的翻页 URL 默认不携带这些参数。
-
order()必须写在paginate()调用之前,且不能被后续链式方法覆盖 - 翻页链接补参用
appends():->appends(['sort' => $field, 'dir' => $dir]) - 如果用了复杂排序(含函数或 JOIN),注意
count()查询可能与主查询不一致,需手动传入count参数避免分页错乱 - 缓存排序结果时,记得把
sort和dir作为缓存键的一部分,否则不同排序共用同一缓存
相关文章
- 猫王小黄鸭 07-21
- 日落海滩时尚人像 07-21
- iOS哔咔网页版入口-哔咔漫画iOS网页版入口 07-21
- 高级定制时装风暴巨片 07-21
- 卧室抓拍人像生活方式 07-21
- 影棚电影级时尚肖像 07-21