ThinkPHP 6.1 不自动启用 PDO 预处理防 SQL 注入,需手动强制参数化查询:配置禁用模拟预处理、设异常错误模式、指定字符集;仅安全写法(数组条件、占位符)有效,严禁字符串拼接;动态字段/排序须白名单校验;配合模型验证与输入过滤。

ThinkPHP 6.1 本身不自动开启 PDO 预处理来防御 SQL 注入,是否启用完全取决于你写查询的方式。框架不会帮你把字符串拼接的 SQL “自动转成”预处理语句——传字符串就是直连执行,传数组或占位符才走预处理。所以“开启”不是改个配置开关,而是**强制所有数据库操作走参数化路径**。
确保数据库连接启用真实预处理
在 database.php 配置中,显式关闭模拟预处理,并设置错误模式:
- 添加
'PDO::ATTR_EMULATE_PREPARES' => false,让 MySQL 真正执行预编译,而非 PHP 模拟 - 设置
'PDO::ATTR_ERRMODE' => PDO::ERRMODE_EXCEPTION,便于及时发现绑定错误 - 确认 DSN 中已指定字符集,如
charset=utf8mb4,避免宽字节绕过
只用安全的查询写法(关键)
TP6.1 的 Db 类和模型都支持参数绑定,但必须主动使用,不能依赖“自动防护”:
- ✅ 正确:用数组条件
where(['name' => input('name')])或闭包where(function ($query) { ... }) - ✅ 正确:原生查询用问号占位符
Db::query("SELECT * FROM user WHERE id = ?", [$id]) - ❌ 危险:字符串拼接
where("name = '" . input('name') . "'")或order(input('sort')) - ❌ 危险:用变量直接插进 raw SQL,如
"WHERE status = {$status}"
对动态字段和排序做白名单控制
预处理无法绑定字段名、表名或 ORDER BY 子句,这些必须严格校验:
- 字段名从固定列表中选取:
$allowFields = ['id', 'name', 'create_time']; $field = in_array($input, $allowFields) ? $input : 'id'; - 排序方向限定为
ASC或DESC,不接受用户任意输入 - 避免
order(input('by'))这类写法,哪怕加了 trim 或 addslashes 也不安全
配合模型验证与输入过滤
预处理防的是 SQL 层注入,但业务层仍需清理数据:
- 在模型里定义
$type和$validate,强制字段类型(如'id' => 'integer') - 用
input('id/d')自动转整型,input('name/s')强制字符串,避免类型混淆 - 对富文本等高风险输入,不在 WHERE 条件中直接使用,改用全文检索或独立字段匹配
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











