thinkphp的where、select等查询构造器默认防sql注入,前提是使用数组或键值对参数绑定(如where('id', $id)),而非字符串拼接(如where("id=$id"));原生sql须用?占位符顺序绑定,动态字段名和order by必须白名单校验,raw和闭包查询需手动过滤输入。

ThinkPHP 的 where、select 等查询构造器方法默认就防 SQL 注入,前提是别手动拼 SQL 字符串——只要用对参数绑定形式,PDO 层的预处理会自动生效;一旦写成 where("name = '$name'"),防护就彻底失效。
where() 传字符串 vs 传数组:安全边界在这里
传字符串时 ThinkPHP 不做参数绑定,只做简单解析;传数组或键值对时才走 PDO prepare 流程。
- ❌ 危险写法:
$user = User::where("id = " . input('id'))->find()——input('id')直接拼进 SQL,' OR 1=1 --一贴就中招 - ✅ 安全写法:
$user = User::where('id', input('id'))->find()或$user = User::where(['id' => input('id')])->find()—— 框架生成WHERE id = ?,变量单独绑定 - ⚠️ 特殊注意:
like场景不能自己拼"%{$kw}%",得用数组语法:['like', '%' . input('kw') . '%']
Db::query() 和 Db::execute() 必须用 ? 占位符
这两个方法不识别变量名,只认 ?,且严格按顺序绑定。命名占位符(如 :name)在 ThinkPHP 里不支持。
- ✅ 正确:
Db::query("SELECT * FROM user WHERE status = ? AND type = ?", [$status, $type]) - ❌ 错误:
Db::query("SELECT * FROM user WHERE status = $status")—— 零防护,等同裸奔 - ⚠️ 关键限制:
?不能用于表名、字段名、ORDER BY子句——这些地方必须白名单校验,例如:in_array($order, ['id', 'create_time']) ?: die('非法排序字段')
Raw 表达式和闭包查询是“信任区”,必须手动过滤
Db::raw() 和闭包里的 where 不受框架参数绑定保护,内容被原样塞进 SQL。
- ❌ 危险:
$model->where('extra', 'like', Db::raw("'%". input('kw') . "%'"))->select()——Db::raw()绕过一切绑定 - ✅ 安全:
$model->where('extra', 'like', '%' . input('kw') . '%')->select()(前提:用数组语法) - ⚠️ 复杂场景(如 JSON 查询、GIS 计算)若非用
raw不可,务必先用filter_var()或正则清洗输入,例如:filter_var(input('path'), FILTER_SANITIZE_STRING)
最易被忽略的是动态字段名和 ORDER BY 子句——它们无法用 ? 占位,也绕过所有绑定逻辑,必须靠白名单硬控;另外,input() 返回的值默认不做过滤,直接喂给 raw 或字符串拼接等于主动交出数据库权限。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











