使用 checkdnsrr 验证电子邮件,好的还是坏的解决方案?

Mar*_*Mar 5 php regex http email-validation

我正在使用下面的代码来验证电子邮件

if (checkdnsrr($domain , "MX")) {
    echo 'mx - pass <br>';
} else {
    echo 'mx - fail <br>';
}
Run Code Online (Sandbox Code Playgroud)

我的愿望是检查域是否有效并具有 MX 记录。

我已经在使用正则表达式来检查电子邮件格式,但是人们输入了诸如 someone@gmail.con 之类的内容,这显然是错误的,但通过了基本格式验证。

我想进一步验证,但我不想走得太远而得到假阴性。

有没有人看到我的解决方案有任何问题或有更好的方法?

Are*_*eeb 5

您的解决方案非常好!但是,在您进行 DNS 调用之前,我建议您首先使用 FILTER_VALIDATE_EMAIL 验证电子邮件地址,然后将其传递给 MX DNS 检查。

虽然可能不需要检查 MX 记录是否存在,但您希望避免退回电子邮件,请继续!


Ant*_*dge 5

是的,使用checkdnsrr()是个好主意。何时使用它是您应该关注的。我使用四通道系统。这是我对电子邮件所做的工作的框架,而不是确切的组织。

四通道系统

通过 1)我的自定义过滤器使用filter_input_array()此规则(其中过滤器出现在类/对象的方法中。根据需要添加元素(对于其他字段)。

$customFilterRules = [
    'email' => ['filter'  => FILTER_CALLBACK,
                'flags'   => FILTER_REQUIRE_SCALAR,
                'options' => [$this, 'scrubber']
];
Run Code Online (Sandbox Code Playgroud)

Pass 2 ) 与此过滤规则一起使用filter_input_array()。根据需要添加更多元素(对于其他字段)。

$phpFilterRules = [
    'email' => ['filter' => FILTER_SANITIZE_EMAIL,
                'flags'  => FILTER_REQUIRE_SCALAR]
];
Run Code Online (Sandbox Code Playgroud)

通过 3)使用此验证规则filter_var_array()的输出。filter_input_array()根据需要添加更多规则。

$phpValidationRules = [
    'email' => ['filter' => FILTER_VALIDATE_EMAIL,
                'flags'  => FILTER_REQUIRE_SCALAR]
];
Run Code Online (Sandbox Code Playgroud)

通过 4)在课堂上检查以下内容EmailValidator。另外,如果您不喜欢使用filter_input_array(),那么此类中的一些方法通常可能会有所帮助。根据需要进行更改。

哦,我还检查电子邮件地址的基本的、特定于应用程序的、可接受的长度:

$length = mb_strlen($email, 'UTF-8') //Make a decision based on this.
Run Code Online (Sandbox Code Playgroud)

此外,我还有一个很棒的、特定于应用程序的电子邮件正则表达式,与preg_match(). 我只接受 128 个字符的电子邮件地址。

'/(?>\A[A-Za-z0-9_-][A-Za-z0-9_.-]{0,62}?[A-Za-z0-9_-]{0,1}@{1}?(?:(?:[A-Za-z0-9]{1}?){1}?(?:[A-Za-z0-9.-]{0,61}?[A-Za-z0-9]{1}?){0,1}?){1,127}?\.{1}?[a-z]{2,20}?\z){1}?/u'
Run Code Online (Sandbox Code Playgroud)

这里有一些EmailValidator方法。

/**
 * Compares 2 email addresses. If 1, just keep going.
 */
private function sameEmailAddress()
{
    if (count($this->filteredInputArray) === 2) {  //If there are two.
        if ($this->identical($this->filteredInputArray['email1'], $this->filteredInputArray['email2'])) {
            return true;
        }

        $this->testResultsArray['email1'] = false;
        $this->testResultsArray['email2'] = false;
        $this->errorMessagesArray['email1'] = 'Does not match e-mail below.';
        $this->errorMessagesArray['email2'] = 'Does not match e-mail above.';
        return false;
    }

    if (count($this->filteredInputArray) === 1) {  //If there is only 1.
        return true;
    }

    return false;
}

/**
 * Finds problems with e-mail as a whole.
 * There is a regular expression you can do this with.
 */
private function consecutivePeriodTest ($emailAddress, &$errorMessage)
{
    if (!preg_match('/\A(?!..)+?\z/', $emailAddress)) {
        return true;
    }

    $errorMessage = 'Consecutive periods are illegal!';
    return false;
}
Run Code Online (Sandbox Code Playgroud)

最后我用了checkdnsrr()

/**
 * Given an array of unique domains, check DNS MX records.
 */
private function mxDNSPing(array $uniqueDomains)
{   
    $badDomains = [];

    foreach ($uniqueDomains as $key => $domain) {
        if (!checkdnsrr($domain, 'MX')) {
            $this->testResultsArray[$key] = false;
            $this->errorMessagesArray[$key] = 'No DNS MX records found.';
            $badDomains[$key] = $domain;
        }
    }

    return $badDomains;
}
Run Code Online (Sandbox Code Playgroud)

确定电子邮件地址有什么问题。

/**
 * Finds problems with local or domain parts.
 * Should break up into two methods, though.
 */
private function emailPartProblemFinder($string, &$errorMessage)
{
    $emailParts = $this->string->getEmailAddressParts($string); //explode() on `@`

    if (count($emailParts) !== 2) {
        $errorMessage = 'Invalid e-mail address!';
    } else {
        list($localPart, $domain) = $emailParts;

        $localLength  = mb_strlen($localPart);
        $domainLength = mb_strlen($domain);

        if ($localLength === 0) {
            $errorMessage = 'Missing local part of address.';
        } elseif ($localLength > 64) {
            $errorMessage = 'Only 64 characters are alloed before the @ symbol ('.$localLength.' given)';
        } elseif (mb_strrpos($string, '.') === ($localLength - 1)) {
            $errorMessage = 'The local part of an email address cannot end with a period (.).';
        } elseif (mb_strpos($string, '..') >= 0) {
            $errorMessage = 'The local part of an email address cannot contain consecutive periods (..).';
        } elseif ($domainLength < 4) { //x.yy, is my minimum domain format.
            $errorMessage = 'Domain part < 4 characters. ('.$domainLength.' given)';
        } elseif ($domainLength > 253) {
            $errorMessage = 'Domain part exceeds 253 characters. ('.$domainLength.' given)';
        }
    }

    return;
}

/**
 * Finds problems with e-mail as a whole.
 */
private function emailAddressProblemFinder($string, $max, &$errorMessage)
{
    $length = mb_strlen($string, 'UTF-8');
    $atSymbolCount = mb_substr_count($string, '@', 'UTF-8');

    if ($length === 0) {
        return false;    //The reason was already assigned to the error message inside of $this->validateInput()
    } elseif ($length > $max) {
        $errorMessage = 'Exceeds max length (' . $max . ' characters)';
    } elseif ((mb_strpos($string, '@') === 0)) {
        $errorMessage = 'Cannot start with a @';
    } elseif ((mb_strrpos($string, '@') === ($length - 1))) {
        $errorMessage = 'Cannot end with a @';
    } elseif ($atSymbolCount > 1) {
        $errorMessage = '@ appears '.$atSymbolCount.' times.';
    } elseif ((mb_strpos($string, '@') === false)) {
        $errorMessage = 'The @ symbol is missing.';
    } elseif (mb_strpos($string, '.') === 0) {
        $errorMessage = 'The local part of an email address cannot start with a period (.).';
    } else {
        $this->emailPartProblemFinder($string, $errorMessage);
    }

    return;
}
Run Code Online (Sandbox Code Playgroud)

该方法emailAddressProblemFinder()仅被调用以发现问题所在。emailPartProblemFinder()如有必要,它会调用。

我的观点是,在使用之前您可以进行大量测试checkdnsrr()。这是否明智值得你和其他人争论。无论如何,我总是喜欢看别人做什么!