如何在PHP中验证电子邮件地址

我有这个功能来验证一个电子邮件地址:

function validateEMAIL($EMAIL) {
$v = "/[a-zA-Z0-9_-.+]+@[a-zA-Z0-9-]+.[a-zA-Z]+/";


return (bool)preg_match($v, $EMAIL);
}

这样可以检查电子邮件地址是否有效吗?

374809 次浏览

检查电子邮件地址是否格式良好的最简单和最安全的方法是使用filter_var()函数:

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
// invalid emailaddress
}

此外,你可以检查域是否定义了MX记录:

if (!checkdnsrr($domain, 'MX')) {
// domain is not valid
}

但这仍然不能保证邮件存在。唯一的办法就是发送确认邮件。


现在你已经有了简单的答案,如果你想学习,可以继续阅读关于电子邮件地址验证的内容,或者只是使用快速答案并继续前进。别见怪不怪。

尝试使用正则表达式验证电子邮件地址是“不可能的”;的任务。我想说的是,你所做的正则表达式是无用的。关于电子邮件地址有三个rfc,编写一个正则表达式来捕获错误的电子邮件地址,同时避免误报,这是没有人能做到的。检查这个列表以获得PHP filter_var()函数使用的正则表达式的测试(失败和成功)。

即使是内置的PHP函数,电子邮件客户端或服务器也没有做到这一点。在大多数情况下,filter_var仍然是最好的选择。

如果你想知道PHP(目前)使用哪种正则表达式模式来验证电子邮件地址,请参阅PHP源代码

如果你想了解更多关于电子邮件地址的信息,我建议你开始阅读说明书,但我必须警告你,无论如何,这都不是一个简单的阅读:

我认为你最好使用PHP内置的过滤器 -在这种特殊情况下:

当提供FILTER_VALIDATE_EMAIL参数时,它可以返回true或false。

你可以使用使用filter_var

<?php
function validateEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL);
}
?>

在关于电子邮件验证https://stackoverflow.com/a/41129750/1848217的“顶级问题”中回答了这个问题

对我来说,查看邮件的正确方法是:

  1. 检查符号@是否存在,在它之前和之后有一些非-@符号:/^[^@]+@[^@]+$/
  2. 试着向这个地址发送一封带有“激活码”的电子邮件。
  3. 当用户“激活”他的电子邮件地址时,我们将看到一切都是正确的。
当然,当用户使用时,你可以在前端显示一些警告或提示 输入“奇怪”的电子邮件来帮助他避免常见的错误,比如没有 域名部分的点或名称中没有引号的空格等等。但

.你必须接受地址“hello@world”如果用户确实需要它 此外,你必须记住,电子邮件地址的标准是过去和现在 因此您不能只键入一次“标准有效”的regexp 永远如此。你必须记住一些具体的互联网 服务器可能会在一些公共标准的细节上失败,但实际上可以正常工作 自己的“修改标准”。

所以,只要检查@,提示用户在前端和发送验证电子邮件在给定的地址。

如果你只是在寻找一个允许各种点、下划线和破折号的实际正则表达式,它如下所示:[a-zA-z0-9.-]+\@[a-zA-z0-9.-]+.[a-zA-Z]+。这将允许像tom_anderson.1-neo@my-mail_matrix.com这样看起来相当愚蠢的电子邮件被验证。

根据我的经验,regex解决方案有太多的假阳性和filter_var()解决方案有假阴性(特别是所有更新的顶级域名)。

相反,最好确保地址包含电子邮件地址的所有必需部分(user, "@"符号和域),然后验证域本身是否存在。

无法确定(服务器端)外部域是否存在电子邮件用户。

这是我在Utility类中创建的一个方法:

public static function validateEmail(string $email): bool {


// SET INITIAL RETURN VARIABLE
// ENSURE -> EMAIL ISN'T EMPTY | AN @ SYMBOL IS PRESENT


$emailIsValid = FALSE;


if (
!empty($email) &&
strpos($email, '@') !== FALSE
) {


// GET EMAIL PARTS


$email  = explode('@', $email);
$user   = $email[0];
$domain = $email[1];


// VALIDATE EMAIL ADDRESS


if (
count($email) === 2 &&
!empty($user) &&
!empty($domain) &&
checkdnsrr($domain)
) {
$emailIsValid = TRUE;
}
}


// RETURN RESULT


return $emailIsValid;
}

这不仅可以验证你的邮件,还可以过滤掉意想不到的字符:

$email  = $_POST['email'];
$emailB = filter_var($email, FILTER_SANITIZE_EMAIL);


if (filter_var($emailB, FILTER_VALIDATE_EMAIL) === false ||
$emailB != $email
) {
echo "This email adress isn't valid!";
exit(0);
}
/(?![[:alnum:]]|@|-|_|\.)./

现在,如果你使用带有type=email的HTML5表单,那么你已经有80%的安全性了,因为浏览器引擎有自己的验证器。为了补充它,将这个正则表达式添加到preg_match_all()并对其求反:

if (!preg_match_all("/(?![[:alnum:]]|@|-|_|\.)./",$email)) { .. }
< p > 找到HTML5表单使用的正则表达式进行验证 < br > https://regex101.com/r/mPEKmy/1 < / p >

如果你想检查提供的域名从电子邮件地址是否有效,可以使用如下方法:

/*
* Check for valid MX record for given email domain
*/
if(!function_exists('check_email_domain')){
function check_email_domain($email) {
//Get host name from email and check if it is valid
$email_host = explode("@", $email);
//Add a dot to the end of the host name to make a fully qualified domain name and get last array element because an escaped @ is allowed in the local part (RFC 5322)
$host = end($email_host) . ".";
//Convert to ascii (http://us.php.net/manual/en/function.idn-to-ascii.php)
return checkdnsrr(idn_to_ascii($host), "MX"); //(bool)
}
}

这是过滤大量无效电子邮件地址以及标准电子邮件验证的方便方法,因为有效的电子邮件格式并不意味着有效的电子邮件

注意,idn_to_ascii()(或它的姐妹函数idn_to_utf8())函数也许不是在你的PHP安装中可用,它需要扩展PECL intl >= 1.0.2和PECL idn >= 0.1。

还要记住,IPv4或IPv6作为电子邮件中的域部分(例如user@[IPv6:2001:db8::1])不能被验证,只有命名主机可以。

参见更多在这里

看完这里的答案后,我得出了以下结论:

public static function isValidEmail(string $email) : bool
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return false;
}


//Get host name from email and check if it is valid
$email_host = array_slice(explode("@", $email), -1)[0];


// Check if valid IP (v4 or v6). If it is we can't do a DNS lookup
if (!filter_var($email_host,FILTER_VALIDATE_IP, [
'flags' => FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE,
])) {
//Add a dot to the end of the host name to make a fully qualified domain name
// and get last array element because an escaped @ is allowed in the local part (RFC 5322)
// Then convert to ascii (http://us.php.net/manual/en/function.idn-to-ascii.php)
$email_host = idn_to_ascii($email_host.'.');


//Check for MX pointers in DNS (if there are no MX pointers the domain cannot receive emails)
if (!checkdnsrr($email_host, "MX")) {
return false;
}
}


return true;
}

使用以下代码:

// Variable to check
$email = "john.doe@example.com";


// Remove all illegal characters from email
$email = filter_var($email, FILTER_SANITIZE_EMAIL);




// Validate e-mail
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo("Email is a valid email address");
}

FILTER_VALIDATE_EMAIL中有一个更好的正则表达式,但任何正则表达式都可能给出糟糕的结果。

例如. .

// "not an email" is invalid so its false.
php > var_export(filter_var("not an email", FILTER_VALIDATE_EMAIL));
false
// "foo@a.com" looks like an email, so it passes even though its not real.
php > var_export(filter_var("foo@a.com", FILTER_VALIDATE_EMAIL));
'foo@a.com'
// "foo@gmail.com" passes, gmail is a valid email server,
//  but gmail require more than 3 letters for the address.
var_export(filter_var("foo@gmail.com", FILTER_VALIDATE_EMAIL));
'foo@gmail.com'

你可能想要考虑使用像真正的电子邮件这样的API,它可以进行深入的邮箱检查,以检查电子邮件是否真实。

有点像…

$email = "foo@bar.com";
$api_key = ???;


$request_context = stream_context_create(array(
'http' => array(
'header'  => "Authorization: Bearer " . $api_key
)
));


$result_json = file_get_contents("https://isitarealemail.com/api/email/validate?email=" . $email, false, $request_context);


if (json_decode($result_json, true)['status'] == "valid") {
echo("email is valid");
} else if (json_decode($result_json, true)['status'] == "invalid") {
echo("email is invalid");
} else {
echo("email was unknown");
}

有三个rfc奠定了“互联网消息格式”的基础。

  1. RFC 822
  2. RFC 2822(取代RFC 822)
  3. RFC 5322(取代RFC 2822)

然而,RFC 5322以最专业的方式定义了电子邮件id及其命名结构。这更适合于为一个互联网标准奠定基础,这个标准足够自由,可以允许所有的用例,也足够保守,可以用某种形式主义来约束它。

然而,来自软件开发人员社区的电子邮件验证需求,有以下需求——

  • 避免不必要的垃圾邮件发送者
  • 确保用户不会因疏忽而出错
  • 以确保电子邮件ID属于实际输入它的人

他们对实现一个技术上全面的定义不感兴趣,这个定义允许电子邮件id的所有形式(IP地址,包括端口号和所有形式)。适合他们用例的解决方案应该仅仅确保所有合法的电子邮件持有者都能够通过。“合法”的定义;从技术立场(RFC 5322方式)到可用性立场(此解决方案)有很大的不同。验证的可用性方面旨在确保验证机制验证的所有电子邮件id都属于实际用户,并将其用于通信目的。因此,这为验证过程引入了另一个角度,确保了实际“使用中”;e-mail ID, RFC-5322的定义显然不足以满足这一要求。

因此,在实际的基础上,实际的要求归结为这一点

  1. 以确保一些非常基本的验证检查
  2. 确保输入的电子邮件正在使用

第二个需求通常包括向输入的电子邮件ID发送标准响应,并根据响应机制中描述的操作对用户进行身份验证。这是用于确保验证“正在使用”的第二个要求的最广泛使用的机制。电子邮件ID。这确实涉及到从后端服务器实现的往返,并且不是一个直接的单屏幕实现,但是,我们不能放弃这一点。

第一个需求,源于开发者不希望完全“非电子邮件式”的需求。作为电子邮件传递的字符串。这通常包括空格,没有"@"签或不签域名。对于域名的punycode表示,如果需要启用域验证,则需要进行完整的实现,以确保域名有效。因此,鉴于这方面要求的基本性质,验证“;<某事>@<某事>。<某事>& gt;”是满足要求的唯一恰当的方法。

一个典型的正则表达式可以满足这个要求: ^ ^ @ \ [s] + @ ^ @ \ [s] + [^ @ \ s]。+ $ 上面的正则表达式遵循大多数编程语言都广泛遵循的标准Perl正则表达式标准。验证语句是: 除了空格和“@"除了空格和"@"符号>.<除空格,@符号和点>

对于那些想要更深入地了解更相关的实现的人,他们可以遵循以下验证方法。 电子邮件本地部分>@<域名>

为<电子邮件本地部分>-遵循“普遍接受指导小组”的指导方针;- UASG-026 . 对于域名,您可以使用标准库遵循任何域验证方法,这取决于您的编程语言。有关该主题的最新研究,请参阅文档uasg - 018 a.

.

.

.

那些有兴趣了解在实施国际化电子邮件解决方案时可能遇到的整体流程、挑战和问题的人,也可以通过以下rfc:

RFC 6530(国际化电子邮件概述和框架) RFC 6531(国际化电子邮件的SMTP扩展名) RFC 6532(国际化邮件头) RFC 6533(国际化交付状态和处置通知) RFC 6855 (IMAP支持UTF-8) RFC 6856(邮局协议版本3 (POP3)支持UTF-8) RFC 6857(国际化电子邮件消息的发送后消息降级) RFC 6858(简化POP和IMAP降级的国际化电子邮件)

我已经创建了Python &PHP实现 正确验证任何电子邮件地址,即 邮件服务器确认是真的

在GPL-3.0许可下发布。

就是这样:

https://lja.fi/index.php/github-stuff/

——lja

我准备了一个检查电子邮件有效性的函数:

function isValidEmail($email)
{
$re = '/([\w\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)/m';
preg_match_all($re, $email, $matches, PREG_SET_ORDER, 0);
if(count($matches) > 0) return $matches[0][0] === $email;
return false;
}

FILTER_VALIDATE_EMAIL的问题是,它甚至认为无效的电子邮件是有效的。

以下是例子:

if(isValidEmail("foo@gmail.com")) echo "valid";
if(!isValidEmail("fo^o@gmail.com")) echo "invalid";