ThinkPHP5.0防SQL注入核心是参数绑定:优先用数组方式where(['id'=>$id])自动绑定;字符串条件须用%s/%d占位符;禁用user可控的['exp',...]结构,升级至5.0.25+修复parseData漏洞。

ThinkPHP5.0 使用参数绑定防 SQL 注入,核心是让数据不参与 SQL 语句拼接,而是通过数据库驱动层的预处理机制传递——框架会自动把参数转为占位符,并交由 PDO 或 MySQLi 底层安全绑定。这不是“可选技巧”,而是必须落实的底线做法。
用数组方式写 where 条件(最推荐)
这是 ThinkPHP 最自然、最安全的参数绑定方式,框架内部自动识别键值对并转为预处理参数:
- ✅ 正确示例:
$user = Db::name('user')->where(['id' => $id, 'status' => 1])->find(); - ✅ 支持多条件+类型隐式转换:
where(['username' => input('username/s'), 'age' => input('age/d')]),/s强制字符串、/d强制整型,避免绕过 - ❌ 避免混用:
where(['id' => $id])->where("username like '%{$keyword}%'")—— 后半段字符串拼接会破坏绑定安全性
字符串条件中使用格式化占位符
当必须用字符串写查询(如复杂表达式),务必用 %d、%s、%f 等占位符,再传参数数组或多个参数:
- ✅ 安全写法:
Db::name('user')->where("id=%d AND username LIKE '%s'", [$id, "%{$keyword}%"])->select(); - ✅ 也支持解包:
->where("score>%f AND level=%d", $score, $level) - ⚠️ 注意:
%s不会自动加引号,所以LIKE '%s'要手动补单引号;而%d和%f会强制转为数字,天然防注入
手动调用 query/execute 方法走原生预处理
对批量插入、复杂语句或需要完全控制的情况,跳过 Query Builder,直接用底层预处理接口:
- ✅ 批量插入推荐:
Db::query("INSERT INTO user (name, email) VALUES (?, ?)", [$name1, $email1]); - ✅ 多条数据拼占位符:
$placeholders = str_repeat('(?, ?),', count($data) - 1) . '(?, ?)'; Db::query("INSERT INTO user (name, email) VALUES $placeholders", $flatValues);($flatValues是一维数组,按顺序对应所有 ?) - ✅ 查询同样适用:
Db::query("SELECT * FROM user WHERE id IN (" . implode(',', array_fill(0, count($ids), '?')) . ")", $ids);
禁用危险结构,堵住 exp 注入入口
ThinkPHP5.0.13–5.0.15 存在 ['exp', 'UPPER(1)'] 类型的解析漏洞,即使用了参数绑定也可能被绕过:
- ❌ 绝对禁止接收用户传来的嵌套数组:
input('data/a')若未校验字段名,可能带入['username' => ['exp', '...']] - ✅ 升级到 5.0.25+ 或 5.1.40+,官方已修复 parseData() 中对 exp 字段的白名单校验
- ✅ 临时方案:批量插入前用
array_filter($data, function($k) { return in_array($k, ['name', 'email', 'status']); }, ARRAY_FILTER_USE_KEY);
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











