Проверка международных адресов электронной почты с помощью PHP - PullRequest
0 голосов
/ 25 февраля 2019

Мотивация

В этой теме я хотел бы собрать лучшие практики и решения, как решить проблему проверки адреса электронной почты, включая международные письма.Есть несколько способов, таких как структурные проверки, поиск DNS и т. Д. Но, похоже, на этом пути есть ловушки / крайние случаи, о которых не все знают.Я надеюсь, что вы, ребята, можете помочь мне собрать хорошие ссылки / код / ​​советы, сгруппированные по темам (например, на стороне сервера, подготовка HTML, ...).

Позволяет обрабатывать каждую область интересов в отдельном ответе.

Значение проверки

Если я использую термин «проверка», я имею в виду проверку данных.Википедия определяет это:

[...] - это процесс проверки того, что данные подверглись очистке, чтобы гарантировать, что они имеют качество данных, то есть оба они правильны иполезно.

Источник: https://en.wikipedia.org/wiki/Data_validation

Проверка адреса электронной почты

Проверка адреса электронной почты означает проверку строки, если она действительна в соответствии с условиями RFC 5322.это последняя версия, которая описывает формат сообщений в Интернете, используемый в электронных письмах.Ссылка: https://tools.ietf.org/html/rfc5322

Это не включает проверки, если поставщик электронной почты действителен (например, одноразовые электронные письма) или если адрес имеет смысл (например, a1@a2.coo) или если TLD являетсядоступно.

Не поддерживается большинством валидаторов: международные адреса электронной почты

международная почта ( ref ) может содержать все виды символов UTF-8, которых нет в ASCII.

Допустимые примеры на основе статьи в вики:

  • θσερ@εχαμπλε.ψομ
  • Dörte@Sörensen.example.com

1 Ответ

0 голосов
/ 25 февраля 2019

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

filter_var

Автор этой публикации предложил следующую функциюподтвердите адрес электронной почты:

function isValidEmail($email){ 
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

Если вам требуется, чтобы TLD был частью адреса, автор также предложил:

function isValidEmail($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) 
        && preg_match('/@.+\./', $email);
}

Проблема: нет поддержки международных адресов электронной почты

filter_var не распространяется на международные адреса электронной почты, которые содержат символы UTF-8, такие как греческий или русский.


preg_match

Используйте пользовательское регулярное выражение для проверки структуры.Хороший пост с подробным описанием: здесь .

Автор предложил регулярное выражение из http://emailregex.com/,, которое позволяет проверять последние версии RDF 5322. Следующий код является нефиксированнымверсия:

$regex = '/^(?!(?:(?:\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';

if (1 == \preg_match($regex, $email)) {
   // email OK
}

Он также упомянул:

[...] RFC 5322 приводит к регулярному выражению, которое можно понять, если изучить его в течение нескольких минут, и достаточно эффективно дляфактическое использование.[...]

Проблема: нет поддержки международных адресов электронной почты

Это решение также не распространяется на международные адреса, которые не совпадают.


Необязательно: поиск DNS

Поиск DNS не является проверкой , но может дополнить проверку.Он работает со всеми символами UTF-8, если они образуют действительное интернационализированное доменное имя (Ссылка: https://en.wikipedia.org/wiki/Internationalized_domain_name).

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

С помощью checkdnsrr вы проверяете, есть ли в указанном домене действительная запись DNS.

// $domain was extracted from the given email before
// $domain must end with a . (see comment below)

if (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA')) {
    // domain is VALID
}

Пользователь Мартин упомянул на php.net, что домен должен заканчиваться на . добудет считаться действительным. Без точки вы получите ложные срабатывания.

Источник : http://php.net/manual/en/function.checkdnsrr.php#119969


Обработка международных писем

ВозможноРешение 1: структурная проверка + поиск DNS

Что я видел до сих пор, вам нужна комбинация структурных проверок + поиск DNS, чтобы получить лучшее покрытие. Первая часть следующего кода основана накласс EmailAddress из Genkgo Mail ( source ).

function mail_is_valid(string $address): bool {
    $hits = \preg_match('/^([^@]+)@([^@]+)$/', $address, $matches);

    if ($hits === 0) {
        // email NOT valid
        return false;
    }

    [$address, $localPart, $domain] = $matches;

    $variant = INTL_IDNA_VARIANT_2003;
    if (\defined('INTL_IDNA_VARIANT_UTS46') ) {
        $variant = INTL_IDNA_VARIANT_UTS46;
    }

    $domain = \rtrim(\idn_to_ascii($domain, IDNA_DEFAULT, $variant), '.') . '.';

    if (!\checkdnsrr($domain, 'MX')) {
        return \checkdnsrr($domain, 'A') || \checkdnsrr($domain, 'AAAA');
    } else {
        return true;
    }
}

Я считаю это лучшим на данный момент решением, поскольку алгоритм в основном не зависит от символов, что допускает использование символов UTF-8 в электронном письме.Это верно, если у вас есть пользовательская часть + @ + domain-part.Поиск DNS гарантирует, что домен существует.

Это не оптимально.Если вы знаете лучший способ, пожалуйста, оставьте его как комментарий или решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...