preg_replace() 是清理 php 日志敏感信息的正确方式,需按语义编写精准正则(如ipv4、手机号、password=值等),配合 i/u 修饰符,避免误删结构信息;禁用 preg_match_all()+循环替换以防偏移错乱。
用 preg_replace() 清理 PHP 日志中的敏感信息
直接上手:日志里混着 IP、手机号、token、密码字段?别用 str_replace() 硬换,得靠 preg_replace() 做模式化擦除。核心是写对正则,再配好修饰符。
常见错误是写太宽泛的模式,比如 /\d+/ 一把梭——结果把时间戳、行号、HTTP 状态码全干掉了。得按字段语义匹配:
-
/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/匹配 IPv4(加\b防止匹配到 123.456.789.012 中的子串) -
/\b1[3-9]\d{9}\b/匹配大陆手机号(注意边界,避免误伤 138123456789 中的前 11 位) -
/password\s*=\s*["']?[^"'\s]+["']?/i匹配password=xxx或Password: 'abc123'类型
实际调用时务必加 i(忽略大小写)和 u(UTF-8 安全),尤其日志含中文路径或用户名时:
$clean_log = preg_replace([
'/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/',
'/\b1[3-9]\d{9}\b/',
'/(token|auth|key)\s*[:=]\s*["\']?[^"\'\s]{10,}["\']?/i',
], '[REDACTED]', $raw_log);
为什么不能用 preg_match_all() + 循环替换
有人先 preg_match_all() 找出所有匹配项,再逐个 str_replace() ——这会破坏日志结构。比如同一行有多个 IP:[2024-01-01] GET /api from 192.168.1.100 and 10.0.0.5,两次 str_replace() 可能因字符串偏移错位,第二次替换把 10.0.0.5 替成 [REDACTED].0.5。
立即学习“PHP免费学习笔记(深入)”;
preg_replace() 是原子操作,一次扫描、一次定位、一次替换,位置精准。性能也更好——不用反复遍历字符串。