问题描述
我正在使用 is_email()
来检查 user-provided 电子邮件地址是否有效。例如:
$email = $_POST['email'];
if ( is_email( $email ) )
// Do something.
据我所知,此功能中的任何内容都不会将信息写入数据库。在将 $email
传递给函数之前,是否应该进行消毒?
最佳解决方案
看看在 trac 上的 is_email()
功能,看起来你不需要圣诞节,因为它只是字符串测试。我甚至会说,如果这个函数返回 true,那么在将数据发送到数据库之前不需要对它进行清理。
次佳解决方案
WordPress 和 PHP 内核
is_email()
功能 Source 是一种典型的 WordPress 实现,不能与 RFC 6531 允许的功能完全相同。一个原因可能是,filter_var()
的默认 PHP FILTER_VALIDATE_EMAIL
常数在根据 The Internet Engineering Task Force (IETF®)指南验证某些内容方面没有太大的好转。
Standards
要点是 RFC 6531 允许 「Unicode 字符超出 ASCII 范围」 。那就是 (对于 @
之前的本地部分):
- Uppercase and lowercase English letters (a–z, A–Z) (ASCII: 65–90, 97–122)
- Digits
0
to9
(ASCII: 48–57)- These special characters:
! # $ % & ' * + - / = ? ^ _ ` { | } ~
- Character
.
(dot, period, full stop) (ASCII: 46) provided that it is not the first or last character, and provided also that it does not appear consecutively (e.g.John..Doe@example.com
is not allowed).- Special characters are allowed with restrictions. They are:
- Space and
"(),:;<>@[]
(ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91–93)- The restrictions for special characters are that they must only be used when contained between quotation marks, and that 2 of them (the backslash and quotation mark ” (ASCII: 92, 34)) must also be preceded by a backslash
(e.g.
"\"
and"""
).- Comments are allowed with parentheses at either end of the local part; e.g.
john.smith(comment)@example.com
and(comment)john.smith@example.com
are both equivalent to"john.smith@example.com"
, butjohn.(comment)smith@example.com
would be invalid.- International characters above
U+007F
, encoded as UTF-8, are permitted by RFC 6531, though mail systems may restrict which characters to use when assigning local parts.
对于全局/域名部分:
The domain name part of an email address has to conform to strict guidelines: it must match the requirements for a hostname, consisting of letters, digits, hyphens and dots. In addition, the domain part may be an IP address literal, surrounded by square braces, such as
jsmith@[192.168.2.1]
orjsmith@[IPv6:2001:db8::1]
[…]
什么是有效的?
这可能导致奇怪的,但有效的 e-mail 地址,如下所示:
localpart.ending.with.dot.@example.com
(comment)localpart@example.com
"this is v@lid!"@example.com
"much.more unusual"@example.com
postbox@com
admin@mailserver1
"()<>[]:,;\@"\\!#$%&'*+-/=?^_`{}| ~.a"@example.org
" "@example.org
Source: php.net /作者 gt@kani.hu – 这个帖子的作者固定的例子
Limits
还有当地& 域长限制:
The format of email addresses is
local-part@domain
where the local-part may be up to 64 characters long and the domain name may have a maximum of 253 characters – but the maximum of 256-character length of a forward or reverse path restricts the entire email address to be no more than 254 characters long.[2] The formal definitions are in RFC 5322 (sections 3.2.3 and 3.4.1) and RFC 5321 – with a more readable form given in the informational RFC 3696[3] and the associated errata.
资料来源:维基百科
WordPress 限制
这是 WordPress 检查的:
-
测试电子邮件的最小长度:
strlen( $email ) < 3
-
测试一个 @字符后的第一个位置:
strpos( $email, '@', 1 ) === false
-
测试无效字符:
!preg_match( '/^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$/', $local )
-
测试期间序列:
preg_match( '/.{2,}/', $domain )
-
测试领先和尾随时段和空白:
trim( $domain, " tnrx0B." ) !== $domain
-
假设域将至少有两个 subs:
$subs = explode( '.', $domain );
然后-
2 > count( $subs )
-
trim( $sub, " tnrx0B-" ) !== $sub
-
!preg_match('/^[a-z0-9-]+$/i', $sub )
-
资料来源:WP Core v4.0
过滤器自定义验证
所有上述情况都会触发 is_email()
返回 false 。结果是 filter-able(可以附加回调),过滤器将有三个参数,其中最后一个参数是原因。例:
return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
这意味着您可以覆盖特定检查返回的结果。
这允许您添加特殊检查,例如允许 Umlaut-domains,TLD-only 域名等。
Conclusion
WordPress 在大多数情况下是安全的,但是由于邮件服务器实际上必须符合 RFC 要求,因此更为严格。请记住,并不是每个邮件服务器都符合 RF 6531 指南。
Edit
有趣的一面:~/wp-includes/formatting
内有两个相关的功能:is_email()
和 sanitize_email()
。它们几乎是相同的功能。我不知道为什么有人决定将功能内容从一个复制到另一个是一个好主意,而不是将一个作为回调添加到另一个提供的过滤器。自从 v0.71 起 is_email()
和 v1.5 之后的 sanitize_email()
是一样的,我个人会使用后来的,因为你得到一个清理的字符串。请注意,is_email()
甚至声明它不符合 RFC 。
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。