推荐使用正则/^1[3-9]\d{9}$/验证中国大陆手机号,它覆盖13x~19x合法号段,排除非法开头和非手机号的11位数字,且必须加^和$锚定,配合trim或str_replace清理空格后校验长度是否为11。

PHP中用preg_match验证中国大陆手机号是否合规
直接用正则判断是最常用也最可控的方式,但必须注意:不能只看是否11位数字,得匹配号段规则。2024年起,虚拟运营商号段(如170/171)、物联网卡(14号段部分)、以及新开放的19x号段都要纳入。
推荐正则:/^1[3-9]\d{9}$/ —— 它覆盖了13x~19x全部合法号段,排除了10、11、12开头的非法号段,也过滤掉纯数字但非手机号的11位数(如11111111111)。
-
preg_match('/^1[3-9]\d{9}$/', $phone)返回1才表示匹配成功,返回0或false都算不通过 - 务必加行首
^和行尾$,否则"abc13812345678def"也会被误判为合法 - 别用
\d+或[0-9]{11}这种宽松写法,它们会放过10012345678这类明显错误的号码
为什么filter_var($phone, FILTER_SANITIZE_NUMBER_INT)不能代替正则校验
这个函数只是“清理”,不是“验证”。它会把"138-1234-5678"变成"13812345678",但同样也会把"138abcd5678"变成"1385678"——长度只剩8位,却没报错。更危险的是,它对"+86 138 1234 5678"也会输出"8613812345678",结果变成14位数字,后续正则直接失败。
- 它适合做预处理(比如统一去除非数字字符),但绝不能跳过正则校验
- 如果先
FILTER_SANITIZE_NUMBER_INT再正则,记得检查清洗后字符串长度是否为11 - 别依赖
FILTER_VALIDATE_INT——手机号不是整数,超出了PHP整型范围(尤其19x号段),且会把带前导0的字符串判为无效
表单提交时如何避免空值、空格、全角字符干扰
用户可能输入" 138 1234 5678 "(含全角空格)或" 13812345678 "(前后半角空格),trim()只能处理半角,对全角空格无效。
立即学习“PHP免费学习笔记(深入)”;
- 先用
mb_trim($phone, ' ' . " \t\n\r\0\x0B")(需自定义mb_trim支持全角空格)或简单粗暴:str_replace([' ', ' ', "\t", "\n", "\r"], '', $phone) - 再检查
strlen($phone) !== 11,长度不对立刻拒绝,省得进正则白跑一趟 - 如果前端已用
type="tel",仍要服务端校验——浏览器不强制格式,iOS甚至允许输入字母
遇到Warning: preg_match(): Compilation failed怎么办
这通常是因为正则里混入了未转义的斜杠、点号或括号,尤其是从数据库或配置里动态拼接正则时容易出错。
- 确认正则字符串是用单引号包裹的,比如
'/^1[3-9]\d{9}$/',避免双引号内\d被PHP当转义序列解析 - 如果正则来自变量,用
preg_quote($pattern, '/')转义分隔符(但本例不需要,因为模式固定) - 调试时可先
var_dump($phone),确认输入值没有不可见控制字符(如\u200b零宽空格),这类字符会让strlen和mb_strlen结果不一致,导致正则看似匹配失败











