ThinkPHP 8.1 的 IN 查询本身安全,前提是使用数组语法(如 where('id', 'in', input('ids/a'))触发参数化绑定;禁用字符串拼接,字段/表名需白名单校验,子查询应通过 Db::query() 配合占位符实现。

ThinkPHP 8.1 中的 IN 查询本身是安全的——前提是使用框架推荐的数组语法,不拼接字符串。它底层会自动将数组元素转为参数化占位符(如 WHERE id IN (?, ?, ?)),每个值独立绑定,天然隔离恶意输入。
IN 查询必须用数组写法,禁用字符串拼接
安全写法(自动绑定):
-
where('id', 'in', [input('ids/a')])——input('ids/a')表示接收数组,框架自动校验并绑定 -
where(['status' => ['in', input('status_list/a')]])—— 多字段也支持,数组值全走预处理
危险写法(直接绕过防护):
-
where("id IN (" . input('ids') . ")")—— 字符串拼接,ids=1,2,3 OR 1=1就触发注入 -
where("id IN (" . implode(',', input('ids/a')) . ")")—— 即使是数组,手动拼接仍无绑定
用户传入的 IN 值必须强制为数组且非空
ThinkPHP 的 input('xxx/a') 后缀是关键:它确保返回值一定是数组类型,空值返回空数组,非数组输入(如字符串 "1,2,3")会被忽略或报错,避免被误当标量处理。
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 若前端传
ids=1,2,3(字符串),input('ids/a')返回[],查询变成IN (),SQL 报错但不会注入 - 若需接受逗号分隔字符串,应先用
explode(',', trim(input('ids'))),再对每个元素做intval()或白名单校验,最后传入in条件
动态字段名或表名参与 IN 查询时必须白名单校验
IN 查询本身安全,但若字段名、表名来自用户输入(例如多租户按 tenant_id 动态切表),就不能靠绑定解决——因为表名/字段名无法参数化。
- 错误:
Db::table(input('table'))->where('id', 'in', $ids)->select() - 正确:
$allowed_tables = ['user_2024', 'user_2025']; $table = in_array(input('table'), $allowed_tables) ? input('table') : 'user_2024'; Db::table($table)->where('id', 'in', $ids)->select();
复杂场景:嵌套子查询含 IN 时坚持用 query() + 占位符
当需要在原生 SQL 中写 IN (SELECT ...) 或联合多个条件时,不要硬拼,改用 Db::query() 配合问号占位符:
Db::query("SELECT * FROM user WHERE id IN (SELECT uid FROM log WHERE type = ? AND time > ?)", [input('type'), input('start_time')]);- 避免:
Db::query("SELECT * FROM user WHERE id IN (SELECT uid FROM log WHERE type = '" . input('type') . "')");
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










