PHP中用preg_replace隐藏手机号中间四位最稳妥的方式是使用带捕获组的正则/(1[3-9]\d{3})\d{4}(\d{4})/匹配11位手机号并替换为'$1****$2',需先清理非数字字符、校验长度与号段,并添加字边界\b或断言防止误匹配。

PHP 中用 preg_replace 隐藏手机号中间四位
直接用 preg_replace 匹配 11 位手机号并替换中间段最稳妥,别用 str_replace 或切片——手机号可能带空格、括号或连字符,硬切会出错。
常见错误是写成 /1[3-9]\d{9}/,漏掉 14、17、19 等号段,或没加边界锚点导致匹配到长数字串里的一段(比如身份证号里的连续 11 位)。
- 推荐正则:
/1[3-9]\d{9}\b/(\b防止误匹配) - 替换模式用
'$1****$3',配合捕获组更安全 - 完整写法:
preg_replace('/(1[3-9]\d{3})\d{4}(\d{4})/', '$1****$2', $text)
处理带分隔符的手机号(空格、横线、括号)
用户输入常是 138-1234-5678、(010) 1234 5678 或 138 1234 5678,直接删掉非数字再处理更可靠,比写一堆分支正则简单。
- 先统一清理:
$clean = preg_replace('/\D/', '', $phone) - 再判断长度是否为 11:
if (strlen($clean) === 11 && preg_match('/^1[3-9]/', $clean)) - 最后替换:
substr($clean, 0, 3) . '****' . substr($clean, 7)
批量替换文本中所有手机号时要注意什么
preg_replace 默认全局替换,但容易把「1381234567890」(13 位)也当手机号误杀。必须加字边界或前后断言。
立即学习“PHP免费学习笔记(深入)”;
- 安全写法:
/(?(负向先行/后行断言) - 如果文本含邮箱(如
user@13812345678.com),不加断言就会把邮箱里的数字串也脱敏 - 性能提示:正则越短越快,
[3-9]比[3-9]|4|7|9效率高,别画蛇添足
为什么不用 mb_substr 处理中文混合文本
手机号本身是 ASCII,但所在文本可能是 UTF-8 中文。substr 在 UTF-8 下按字节截取不会出问题,因为手机号数字不涉及多字节字符;用 mb_substr 反而增加开销,且没实际收益。
- 只要确保输入是 UTF-8 编码(PHP 7.4+ 默认),
substr安全可用 - 唯一例外:如果原始字符串用了 GBK 编码,得先
iconv('GBK', 'UTF-8', $text)再处理 - 别在正则里加
u修饰符——它只影响 Unicode 字符类,对纯数字无用
(? 和 <code>(?!\d)。脱敏不是越狠越好,而是刚好命中、不多不少。



















