使用checkdnsrr验证电子邮件,这是一个好的或坏的解决方案?

时间:2017-02-24 11:15:32

标签: php regex http email-validation

我使用以下代码验证电子邮件

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

我希望检查域名是否有效并且有MX记录。

我已经使用正则表达式来检查电子邮件格式,但是人们输入像someone@gmail.con这样的内容,这显然是错误的,但是会进行基本的格式验证。

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

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

3 个答案:

答案 0 :(得分:3)

是的,使用checkdnsrr()是一个好主意。什么时候使用它是你应该关注的。我使用四通系统。这是骨架,而不是我为电子邮件做的确切组织。

四通系统

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

$customFilterRules = [
    'email' => ['filter'  => FILTER_CALLBACK,
                'flags'   => FILTER_REQUIRE_SCALAR,
                'options' => [$this, 'scrubber']
];

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

$phpFilterRules = [
    'email' => ['filter' => FILTER_SANITIZE_EMAIL,
                'flags'  => FILTER_REQUIRE_SCALAR]
];

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

$phpValidationRules = [
    'email' => ['filter' => FILTER_VALIDATE_EMAIL,
                'flags'  => FILTER_REQUIRE_SCALAR]
];

通过4 )使用EmailValidator课程检查以下内容。另外,如果您不喜欢使用filter_input_array(),则此类中的一些方法通常可能会有所帮助。必要时更改。

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

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

此外,我有一个很好的,特定于应用程序的电子邮件正则表达式,我使用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'

以下是一些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;
}

最后,我使用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;
}

确定电子邮件地址的错误。

/**
 * 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;
}

方法emailAddressProblemFinder()仅用于发现出错的地方。如有必要,它会调用emailPartProblemFinder()

我的观点是,在使用checkdnsrr()之前,您可以进行大量的测试。这种智慧是你和其他人辩论的东西。无论如何,我总是喜欢看别人做的事情!

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

我使用chkdnsrr()多年以来一直没有问题,直到本周为止(如上所述,已经进行了预检查),当时它没有明显的原因将有效域(dfp.com.my)踢出。我不知道是什么原因造成的,所以我现在确保已安装nslookup(在CentOS上为sudo yum install bind-utils),并使用以下命令:

function isDomainValid($domain) {
    $output = [];
    $return = false;
    exec("nslookup $domain", $output, $return);
    return $return === 0;
}