php层脱敏仅适用于展示前轻量变形,不可用于存储;必须先清洗再切片,且需对不同字段按规则精准脱敏,避免混用加密与脱敏导致数据丢失。

138****1234。真要保护存储安全,得用数据库字段加密(如 MySQL AES_ENCRYPT)或应用层加解密(openssl_encrypt),而脱敏函数返回的星号串是不可逆的——存进去就再也拿不回原值了。
脱敏和加密必须分清,混用会出生产事故
很多同学看到“敏感数据要处理”,第一反应是写个 maskIdCard() 然后存进数据库,结果导出报表全是 110101******1234,业务方投诉查不到真实身份证号。这不是脱敏错了,是用错了地方。
- 脱敏函数(如
substr_replace($id, '****', 6, 8))输出的是**不可逆字符串**,只供显示,不能反查、不能校验、不能做索引 - 加密(如
openssl_encrypt($id, 'AES-256-CBC', $key, 0, $iv))输出的是**二进制密文**,需配套密钥和 IV 才能解密,适合落库 - 数据库里存脱敏串 = 主动丢数据,等于把身份证号字段改成 VARCHAR(18) 并默认填
******** - 日志里打脱敏后的值没问题,但若打加密后的密文,日志系统没解密能力,等于白记
手机号/身份证号脱敏必须先清洗再切片
直接对原始输入调 substr() 是高危操作。用户提交的手机号可能是 "138-1234-5678"、"+8613812345678" 或带中文空格,身份证可能末位是小写 x,这些都会让切片错位或截出乱码。
- 手机号先清洗:
$clean = preg_replace('/\D/', '', $phone),再判长度:if (strlen($clean) !== 11),否则跳过脱敏 - 身份证统一转大写:
$id = strtoupper($id),再用preg_match('/^\d{17}[\dX]$/', $id)校验格式 - 18 位证用
substr_replace($id, '****', 6, 8),15 位老证用substr_replace($id, '****', 6, 6),别硬写8 - 姓名脱敏必须用
mb_substr($name, 0, 1, 'UTF-8') . '**',substr()按字节切中文必乱码
json_encode() 前没脱敏 = 白干
常见现场:控制器里对 $user['phone'] 调了 mask_phone(),但最后写的是 echo json_encode($user)——而 $user 数组里还有未处理的 $user['id_card']、$user['email'],JSON 一吐全暴露。
- 脱敏必须作用于**最终输出的数组副本**,不是改原始模型属性就完事
- Laravel 中别依赖
toArray()默认行为,要在jsonSerialize()或自定义 DTO 的toArray()方法里显式调用脱敏函数 - ThinkPHP 模型的
$hidden只在toJson()生效,json_encode($model)会绕过,必须用$model->toJson() - 导出 Excel 时,
PhpSpreadsheet::setCellValue()的参数必须是已脱敏值,不是“等写完再套样式”
****,而是厘清「谁决定这个字段要不要脱敏」「同一字段在不同接口是否规则不同」「脱敏后还能不能参与搜索或统计」。这些逻辑一旦散落在 foreach 和控制器里,下次加个「审计员可见全号」需求,就得 grep 全项目改二十个地方。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











