如何设置ThinkPHP Model的hidden属性以隐藏输出时的敏感信息?
- 内容介绍
- 文章标签
- 相关推荐
本文共计711个文字,预计阅读时间需要3分钟。
ThinkPHP中的`$hidden`属性是模型层最基础的字段过滤机制,但仅在`模型序列化`时生效,并非数据库查询过滤,也不影响原始数据读取。错误场景或写法不当,敏感字段会直接暴露。
hidden 只作用于 toArray() 和 toJson() 等序列化过程
它不会阻止数据库查出 password 字段,只是在转数组或 JSON 时把对应键从结果里剔除:
-
User::find(1)->toArray()✅ 尊重$hidden -
User::find(1)->toJson()✅ 底层调用toArray(),也受控 -
json_encode(User::find(1))❌ 绕过所有模型逻辑,直接序列化对象属性 -
User::field('id,password')->find(1)->toArray()❌ 数据库已查出 password,$hidden只是“不显示”,不是“不查”
字段名必须严格匹配,且仅限当前模型原始字段
大小写、下划线、前缀都不能错,关联模型字段也不会被自动过滤:
- 数据库列是
user_id,就写'user_id',不能写'userId'或'User_id' - 写了
protected $hidden = ['password'],但关联模型Profile里的id_card仍会原样输出 - 想隐藏关联字段,得在
Profile模型里单独加protected $hidden = ['id_card'] -
append添加的虚拟字段(如_mobile_masked)默认不受$hidden影响,需显式列入
别踩这些常见坑
很多“hidden 不生效”的问题,其实根本没走到它的执行路径:
立即学习“PHP免费学习笔记(深入)”;
- 用了
toArray(true)—— 这个true表示强制全量导出,$hidden和$visible全部失效 - 手动拼数组:
['id' => $user->id, 'password' => $user->password]—— 直接取值,模型规则彻底旁路 - 用
Db::name('user')->select()替代UserModel::select()—— 完全不经过模型实例,$hidden压根不启动 - 在控制器里临时改
$user->hidden = ['password']——$hidden是类属性,运行时赋值无效
安全建议:优先用 visible 白名单
比起黑名单式隐藏,白名单更可控,尤其字段多、权限细的接口:
- 删掉
$hidden,改用protected $visible = ['id', 'username', 'avatar'] - 不同接口可动态切换:
$user->visible(['id','username'])->toArray() - 关联模型也要各自配
$visible,不会继承主模型设置 - 空数组
[]表示“一个字段都不返回”,不是“返回全部”
本文共计711个文字,预计阅读时间需要3分钟。
ThinkPHP中的`$hidden`属性是模型层最基础的字段过滤机制,但仅在`模型序列化`时生效,并非数据库查询过滤,也不影响原始数据读取。错误场景或写法不当,敏感字段会直接暴露。
hidden 只作用于 toArray() 和 toJson() 等序列化过程
它不会阻止数据库查出 password 字段,只是在转数组或 JSON 时把对应键从结果里剔除:
-
User::find(1)->toArray()✅ 尊重$hidden -
User::find(1)->toJson()✅ 底层调用toArray(),也受控 -
json_encode(User::find(1))❌ 绕过所有模型逻辑,直接序列化对象属性 -
User::field('id,password')->find(1)->toArray()❌ 数据库已查出 password,$hidden只是“不显示”,不是“不查”
字段名必须严格匹配,且仅限当前模型原始字段
大小写、下划线、前缀都不能错,关联模型字段也不会被自动过滤:
- 数据库列是
user_id,就写'user_id',不能写'userId'或'User_id' - 写了
protected $hidden = ['password'],但关联模型Profile里的id_card仍会原样输出 - 想隐藏关联字段,得在
Profile模型里单独加protected $hidden = ['id_card'] -
append添加的虚拟字段(如_mobile_masked)默认不受$hidden影响,需显式列入
别踩这些常见坑
很多“hidden 不生效”的问题,其实根本没走到它的执行路径:
立即学习“PHP免费学习笔记(深入)”;
- 用了
toArray(true)—— 这个true表示强制全量导出,$hidden和$visible全部失效 - 手动拼数组:
['id' => $user->id, 'password' => $user->password]—— 直接取值,模型规则彻底旁路 - 用
Db::name('user')->select()替代UserModel::select()—— 完全不经过模型实例,$hidden压根不启动 - 在控制器里临时改
$user->hidden = ['password']——$hidden是类属性,运行时赋值无效
安全建议:优先用 visible 白名单
比起黑名单式隐藏,白名单更可控,尤其字段多、权限细的接口:
- 删掉
$hidden,改用protected $visible = ['id', 'username', 'avatar'] - 不同接口可动态切换:
$user->visible(['id','username'])->toArray() - 关联模型也要各自配
$visible,不会继承主模型设置 - 空数组
[]表示“一个字段都不返回”,不是“返回全部”

