$strict 控制字段存在性校验,非法字段抛异常;$allowfield 是写入白名单,仅保留指定字段。二者职责不同,需组合使用防误更新和字段注入。

ThinkPHP 中的 $strict 和 $allowField 是两个常被混淆、但职责完全不同的机制:前者管“字段存不存在”,后者管“字段让不让写”。想真正防止误更新或非法字段注入,必须分清它们的作用边界,并组合使用。
strict = true 不等于字段过滤
$strict = true 的作用是开启模型字段合法性校验。当传入一个数据库里根本不存在的字段(比如 user_namme 拼错),模型会在 PHP 层直接抛出 InvalidArgumentException: property not exists,而不是静默忽略或写入失败。
但它不会剔除字段,也不会阻止合法字段被误更新。例如你传了 ['id' => 1, 'password' => '123', 'status' => 1],只要 password 是真实字段,$strict = true 不会拦它——它照常进 SQL。
常见误区:
- 设了 $strict = false 就以为能“防错” → 实际只是把报错变静默,风险更高
- 依赖 $strict 防止敏感字段更新 → 完全无效,password、token 等字段照样入库
allowField 是唯一生效的字段白名单
$allowField 是模型写入阶段真正的字段过滤开关,它在数据进入 data() 前就执行白名单筛选,只保留你明确列出的字段。
正确用法必须满足三个条件:
- 字段名与数据库列名严格一致(含大小写,如 user_name 不能写成 userName)
- 必须链式调用:$model->allowField(['id', 'name', 'status'])->save($data)
- 不能靠属性赋值:$model->allowField = [...]; $model->save($data) 完全不生效
注意:Db::name('user')->update($data) 绕过模型,$allowField 失效;关联模型也需各自定义 $allowField,主模型的设置不传递。
动态白名单要清洗 + 校验 + 实例绑定
从数据库或配置读取白名单时,不能直接传给 allowField():
- 先清洗:用
array_filter($fields, 'is_string')去掉空值、数字、布尔等非字符串项 - 再校验:比对
(new UserModel())->getSchema()->getFields(),确保每个字段真实存在 - 最后绑定:必须在同一个模型实例上调用,
UserModel::create($data)这类静态方法无法继承实例上的allowField
推荐封装为模型方法:saveWithScene($data, $scene),内部完成查库、清洗、校验、调用 allowField()->save(),避免控制器重复逻辑。
查询字段也要白名单,和写入无关
$allowField 只影响 save/update 等写入操作,对 select 查询毫无作用。
防止 SELECT * 泄露敏感字段,必须显式指定字段:
- 用
UserModel::field('id,name,email,created_at')->select() - 关联查询时,每个
with()都要单独加field(),否则关联表仍可能查出全部字段 -
$hidden和$visible只控制toArray()输出,不干预数据库查询本身
白名单优于黑名单:field(['id','name']) 明确限定,新增字段默认不出;withoutField(['password']) 容易遗漏新敏感字段。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











