如何设置ThinkPHP Model的hidden属性以隐藏输出时的敏感信息?

2026-05-07 04:211阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计711个文字,预计阅读时间需要3分钟。

如何设置ThinkPHP Model的hidden属性以隐藏输出时的敏感信息?

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,不会继承主模型设置
  • 空数组 [] 表示“一个字段都不返回”,不是“返回全部”
标签:PHPThinkPHP

本文共计711个文字,预计阅读时间需要3分钟。

如何设置ThinkPHP Model的hidden属性以隐藏输出时的敏感信息?

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,不会继承主模型设置
  • 空数组 [] 表示“一个字段都不返回”,不是“返回全部”
标签:PHPThinkPHP