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

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

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

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

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

17 ответов

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

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

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

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

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


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

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

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

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

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

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

Обратите внимание, что 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 = 'test@gmail.com';

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

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

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

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

По моему опыту, 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;
}

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

Может возвращать true или false, когда поставляется с FILTER_VALIDATE_EMAIL пары.

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

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

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

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

Используйте код ниже:

// Variable to check
$email = "john.doe@example.com";

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

// Validate e-mail
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
  echo("Email is a valid email address");
} else {
  echo("Oppps! Email is not a valid email address");
}

Ответили на это в "топ-вопросе" о проверке электронной почты /questions/33375717/kak-proverit-adres-elektronnoj-pochtyi-s-pomoschyu-regulyarnogo-vyirazheniya/33375781#33375781

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

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

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

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

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

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

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

Подробнее здесь.

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

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

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

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

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

theres - лучшее регулярное выражение, встроенное в FILTER_VALIDATE_EMAIL, но любое регулярное выражение может дать плохие результаты.

Например..

      // "not an email" is invalid so its false.
php > var_export(filter_var("not an email", FILTER_VALIDATE_EMAIL));
false
// "foo@a.com" looks like an email, so it passes even though its not real.
php > var_export(filter_var("foo@a.com", FILTER_VALIDATE_EMAIL));
'foo@a.com'
// "foo@gmail.com" passes, gmail is a valid email server,
//  but gmail require more than 3 letters for the address.
var_export(filter_var("foo@gmail.com", FILTER_VALIDATE_EMAIL));
'foo@gmail.com'

Возможно, вы захотите рассмотреть возможность использования API, такого как Real Email, который может выполнять тщательную проверку почтовых ящиков, чтобы проверить, является ли электронное письмо настоящим.

Немного как ..

      $email = "foo@bar.com";
$api_key = ???;

$request_context = stream_context_create(array(
    'http' => array(
        'header'  => "Authorization: Bearer " . $api_key
    )
));

$result_json = file_get_contents("https://isitarealemail.com/api/email/validate?email=" . $email, false, $request_context);

if (json_decode($result_json, true)['status'] == "valid") {
    echo("email is valid");
} else if (json_decode($result_json, true)['status'] == "invalid") {
    echo("email is invalid");
} else {
  echo("email was unknown");
}

Есть три RFC, которые закладывают основу для «формата интернет-сообщений».

  1. RFC 822
  2. RFC 2822 (заменяет RFC 822)
  3. RFC 5322 (заменяет RFC 2822)

Однако RFC 5322 определяет идентификаторы электронной почты и их структуру именования наиболее техническим образом. Это более уместно, если заложить основу интернет-стандарта, достаточно либерального, чтобы разрешить все варианты использования, но достаточно консервативного, чтобы связать его в некотором формализме.

Однако требование проверки электронной почты от сообщества разработчиков программного обеспечения имеет следующие потребности:

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

Они не совсем заинтересованы в реализации технически всеобъемлющего определения, которое допускает все формы (IP-адреса, включая идентификаторы портов и все) идентификатора электронной почты. Ожидается, что решение, подходящее для их варианта использования, обеспечит только то, что все законные владельцы электронной почты смогут пройти. Определение «законного» сильно отличается с технической точки зрения (способ RFC 5322) с точки зрения удобства использования (это решение). Аспект удобства использования проверки направлен на то, чтобы гарантировать, что все идентификаторы электронной почты, проверенные механизмом проверки, принадлежат реальным людям, использующим их для своих целей общения. Таким образом, это вводит другой аспект процесса проверки, гарантируя действительно «используемый» идентификатор электронной почты, требование, для которого определения RFC-5322 явно недостаточно.

Таким образом, с практической точки зрения фактические требования сводятся к следующему:

  1. Чтобы обеспечить некоторые очень простые проверки проверки
  2. Чтобы убедиться, что введенный адрес электронной почты используется

Второе требование обычно включает в себя отправку стандартного ответа с запросом электронной почты на введенный идентификатор электронной почты и аутентификацию пользователя на основе действия, описанного в механизме ответа. Это наиболее широко используемый механизм для обеспечения второго требования проверки «используемого» идентификатора электронной почты. Это включает в себя круговой обмен от реализации внутреннего сервера и не является прямой реализацией одного экрана, однако от этого нельзя отказаться.

Первое требование проистекает из необходимости, чтобы разработчики не хотели, чтобы строки, полностью «не похожие на электронную почту», проходили как электронная почта. Обычно это пробелы, строки без знака «@» или без имени домена. Учитывая представление доменных имен в punycode, если нужно включить проверку домена, им необходимо задействовать полноценную реализацию, которая гарантирует действительное доменное имя. Таким образом, учитывая основной характер требования в этом отношении, проверка на "<что-то>@<что-то>.<что-то>" является единственным подходящим способом удовлетворения требования.

Типичное регулярное выражение, удовлетворяющее этому требованию:^[^@\s] [email protected] [^@\s.]+.[^@\s.]+$ Приведенное выше регулярное выражение следует стандартному регулярному выражению Perl. стандарт, широко используемый большинством языков программирования. Оператор проверки:<все, кроме пробелов и знака "@">@<все, кроме пробелов и знака "@">.<все, кроме пробелов, знака @ и точки>

Для тех, кто хочет углубиться в более подходящие реализации, они могут следовать следующей методологии проверки.<локальная часть электронной почты>@<имя домена>

Для <локальной части электронной почты> — следуйте рекомендациям «Руководящей группы по универсальному принятию» — UASG-026. Для <имя домена> вы можете следовать любой методологии проверки домена с использованием стандартных библиотек в зависимости от вашего языка программирования. Последние исследования по этому вопросу см. в документе UASG-018A.

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

RFC 6530 (Обзор и структура интернационализированной электронной почты)RFC 6531 (Расширение SMTP для интернационализированной электронной почты)RFC 6532 (Интернационализированные заголовки электронной почты)RFC 6533 (Интернационализированные уведомления о статусе доставки и доставке)RFC 6855 (Поддержка IMAP для UTF-8)RFC 6856 (Почта Протокол Office версии 3 (POP3) с поддержкой UTF-8)RFC 6857 (понижение версии сообщения после доставки для интернационализированных сообщений электронной почты)RFC 6858 (упрощенное понижение версии POP и IMAP для интернационализированной электронной почты).

Я подготовил функцию, которая проверяет действительность электронной почты:

      function isValidEmail($email)
{
    $re = '/([\w\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)/m';
    preg_match_all($re, $email, $matches, PREG_SET_ORDER, 0);
    if(count($matches) > 0) return $matches[0][0] === $email;
    return false;
}

Проблема сFILTER_VALIDATE_EMAILзаключается в том, что он считает даже недействительные электронные письма действительными.

Ниже приведены примеры:

      if(isValidEmail("foo@gmail.com")) echo "valid";
if(!isValidEmail("fo^o@gmail.com")) echo "invalid";

Я сделал реализации Python и PHP для правильной проверки ЛЮБОГО адреса электронной почты, который подтвержден как реальный с почтового сервера для реального домена.

Выпущено под лицензией GPL-3.0.

Ну вот:

https://lja.fi/index.php/github-stuff/

--ля

Название вопроса довольно общее, однако в тексте вопроса указано, что речь идет о решении на основе PHP. Попробую обратиться к обоим.

Вообще говоря, для всех языков программирования: как правило, проверка адреса электронной почты с помощью регулярного выражения — это то, от чего должен воздерживаться любой интернет-провайдер. Возможности различных видов доменных имен и адресов электронной почты значительно расширились. с точки зрения разнообразия, любая попытка проверки, которая не очень хорошо продумана, может привести к отказу в доступе некоторых действительных пользователей к вашей системе.Чтобы избежать этого, один из лучших способов — отправить электронное письмо пользователю и убедиться, что оно получено. хорошие ребята из " Руководящей группы по универсальному принятию "" составили языковой список библиотек, которые признаны соответствующими/несовместимыми с различными параметрами, включая проверки в отношении интернационализированных доменных имен и интернационализированных адресов электронной почты. Ссылки на эти документы можно найти здесь и здесь.

Говоря конкретно о PHP: в PHP есть одна хорошая библиотека, а именно EmailValidator. Это валидатор адресов электронной почты, который включает в себя множество методов проверки, таких как проверка DNS. Специально рекомендуемый валидатор называется RFCValidator и проверяет адреса электронной почты на соответствие нескольким RFC. Он имеет хорошее соответствие, когда речь идет об инклюзивности IDN и интернационализированных адресов электронной почты.

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

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

Это будет проверять только правильность формата электронной почты или нет. Но если вы хотите использовать что-то большее, например, существует ли это электронное письмо на самом деле или нет. Вам нужно использовать какой-то API проверки почты, как предложил @Stephan, но за это нужно заплатить.

если вы хотите использовать 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 в том, что он предоставляет результаты в режиме реального времени, и вы получите 10000 бесплатных кредитов.

Другие вопросы по тегам