如何在PHP中验证电子邮件?

130

我该如何使用php5验证输入值是否为有效的电子邮件地址?现在我正在使用以下代码

function isValidEmail($email){ 
     $pattern = "^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$"; 

     if (eregi($pattern, $email)){ 
        return true; 
     } 
     else { 
        return false; 
     }    
} 

但它显示已过时错误。我该如何解决这个问题,请帮助我。


3
已经提供了正确答案,但是关于已弃用的问题:使用POSIX正则表达式(eregi是其函数之一)已被弃用。请改用PCRE - Felix Kling
3
顺便说一下,你的正则表达式完全错误。你的函数会把一些完全有效的电子邮件地址标记为无效。用正则表达式过滤电子邮件地址是一场噩梦。 - Artefact2
你应该使用RFC 822标准,这里有一篇好文章在PHP中解析电子邮件地址,可以帮助你理解。 - kta
避免使用regexfilter_var()来验证电子邮件。请参考此答案:https://dev59.com/v2ct5IYBdhLWcg3wh9xK#42037557 - Jabari
8个回答

292
你可以使用filter_var()函数,它提供了许多方便的验证和净化选项。
filter_var($email, FILTER_VALIDATE_EMAIL)

如果您不想更改依赖于函数的代码,只需执行以下操作:

function isValidEmail($email){ 
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

注意: 对于其他需要使用正则表达式的情况,已弃用的ereg函数族(POSIX正则表达式函数)应该被替换为preg函数族(PCRE正则表达式函数)。有一些小差异,阅读手册就足够了。
更新1: 如@binaryLV所指出的:
PHP 5.3.3和5.2.14存在一个与FILTER_VALIDATE_EMAIL相关的bug,当验证大量值时会导致段错误。这个问题的简单和安全的解决方法是在filter_var()之前使用strlen()。我不确定5.3.4 final版本是否有影响,但写道某些5.3.4快照版本也受到影响。
这个bug已经被修复。

更新2: 当然,此方法将验证bazmega@kapa作为有效的电子邮件地址,因为实际上它是一个有效的电子邮件地址。但在互联网上大多数情况下,您也希望电子邮件地址具有TLD:bazmega@kapa.com。正如博客文章(由@Istiaque Ahmed发布的链接)所建议的那样,您可以使用正则表达式增强filter_var(),以检查域部分中是否存在一个点(尽管不检查一个有效的TLD):

function isValidEmail($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) 
        && preg_match('/@.+\./', $email);
}

正如@Eliseo Ocampos所指出的那样,这个问题只存在于PHP 5.3之前的版本中,在那个版本中他们改变了正则表达式,现在它会进行检查,因此您不必担心。


4
说到这里,你可能需要提及这仅适用于PHP 5.2.x及以上版本。 :-) - John Parker
5
由于eregi方法已过时,OP收到了一个过时信息,这表明他正在使用PHP 5.3。但是,重要的是要提到这一点(对于其他人来说)。 - Felix Kling
8
PHP 5.3.3和5.2.14存在一个与FILTER_VALIDATE_EMAIL相关的错误(http://bugs.php.net/52929),当验证大量数据时会导致段错误。解决方法是在使用`filter_val()`之前先使用`strlen()`进行长度检查,这是一个简单而安全的解决办法。我不确定5.3.4 final版本是否有此问题,但据报道一些5.3.4快照版本也受到了影响。 - binaryLV
3
@kapa,实际上你不需要再检查域名部分是否有句点。请参考http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c?r1=297250&r2=297350&pathrev=303779。 - Eliseo Ocampos
1
重要通知 - 在最近的更新中,您稍微更改了逻辑,因为您删除了“!== false”。 - Tomer Gal
显示剩余16条评论

9

7

虽然这是一篇旧文章,但我想分享我的解决方案,因为之前没有人提到这个问题。

新的电子邮件地址可以包含UTF-8字符或特殊域名,如.live.news等。

我还发现有些电子邮件地址可能是用西里尔字母编写的,在所有情况下,标准正则表达式或filter_var()都会失败。

这就是我为此制定的解决方案:

function valid_email($email) 
{
    if(is_array($email) || is_numeric($email) || is_bool($email) || is_float($email) || is_file($email) || is_dir($email) || is_int($email))
        return false;
    else
    {
        $email=trim(strtolower($email));
        if(filter_var($email, FILTER_VALIDATE_EMAIL)!==false) return $email;
        else
        {
            $pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD';
            return (preg_match($pattern, $email) === 1) ? $email : false;
        }
    }
}

此功能可完美处理所有情况和电子邮件格式。

3
我总是使用这个:
function validEmail($email){
    // First, we check that there's one @ symbol, and that the lengths are right
    if (!preg_match("/^[^@]{1,64}@[^@]{1,255}$/", $email)) {
        // Email invalid because wrong number of characters in one section, or wrong number of @ symbols.
        return false;
    }
    // Split it into sections to make life easier
    $email_array = explode("@", $email);
    $local_array = explode(".", $email_array[0]);
    for ($i = 0; $i < sizeof($local_array); $i++) {
        if (!preg_match("/^(([A-Za-z0-9!#$%&'*+\/=?^_`{|}~-][A-Za-z0-9!#$%&'*+\/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$/", $local_array[$i])) {
            return false;
        }
    }
    if (!preg_match("/^\[?[0-9\.]+\]?$/", $email_array[1])) { // Check if domain is IP. If not, it should be valid domain name
        $domain_array = explode(".", $email_array[1]);
        if (sizeof($domain_array) < 2) {
            return false; // Not enough parts to domain
        }
        for ($i = 0; $i < sizeof($domain_array); $i++) {
            if (!preg_match("/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/", $domain_array[$i])) {
                return false;
            }
        }
    }

    return true;
}

1
@unbreak 我尝试了你的代码,发现如果将电子邮件地址传递为 alex@.,则它总是返回 true,而这不是一个有效的电子邮件地址。 - Subhajit

2

用户数据对于好的开发者来说非常重要,因此不要一遍又一遍地询问相同的数据,使用一些逻辑来纠正数据中的一些基本错误。

在验证电子邮件之前:首先您需要从电子邮件中删除所有非法字符。

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

然后,使用这个filter_var()函数验证您的电子邮件地址。

filter_var($email, FILTER_VALIDATE_EMAIL)) // To Validate the email

例如。
<?php
$email = "john.doe@example.com";

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

// Validate email
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
    echo $email." is a valid email address";
} else {
    echo $email." is not a valid email address";
}
?>

1

0

请注意,地址为 iasd@x.z-----com 是无效的,但是 filter_var() 函数返回 true,许多其他字符串(电子邮件)也是无效的,但使用 filter_var() 函数却返回 true。

为了验证电子邮件,我使用以下函数:

function correcorre($s){// correo correcto
    $x = '^([[:alnum:]](_|-|\.)*)*[[:alnum:]]+@([[:alnum:]]+(-|\.)+)*[[:alnum:]]+\.[[:alnum:]]+$';
    preg_match("!$x!i", $s, $M);
    if(!empty($M[0]))return($M[0]);
    }

请改进并分享,谢谢。

0
虽然我有点晚了,但这可能对仍然想要查看更多的人有所帮助。
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  // invalid email address
}

这将仅验证电子邮件格式是否正确。但如果你想使用更多功能,比如检查该电子邮件地址是否真实存在,你可以使用免费的 API。

以下是我目前在我的网站上使用的代码。

    if(isEmialExist("EMAIL_ADDRESS_THAT"))
{
    echo "email exists, real email";
}
else
{
    echo "email doesn't exist";
}


function isEmialExist($emailAddress)
{
    if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
     return false; //invalid format
    }
    //now check if email really exist
    $postdata = http_build_query(array('api_key' => 'YOUR_API_KEY', 'email' => $emailAddress ));
    $url = "https://email-validator.com/api/v1.0/json";
    $opts = array('http' => array( 'method'  => 'POST', 'header'  => 'Content-Type: application/x-www-form-urlencoded', 'content' => $postdata ));
    
    $context  = stream_context_create($opts);
    $result = file_get_contents($url, false, $context);
    $data = json_decode($result, false);
    return $data->is_exists;
}

你可以在这里找到更多详细信息。 https://email-validator.com/tutorial 这个API的优点是,它提供实时结果,并且您将获得10,000个免费积分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接