优先用 filter_var($email, FILTER_VALIDATE_EMAIL),因其基于RFC 5322简化解析,能正确处理引号本地部分、Gmail别名、多级子域名等;自写正则易过松或过紧,常见错误包括忽略localhost、缺失锚点、误用\w等。

直接用 filter_var($email, FILTER_VALIDATE_EMAIL) 就行,别写正则——除非你明确知道它会漏掉什么、又会多拦住什么。
为什么优先用 filter_var 而不是自己写正则
PHP 内置的 FILTER_VALIDATE_EMAIL 基于 RFC 5322 的简化解析逻辑,能处理引号包裹的本地部分(如 "john..doe"@example.com)、带 + 号的 Gmail 别名(user+tag@example.com)、多级子域名(u@sub.dom.example.co.uk)等常见但正则容易误判的情况。自己写的正则要么太松(放过 ..@a.b),要么太紧(拒绝合法的 a@b.c.d.e)。
常见错误现象:
- 用
/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i验证时,test@localhost返回 false(其实合法) - 没加
^和$锚点,导致xxx@yyy.zzz@abc也能部分匹配通过 - 用
\w匹配本地部分,却忽略了%和+在某些邮箱中是允许的
如果非要用正则,选哪个模式最稳妥
真要手写正则,就用这个最小可行版本:/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/。它不追求 RFC 全覆盖,但能挡住绝大多数明显非法输入,且性能可控。
立即学习“PHP免费学习笔记(深入)”;
使用场景和注意事项:
- 仅用于前端 JS 同步校验或后端快速初筛,不能替代
filter_var -
{2,}比{2,6}更合理——.museum、.travel、.info都超过 6 字符 - 不要用
\w替代[a-zA-Z0-9_],因为\w在 Unicode 模式下可能匹配非 ASCII 字符,引发意外行为 - 必须配合
trim()使用,否则" user@example.com "会失败
filter_var 也得小心这几个坑
filter_var 不是银弹,它只做语法校验,不查 DNS、不发验证信、不处理国际化域名(IDN)。
容易被忽略的点:
- 传入含换行符的字符串(如用户粘贴时带
\r\n)会导致返回 false,务必先trim() - 对纯数字域名(如
123@456.789)返回 true——这在技术上符合 RFC,但业务上大概率要拦截 - 不支持中文域名(如
张三@例子.中国),需先用idn_to_ascii()转换再校验 - 不检查长度上限,
str_repeat('a', 300).'@b.c'也能过,建议额外加strlen($email)
真正难的不是“怎么写对”,而是“怎么定义什么叫对”:你要拦住的是拼写错误,还是恶意构造?要不要支持企业内网邮箱(user@server)?是否允许单字母顶级域(.a)?这些边界问题,比选函数或正则更关键。



















