ThinkPHP排序最安全用法是order()传关联数组,如->order(['create_time'=>'desc','id'=>'asc']),天然防注入、兼容多字段及关联查询;字符串拼接易被注入且不安全。

ThinkPHP 排序最简单、最安全的用法,就是用 order() 方法传关联数组,比如:->order(['create_time' => 'desc', 'id' => 'asc'])。不拼字符串、不写 raw、不依赖模型属性,一行代码搞定,且天然防注入、兼容多字段、支持关联查询。
直接用数组,别拼字符串
字符串写法如 ->order('create_time desc, id asc') 看似简洁,但字段名没转义,遇到用户输入或带点号的字段(如 user.status)容易报错或被注入。数组方式由框架自动加反引号、过滤非法字符,更可靠。
- ✅ 正确写法:
->order(['status' => 'desc', 'create_time' => 'asc']) - ❌ 避免写法:
->order(input('sort') . ' ' . input('order'))(高危!) - 字段含关联表时(如
user.name),数组仍可直接用;字符串必须手动加`user`.`name`,漏一个就崩
用户能选排序字段?必须白名单校验
前端传什么字段就排什么字段,等于把数据库字段名暴露给用户——这是 SQL 注入的温床。哪怕只允许 id、title、create_time 几个字段,也得硬编码校验。
- 定义白名单:
$allow = ['id' => 'id', 'title' => 'title', 'create_time' => 'create_time']; - 取参并校验:
$field = input('sort_field', 'id'); $safeField = $allow[$field] ?? 'id'; - 方向只认两个值:
$dir = in_array(input('sort_type'), ['asc', 'desc']) ? input('sort_type') : 'desc'; - 最终调用:
->order([$safeField => $dir])
多字段排序,顺序即优先级
数组里键值对的顺序,就是 SQL 中 ORDER BY 的执行顺序。先按状态降序,状态相同时再按时间升序,就写成:
立即学习“PHP免费学习笔记(深入)”;
->order(['status' => 'desc', 'create_time' => 'asc'])- 生成的 SQL 是:
ORDER BY status DESC, create_time ASC - 不用额外写逻辑,也不用担心字段重复或覆盖 —— TP6 的
order()是“最后设置生效”,所以多个order()调用会覆盖前一个,建议统一收口
分页时排序参数别丢
点击“创建时间”切换升/降序,页面跳回第一页?问题出在分页链接没保留当前页码。URL 中必须显式带上 page 参数。
- 前端链接示例:
{:url('article/index', ['create_time' => $nextDir, 'page' => input('page', 1)])} - 或用
request()->param()全量透传(排除敏感参数后) - 搜索器(如
searchCreateTimeAttr)里只管加order(),分页由控制器统一调用paginate(),不要在里面改页码



















