Как проверить адрес электронной почты в PHP

У меня есть эта функция для проверки адресов электронной почты:

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

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

Это нормально для проверки правильности адреса электронной почты?

Ответы

Ответ 1

Самый простой и безопасный способ проверить, правильно ли сформирован адрес электронной почты, - использовать filter_var():

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

Кроме того, вы можете проверить, определяет ли домен запись MX:

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

Но это все еще не гарантирует, что почта существует. Единственный способ узнать это - отправить письмо с подтверждением.


Теперь, когда у вас есть свой простой ответ, вы можете свободно читать о проверке адреса электронной почты, если хотите научиться или иным образом просто использовать быстрый ответ и двигаться дальше. Никаких жестких чувств.

Попытка проверить адрес электронной почты с помощью регулярного выражения является "невозможной" задачей. Я хотел бы сказать, что это регулярное выражение, которое вы сделали, бесполезно. Существует три rfc относительно адресов электронной почты и написания регулярных выражений, чтобы поймать неправильные адреса электронной почты и в то же время не имеют ложных срабатываний - это то, что не может сделать смертный. Проверьте этот список для тестов (как неудачных, так и filter_var() регулярного выражения, используемого filter_var() PHP filter_var().

Даже встроенные функции PHP, почтовые клиенты или серверы не понимают это правильно. В большинстве случаев filter_var - лучший вариант.

Если вы хотите узнать, какой шаблон регулярного выражения PHP (в настоящее время) используется для проверки адресов электронной почты, обратитесь к источнику PHP.

Если вы хотите узнать больше о адресах электронной почты, я предлагаю вам начать читать спецификации, но я должен предупредить вас, что это нелегко прочитать на любом участке:

  • rfc5322
  • RFC5321
  • rfc3696
  • rfc6531 (допускает символы Unicode, хотя многие клиенты/серверы не принимают его)

Обратите внимание: filter_var() уже указан только в PHP 5.2. Если вы хотите, чтобы он работал с более ранними версиями PHP, вы могли бы использовать регулярное выражение, используемое в PHP:

<?php

$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';

$emailaddress = '[email protected]';

if (preg_match($pattern, $emailaddress) === 1) {
    // emailaddress is valid
}

PS Замечание о шаблоне регулярного выражения, используемом выше (из источника PHP). Похоже, есть некоторые авторские права на него Майкла Раштона. Как указано: "Не стесняйтесь использовать и распространять этот код, но, пожалуйста, сохраните это уведомление об авторских правах".

Ответ 2

Вы можете использовать filter_var для этого.

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

Ответ 3

По моему опыту, в решениях regex слишком много ложных срабатываний, а в filter_var() есть ложные негативы (особенно со всеми новыми TLD).

Вместо этого лучше убедиться, что адрес имеет все необходимые части адреса электронной почты (пользователь, символ "@" и домен), а затем убедитесь, что сам домен существует.

Невозможно определить (серверную сторону), если пользователь электронной почты существует для внешнего домена.

Это метод, который я создал в классе Utility:

public static function validateEmail($email)
{
    // SET INITIAL RETURN VARIABLES

        $emailIsValid = FALSE;

    // MAKE SURE AN EMPTY STRING WASN'T PASSED

        if (!empty($email))
        {
            // GET EMAIL PARTS

                $domain = ltrim(stristr($email, '@'), '@') . '.';
                $user   = stristr($email, '@', TRUE);

            // VALIDATE EMAIL ADDRESS

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

    // RETURN RESULT

        return $emailIsValid;
}

Ответ 4

Я думаю, вам может быть лучше использовать PHP inbuilt filters - в данном конкретном случае:

Он может возвращать true или false, если поставляется с параметром FILTER_VALIDATE_EMAIL.

Ответ 5

Это не только подтвердит вашу электронную почту, но и дезинформирует ее для неожиданных символов:

$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);
}

Ответ 6

Ответил это в "верхнем вопросе" о проверке электронной почты fooobar.com/questions/245/...

Для меня правильный способ проверки электронной почты:

  • Убедитесь, что символ @существует, и до и после него есть некоторые символы @@: /^[^@][email protected][^@]+$/
  • Попробуйте отправить электронное письмо на этот адрес с некоторым "кодом активации".
  • Когда пользователь "активирует" свой адрес электронной почты, мы увидим, что все правильно.

Конечно, вы можете показать предупреждение или всплывающую подсказку в интерфейсе, когда пользователь набрал "странную" электронную почту, чтобы помочь ему избежать распространенных ошибок, например, нет точка в доменной части или пробелы в названии без цитирования и т.д. Но вы должны принять адрес "hello @world", если пользователь действительно этого хочет.

Кроме того, вы должны помнить, что стандарт адреса электронной почты был и может evolute, поэтому вы не можете просто называть некоторое "стандартное допустимое" регулярное выражение один раз и на все времена. И вы должны помнить, что какой-то конкретный интернет серверы могут выдать некоторые детали общего стандарта и фактически работать с собственный "модифицированный стандарт".

Итак, просто отметьте @, подскажите пользователю об интерфейсе и отправьте письма с подтверждением по указанному адресу.

Ответ 7

Если вы просто ищете фактическое регулярное выражение, которое допускает различные точки, подчеркивания и тире, это выглядит следующим образом: [a-zA-z0-9.-]+\@[a-zA-z0-9.-]+.[a-zA-Z]+. Это позволит проверять довольно глупый вид электронной почты, например [email protected]_matrix.com.

Ответ 8

/(?![[:alnum:]]|@|-|_|\.)./

В настоящее время, если вы используете форму HTML5 с type=email, вы уже на 80% безопасны, так как у браузеров есть свой валидатор. Чтобы дополнить его, добавьте это регулярное выражение к вашему preg_match_all() и отрицайте его:

if (!preg_match_all("/(?![[:alnum:]]|@|-|_|\.)./",$email)) { .. }

Найти регулярное выражение, используемое форматами HTML5 для проверки
https://regex101.com/r/mPEKmy/1

Ответ 9

При запуске некоторых тестов этим утром я обнаружил, что FILTER_VALIDATE_EMAIL будет проверять [email protected] как действительный адрес электронной почты.

$counter = 0;
foreach($emails as $email){    
    $email = trim($email);
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        unset($emails[$counter]);
    }  
    $counter++;
}

У кого-нибудь есть рекомендация по устранению этого?

Ответ 10

Если вы хотите проверить, действительно ли предоставленный домен с адреса электронной почты действителен, используйте что-то вроде:

/*
* 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 как часть домена в электронной почте (например, [email protected][IPv6:2001:db8::1]) не могут быть проверены, но только именами хостов.

Подробнее см. Здесь.

Ответ 11

Прочитав ответы здесь, я получил следующее:

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

Ответ 12

Кроме того, вы могли бы полагаться на сторонний API, такой как https://email-validation-api.com, для того, чтобы иметь корректор орфографических ошибок и несколько контрольных точек и индикаторов на релевантность соответствующего адреса электронной почты.

Ответ 13

Лучшее решение использует filter_var:

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $this->addError($attribute, 'you inputted wrong email'); // Or another handler
}