thinkphp不自动防sql注入,安全取决于写法:用数组条件的where()最稳妥;拼接字符串、滥用exp或原生sql不bind()则危险;in查询需动态占位符或链式调用,空数组须提前判断。

ThinkPHP 本身不自动防 SQL 注入,关键取决于你用什么方式写查询——用查询构造器或 ORM 模型基本安全;一旦拼字符串、绕过绑定、滥用 EXP 表达式,立刻失守。
用 where() 数组条件代替字符串条件
数组形式的 where() 会触发 ThinkPHP 内部的类型检测和参数绑定,是默认最稳妥的方式。字符串条件虽然支持预处理占位符(如 %d、%s),但容易漏写或格式错配,且无法覆盖复杂逻辑。
- 安全写法:
$user = M('User')->where(['id' => I('get.id'), 'status' => 1])->find(); - 危险写法:
$user = M('User')->where("id=".I('get.id')." AND status=1")->find();—— 这里I('get.id')未做任何类型约束,攻击者传1 OR 1=1就直接生效 - 即使写字符串条件,也必须用占位符:
$user = M('User')->where("id=%d AND status=%d", [I('get.id'), 1])->find();,但不如数组直观可靠
原生 SQL 必须用 bind(),且类型要显式声明
Db::query() 和 Db::execute() 是纯透传接口,不做任何过滤或绑定——它把你的字符串原样交给 PDO。不手动 bind(),等于裸奔。
- 位置占位符必须配索引数组:
Db::query("SELECT * FROM user WHERE id = ? AND status = ?", [1, 0]); - 命名占位符必须配关联数组:
Db::query("SELECT * FROM user WHERE id = :id AND status = :status", [':id' => 1, ':status' => 0]); - 混用会静默失效:
Db::query("...", [1, ':status' => 0])不报错,但:status根本没被绑定 - 数值类参数建议显式指定类型:
bind([1, 0], [\PDO::PARAM_INT, \PDO::PARAM_INT]),避免 PDO 自动推断出错
IN 查询不能直接 bind 数组
把一个 PHP 数组直接传给 bind(),ThinkPHP 会把它当单个字符串参数处理,生成类似 WHERE id IN ('1,2,3') 的错误 SQL,既语法报错,又彻底绕过预处理。
- 正确做法一(动态占位符):
$ids = [1, 2, 3]; $placeholders = str_repeat('?,', count($ids) - 1) . '?'; Db::query("SELECT * FROM user WHERE id IN ($placeholders)", $ids); - 正确做法二(链式调用):
Db::name('user')->where('id', 'in', $ids)->select();—— 内部已封装好 IN 绑定逻辑 - 空数组必须提前判断:
if (empty($ids)) { return []; },否则IN ()直接触发 SQL 语法错误
EXP 表达式和数组参数是高危盲区
ThinkPHP 允许用 ['id' => ['exp', 'UPPER(username)']] 这类写法,但 EXP 本质是把用户输入原样塞进 SQL,极易被利用。同样,I('get.id') 返回数组时(如 ?id[where]=1),会跳过常规过滤。
- 禁用非必要 EXP:
$allowExp = ['eq', 'neq', 'gt', 'egt']; $exp = in_array(I('get.exp'), $allowExp) ? I('get.exp') : 'eq'; - 强制转换数组参数:
$id = is_array(I('get.id')) ? intval(reset(I('get.id'))) : intval(I('get.id')); - 配置层加固:
'DB_PARAMS' => ['strict' => true]可阻止非法字段名条件,但不能替代代码层校验
真正容易被忽略的不是“怎么写安全”,而是“哪些地方看似安全实则危险”:比如 I('get.id') 看似经过过滤,但它只对字符串做 htmlspecialchars,对数字不做类型拦截;比如 where("id=%d", $id) 看似用了占位符,但如果 $id 是数组或对象,%d 会转成 0 或触发警告,反而掩盖真实问题。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











