脱敏必须在json输出前完成字段级处理:手机号需清洗、校验后再切片;身份证要分15/18位并保留末位x大小写;姓名须用mb_substr防乱码,复姓特殊处理;所有脱敏操作必须作用于最终输出数组,覆盖接口、日志、导出全链路。

直接在 JSON 输出前做字段级替换,别等前端或日志里再处理——否则等于没脱敏。
手机号脱敏必须先清洗再切片
拿到 $phone 不能直接 substr_replace($phone, '****', 3, 4),因为实际数据可能是 "138-1234-5678"、" 13812345678",甚至 null 或空字符串。
- 清洗:用
preg_replace('/\D/', '', $phone)去掉所有非数字字符 - 校验:清洗后检查
strlen($clean) === 11且匹配/^1[3-9]\d{9}$/ - 替换:通过则
substr_replace($clean, '****', 3, 4);否则返回原值或null(按业务定) - 别混固话:像
"010-12345678"要单独分支,不能塞进同一逻辑
身份证号得区分 15 位和 18 位,末位 X 大小写不能动
硬写 substr($id, 0, 6) . '******' . substr($id, -4) 在 "11010119900307271x" 上会把小写 x 截出来,下游系统比对失败;15 位老证这么切还会错位。
- 粗筛:用
preg_match('/^\d{17}[\dXx]$/', $id)或strlen($id) === 15 - 保留末位:直接
substr($id, -4)拿最后 4 字符(含原始大小写X/x) - 分情况替换:
- 18 位:
substr_replace($id, '******', 6, 8) - 15 位:
substr_replace($id, '******', 6, 6)(掩中间 6 位,保前 6 + 后 3)
- 18 位:
- 不匹配的字符串(如含字母、长度异常)跳过脱敏,不强行替换
姓名脱敏要用 mb_substr,别用 substr
中文姓名字数不定:"张三"(2 字)、"欧阳修"(3 字)、"司马相如"(4 字),且 UTF-8 下每个汉字占 3 字节。substr() 按字节切会乱码,mb_substr() 才安全。
- 取首字:用
mb_substr($name, 0, 1, 'UTF-8') - 拼掩码:
mb_substr($name, 0, 1, 'UTF-8') . '**' - 复姓要额外判断:比如前两个字符是
"诸葛"或"司马",就得取前 2 字再加**,不能只看长度 - 别依赖固定截取,更别用
str_replace()全局替换“所有汉字”
json_encode() 前必须完成脱敏,且作用于最终输出副本
很多接口看着写了脱敏,但 echo json_encode($data) 一执行,敏感字段又全暴露了——因为脱敏只改了中间变量,没改最终要序列化的那个数组。
- 脱敏操作必须在
json_encode()调用之前,且明确作用于你要echo的那个数组 - 避免“改一半”:比如只处理
$user['phone']却漏了$user['id_card'],JSON 里一个星号一个原文 - 用 Laravel/Eloquent 时,别信
toArray()默认行为;应在toArray()或jsonSerialize()方法里显式调用脱敏函数 - 日志同理:
error_log()或 Monolog 记录前也得脱敏,不然白做
最易被忽略的是导出和日志场景——它们和接口响应一样,都是敏感数据流出的关键出口,但往往没被纳入统一脱敏链路。一旦漏掉,就等于在防火墙上凿了个洞。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











