preg_match非英文邮箱地址验证(国际域名)

preg_match verification of non English email addresses (international domain names)

我们都知道电子邮件地址验证是一个敏感的话题,关于在不对整个 RFC 进行编码的情况下处理它的最佳方式有很多意见。但自 2009 年以来,它变得更加困难,而且我还没有真正看到有人解决 IDN 的问题。

这是我一直在使用的:

preg_match(/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,6}\z/i)

哪个适用于大多数电子邮件地址,但如果我需要匹配非拉丁电子邮件地址怎么办?例如:bob@china.中国,或 bob@russia.рф

查看 here 以获取完整列表。 (注意列表底部的所有非拉丁域扩展。)

可以找到关于这个主题的信息here,我想他们的意思是这些新字符在机器级别,但我不是 100% 确定。

如果是,这是否意味着我需要考虑在我的代码中进行以下更改? (对于 .travelersinsurance 和 .sandvikcoromant 等域扩展)

preg_match(/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,20}\z/i)

注意:这与本页的讨论无关 Using a regular expression to validate an email address

我会坚持你应该向他们发送一封验证电子邮件的可靠建议。不需要需要一次又一次更新的花哨的正则表达式。假设他们知道自己的电子邮件地址并让他们输入。

当这种情况出现时,我一直都是这么做的。如果有的话,我会让他们输入他们的电子邮件两次。它会让您有更多时间花在 site/project.

的重要部分上

这是我最终想到的。

preg_match(/^[\pL\pM*+\pN._%+-]+@[\pL\pM*+\pN.-]+\.[\pL\pM*+]{2,20}\z/u)

这使用 Unicode 正则表达式,如 \pL\pM*+\pN 帮助我处理来自任何语言的字符和数字。

\pL 任何语言的任何种类的字母,大写或小写。

\pM*+ 匹配零个或多个组合标记的代码点。旨在与另一个字符组合的字符(例如重音符号、变音符号、封闭框等)。

\pN任意数。

上面的表达式对于像 me@mydomain.com 这样的普通电子邮件地址和像 a.s中3_yÄhমহাজোটেরoo文%网+d-fελληνικì@πyÄhooαράδειγμα这样的杂音电子邮件地址非常有效。 δοκιμή.

并不是我不相信人们能够输入他们自己的电子邮件地址,但人们确实会犯错误,我可能会在其他情况下使用此代码。例如:我需要仔细检查包含 10,000 个电子邮件地址的现有列表的完整性。此外,我总是被教导不要相信用户输入并始终过滤。

更新

我刚刚发现,虽然这在像 phpliveregex.com 这样的网站上进行测试时以及在本地解析 utf-8 内容的普通字符串时效果很好,但它不适用于电子邮件字段,因为浏览器会转换该字段内容类型为普通拉丁语。所以像 bob@china.China 或 bob@russia.рф 这样的电子邮件地址在被服务器接收之前确实会被转换为 bob@china.xn--fiqz9s 或 bob@russia.xn--p1ai。我的原始过滤器中唯一真正缺少的是包含域扩展中的连字符。

这是最终版本:

preg_match('/^[a-z0-9%+-._]+@[a-z0-9-.]+\.[a-z0-9-]{2,20}\z/i');

考虑:每次您编写自己的新正则表达式 而不根据完整的 RFC 规范 验证地址时,您只是在制造使用 "exotic" 的情况网络上的电子邮件地址更糟。您正在发明官方 RFC 规范的一些新的临时子集或超集;这意味着您要么有误报,要么有误报,或者两者都有,您将拒绝人们使用他们的实际地址,因为您的正则表达式没有正确说明它们,或者您将接受实际上无效的地址。

此外,即使地址在句法上有效,也并不意味着 a) 地址实际(仍然)存在,b) 属于该用户或 c) 实际上可以接收电子邮件。在赠款方案中,验证语法是一个非常次要的问题。

如果你要验证语法,要么做一个非常粗略的一般检查,确保不会拒绝任何有效地址(例如/.+@.+/ ), 根据所有RFC规则进行验证;不要做一些半途而废的那种你刚刚想出的严格但不是真正的验证。