如何通过ThinkPHP 6框架的Query类闭包查询有效避免SQL注入攻击?
- 内容介绍
- 文章标签
- 相关推荐
本文共计661个文字,预计阅读时间需要3分钟。
因为闭包中的 `where()`、`like()` 等方法默认走参数绑定流程,框架会将变量值单独传递给 PDO 的 `bindValue()` 方法,而不是拼接到 SQL 字符串中。所以,你可以在闭包中直接写 `$$query-`。
闭包里哪些写法仍然危险
闭包本身不自动免疫注入,关键看里面怎么用查询方法:
-
where('name = "' . input('name') . '"')❌ —— 字符串拼接,直接退化为裸 SQL -
where(['name' => ['exp', "UPPER(name) = '" . input('name') . "'"]])❌ ——exp表示“原样执行”,跳过所有绑定 -
order(input('sort'))❌ —— 排序字段不能参数化,必须白名单校验,不能靠闭包“包住”就放心 -
where('id', 'in', input('ids'))✅ —— 框架自动处理IN绑定,前提是input('ids')是数组(如[1,2,3])
闭包配合动态条件的真实写法
常见于后台搜索、多条件筛选等场景,既要灵活又要安全:
- 用
use ($var)显式引入外部变量,避免闭包内直接读$_GET - 条件分支用
if套$query->where(),别堆在一行里拼字符串 - 模糊查询必须用
like()或['like', '%' . $kw . '%'],别写"name LIKE '%{$kw}%'" - 空值或无效参数要提前判断,比如
if (!empty($status)) { $query->where('status', $status); }
示例:
Db::name('user')->where(function ($query) use ($name, $status) { if ($name) { $query->where('name', 'like', '%' . $name . '%'); } if ($status !== null) { $query->where('status', $status); } })->select();
容易被忽略的兼容性细节
ThinkPHP 6 默认启用 PDO 预处理,但以下情况会让绑定失效:
立即学习“PHP免费学习笔记(深入)”;
- MySQL 连接配置中
PDO::ATTR_EMULATE_PREPARES被设为true(Docker 或低版本 MySQL 常见),此时?占位符实际还是字符串替换 - 调用
strict(true)后,空闭包(如where(function ($q) {}))会抛异常,防止条件被静默忽略 -
failException(true)配合使用,能让绑定失败或语法错误在开发期暴露,而不是上线后才被扫出
真正防住注入的,从来不是“用了闭包”,而是“闭包里没拼字符串、没用 exp、没放行不可信字段”。只要有一处松动,整条链就断了。
本文共计661个文字,预计阅读时间需要3分钟。
因为闭包中的 `where()`、`like()` 等方法默认走参数绑定流程,框架会将变量值单独传递给 PDO 的 `bindValue()` 方法,而不是拼接到 SQL 字符串中。所以,你可以在闭包中直接写 `$$query-`。
闭包里哪些写法仍然危险
闭包本身不自动免疫注入,关键看里面怎么用查询方法:
-
where('name = "' . input('name') . '"')❌ —— 字符串拼接,直接退化为裸 SQL -
where(['name' => ['exp', "UPPER(name) = '" . input('name') . "'"]])❌ ——exp表示“原样执行”,跳过所有绑定 -
order(input('sort'))❌ —— 排序字段不能参数化,必须白名单校验,不能靠闭包“包住”就放心 -
where('id', 'in', input('ids'))✅ —— 框架自动处理IN绑定,前提是input('ids')是数组(如[1,2,3])
闭包配合动态条件的真实写法
常见于后台搜索、多条件筛选等场景,既要灵活又要安全:
- 用
use ($var)显式引入外部变量,避免闭包内直接读$_GET - 条件分支用
if套$query->where(),别堆在一行里拼字符串 - 模糊查询必须用
like()或['like', '%' . $kw . '%'],别写"name LIKE '%{$kw}%'" - 空值或无效参数要提前判断,比如
if (!empty($status)) { $query->where('status', $status); }
示例:
Db::name('user')->where(function ($query) use ($name, $status) { if ($name) { $query->where('name', 'like', '%' . $name . '%'); } if ($status !== null) { $query->where('status', $status); } })->select();
容易被忽略的兼容性细节
ThinkPHP 6 默认启用 PDO 预处理,但以下情况会让绑定失效:
立即学习“PHP免费学习笔记(深入)”;
- MySQL 连接配置中
PDO::ATTR_EMULATE_PREPARES被设为true(Docker 或低版本 MySQL 常见),此时?占位符实际还是字符串替换 - 调用
strict(true)后,空闭包(如where(function ($q) {}))会抛异常,防止条件被静默忽略 -
failException(true)配合使用,能让绑定失败或语法错误在开发期暴露,而不是上线后才被扫出
真正防住注入的,从来不是“用了闭包”,而是“闭包里没拼字符串、没用 exp、没放行不可信字段”。只要有一处松动,整条链就断了。

