23

我有一个类可以在将每个输入发送到数据库层之前对其进行验证。请注意,我的问题与逃避或任何事情无关。我的数据库层将处理 SQL 注入问题。我要做的就是验证电子邮件是否有效,因为稍后该电子邮件可能会被用作“发送至”。例如,用户将通过发送到电子邮件的链接恢复对其帐户的访问。我读了很多关于它的内容filter_var,有很多人反对它,而其他人则支持它。将重点放在“我只想验证电子邮件而不是针对数据库或 html 或 XSS 或其他任何内容进行过滤”,使用时有问题filter_var吗?

4

6 回答 6

25

是的你应该。

使用标准库验证而不是自制验证具有多种好处:

  1. 许多眼球已经看到了您将使用的代码(至少有两个),希望甚至在它被合并到一个版本之前就具有电子邮件验证的经验。
  2. 它是单元测试的。
  3. 其他人将使用相同的检查和报告错误,您可以在 php 更新中免费获得这些修复。

但是检查电子邮件地址的格式只是第一道防线,如果你真的想知道它是不是真的,你必须给它发送消息。

于 2013-10-22T15:43:34.877 回答
10

是的,你应该使用filter_var,这就是你可以合并它的方式:

if( filter_var( $email ,FILTER_VALIDATE_EMAIL ) )
{
    /*
     * Rest of your code
     */
}
于 2013-10-22T15:38:19.740 回答
8

是的。但checkdnsrr()在这里也可能值得一提。

filter_var()将批准似乎不完整的域,因为它可能在本地上下文中有效(例如,someone@localhost)。这可能会导致误报,人们只是错过了 TLD 或域名中的点(例如 hattie.jacques@gmailcom)

通过做一个来抓住这些checkdnsrr()- 如果您可以找到域的 MX 记录并且地址有效,那么您几乎已经尽了最大努力。

示例代码:

if(filter_var($email, FILTER_VALIDATE_EMAIL)) 
{
    list($userName, $mailDomain) = explode("@", $email);
    if (!checkdnsrr($mailDomain, "MX"))
    {
        // Email is unreachable.
    }
}
else
{
    // Email is bad.
}

checkdnsrr()非常即时(根据我的经验),我还没有找到它不起作用的环境。

于 2014-12-09T16:33:19.417 回答
3

不幸的是,filter_var地址的本地部分(@之前)不支持UTF8,并且要支持国际域名,您需要idn_to_ascii单独运行域名(这很麻烦且不明显)。

在我看来,这filter_var毫无用处:在野外出现的 unicode 电子邮件地址越多,合法的电子邮件地址就越失败,对于中国或巴西等对这些地址有明显需求的国家尤其如此。filter_var也不允许使用root@localhost有效的电子邮件地址,并且可能在服务器上下文中有用。

如果存在电子邮件库以根据特定说明进行验证,那将非常有用 - 只允许域名,或者也允许像 localhost 这样的任意主机,或者是否有一个应该有效的自定义域的白名单?应该允许 unicode 吗?免费邮件域名(如@homail.com)的常见拼写错误也应该失败?

此外,以更具体的方式验证某些域名是明智的 - hotmail.com 目前不允许使用 unicode 字符,并且对可用字符有特定限制。由于 PHP 应用程序中使用的大多数电子邮件地址都集中在大约 100 个不同的域上,因此这可以用来以更好的方式验证这些域名。不幸的是,据我所知,还没有这样的库。

于 2016-05-19T17:44:44.467 回答
1

我看到的一些评论与我的测试不匹配,所以我想指出我在 PHP 5.x 中发现的功能。如果您首先清理电子邮件,它将删除您不想要的所有字符,然后您可以验证。我有两个功能,以防有人只想做一个或另一个。

检查电子邮件是否有效:

function isValidEmailAddress($email = '', $check_domain = false)
{
    if (empty($email)) {
        return false;
    } else {
        $success = true;
    }

    if (!filter_var((string) $email, FILTER_VALIDATE_EMAIL)) {
        $success = false;
    }
    if ($check_domain && $success) {
        list($name, $domain) = explode('@', trim($email) . "@");
        if (!checkdnsrr($domain, 'MX')) {
            $success = false;
        }
    }
    return array("success" => $success, "email" => $email);
}

删除 <> 和 UTF8 等:

function sanitizeEmailAddress($email = '') {
    if (!empty($email)) {
        $email = filter_var(strtolower(trim($email)), FILTER_SANITIZE_EMAIL);
    }
    return $email;
}

样品用法:

// test -- 
$list = array('goodÂ@bad.com', 'mikeq@google.com', 'puser@porsche.us', 'quick@us', '', '<yo@marist.edu>', 'hello@us.edu', 'rgil@yahoo.com', 'abc@2r.edu', 'one2@e3.edu', 'key@gen.us');

foreach($list as $email) {

    $ret = isValidEmailAddress( sanitizeEmailAddress($email), false );
    if ($ret['success']) {
        echo "GOOD " . $ret['email'];
    } else {
       echo "BAD  " .$email;
    }
        echo "\n";
    }

结果 :

GOOD good@bad.com
GOOD mikeq@google.com
GOOD puser@porsche.us
BAD  quick@us
BAD  
GOOD yo@marist.edu
GOOD hello@us.edu
GOOD rgil@yahoo.com
GOOD abc@2r.edu
GOOD one2@e3.edu
GOOD key@gen.us

如果您使用域选项: $ret = isValidEmailAddress(sanitizeEmailAddress($email), true );

GOOD good@bad.com
GOOD mikeq@google.com
GOOD puser@porsche.us
BAD  quick@us
BAD  
GOOD yo@marist.edu
GOOD hello@us.edu
GOOD rgil@yahoo.com
BAD  abc@2r.edu
BAD  one2@e3.edu
BAD  key@gen.us
于 2017-07-18T15:28:22.887 回答
1

2021 年,No filter_var . 的验证实现(从 PHP 8 开始)不验证国际域名,我认为这足以成为放弃的理由。

Symfony 自己的电子邮件验证也使用不支持 UTF-8 的 Regex。

使用https://github.com/egulias/EmailValidator。它遵循电子邮件 RFC,还可以检查 MX 记录以进一步验证域确实存在。

于 2021-05-25T16:56:01.917 回答