Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Избранное > Валидность email - самая дотошная регулярка


Автор: smartov 22.4.2008, 15:01
Недавно вдруг захотелось написать дотошную регулярку на email - не как обычно буковки там проверил, немного на точку и собаку - а остальное не важно, а так чтобы не пропустило синтаксически невалидный адрес.

Имя 
  •  Должно начинаться с буквы/цифры
  •  Не дожно содержать символов кроме [0-9a-zA-Z\-\_\.]
  •  Не должно содержать двух точек подряд
  •  Должно заканчиваться на букву/цифру
С политикой имени домена всё аналогично. Последняя часть доменного имени (com, info ...) должна состоять из 2-6 буквенных символов.
Доменное имя можеть быть вида my.cool.sub.domain.com

Родилось вот это.

Код

<?php

$email = 'name.lastname@my.site.com';
$regexp = '^[0-9a-zA-Z]([0-9a-zA-Z\-\_]+\.)*[0-9a-zA-Z]*@[a-zA-Z0-9]*([0-9a-zA-Z\-\_]+\.)*[0-9a-zA-Z]+\.[a-zA-Z]{2,6}$';

var_dump( preg_match("/$regexp/", $email) );

?>


License - LGPL smile

UPDATE:
Как оказалось "Всё уже украдено до нас" (С)

Код

var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));

Автор: flashaa 22.4.2008, 15:24
smartov у емейл и доменных имен есть вполне четкие спецификации в стандартах rfc и если писать дотошную регулярку, то стоило обратить внимание прежде всего туда. Там есть ещё некоторые подводные камни.
Последняя часть имени называется tld (top level domain) - ликбез.

Автор: ksnk 22.4.2008, 15:26
GPL - неправильно, нужно LGPL  smile 

А как-же всякие навороченные http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html?

Автор: SelenIT 22.4.2008, 16:35
Запись [0-9\w] избыточна, цифры (и даже подчеркивание, а при правильной локали - еще и русские буквы) уже входят в \w.

Автор: CyClon 22.4.2008, 18:50
Код
Запись [0-9\w] избыточна, цифры (и даже подчеркивание, а при правильной локали - еще и русские буквы) уже входят в \w. 

В email недопустимы русские буквы, поэтому \w действительно избыточна. Я предпочитаю указывать конкретно набор допустимых символов, дабы избежать зависимости от настроек локали.

Примерно так выглядит эта регулярка в моем исполнении:

Код
~^[a-Z0-9_.-]{1,20}@[a-Z0-9.-]+\.[a-Z0-9]{2,5}$~


Тобишь сначала идем учетная запись от 1 до 20 символов, потом знак @, за которым следуем одно или многоуровневое название сервера, дальше точка, после которой от 2 до 5 символов имя первого уровня. Вроде так.

Автор: flashaa 22.4.2008, 19:15
Цитата(CyClon @  22.4.2008,  18:50 Найти цитируемый пост)
Вроде так

не так =)

Автор: CyClon 22.4.2008, 19:40
flashaa, обоснуй плз smile

Автор: smartov 22.4.2008, 22:01
flashaa, спасибо за комментарий, RFC я читал, но судя по вашему комментарию, плохо, думаю вы читали лучше и наверняка у вас есть лучший вариант регулярки, написанной вами. Не поделитесь?

ksnk, хыы  smile  smile 

Автор: SelenIT 22.4.2008, 22:01
CyClon, можно я обосную? ;)
1) a-Z - бессмысленный диапазон, потому что в http://ru.wikipedia.org/wiki/ASCII (первая половина всех однобайтных кодировок + начало UTF-8) заглавные буквы идут раньше строчных. Но даже если диапазон и будет прочитан "задом наперед", туда попадут аж 6 левых символов;
2) валидным доменом окажется ......500;
3) есть 6-буквенные домены верхнего уровня (.museum, .travel).

Вообще сколько раз обсуждали уже эту задачу smile. Вроде как давно общепринятое мнение, что единственный способ 100%-ной валидации e-mail - это посылка туда письма с подтверждающей ссылкой smile. Во всех остальных случаях юзер наверняка вобъет белиберду, не задумываясь. И чтобы заставить его задуматься (после чего ему может оказаться легче вспомнить и вбить настоящий е-mail, чем выдумывать левый;), в 90% случаев вполне достаточно той самой примитивной проверки на наличие собачки и точки (если не путаю, как раз похожую простейшую проверку делает нативный <input type="email"> в HTML5...). Ну и, само собой, при отправке по почте любых юзерских данных нужно нещадно резать все символы перевода строки и т.п. отовсюду, кроме тела письма (во избежание mail injection).

Автор: smartov 22.4.2008, 22:02
Цитата(SelenIT @  22.4.2008,  16:35 Найти цитируемый пост)
Запись [0-9\w] избыточна, цифры (и даже подчеркивание, а при правильной локали - еще и русские буквы) уже входят в \w. 

Точно smile Нужно будет поправить

Автор: flashaa 23.4.2008, 11:45
smartov, да вариант есть. В свое время был изучен вопрос. Найду и скину сюда. Извиняюсь за голословность на данный момент.
СyСlonSelenIT обосновал =)

Автор: Akina 23.4.2008, 12:53
Вот синтаксически валидный адрес (см. напр. RFC 822, 3.4.1):

"My e-mail"@mycompany.ru

Автор: CyClon 23.4.2008, 13:05
SelenITflashaa, ок спасибо smile Ну, смысл я думаю понятен smile

Вообще такая регулярка еще и защищает от инъекции в некоторой степени, так что проверять емаил на наличие одной только собачки имхо не стоит smile

Автор: source777 23.4.2008, 22:11
smartov Чтобы написать дотошную регулярку для email надо тупо взять RFC и записать его в синтаксисе регулярных выражений, получится естественно на полэкрана, зато дотошно, а так интуитивно как ты попытался сделать - это всё по сути баловство, с тем же успехом можно использовать что-нить типа: ^[a-z0-9.-]*[a-z0-9]@([a-z0-9-]*[a-z]\.?[a-z]+)+$

Автор: flashaa 23.4.2008, 23:28
Итак, пойдем по rfc822.
Поскольку эти документы содержат не стандарты, а рекомендации, некоторые варианты представления сущностей можно опустить. Рассмотрим только те, которые нам встречаются в реальной (точнее, виртуальной) жизни.

email адрес состоит из локальной части и домена - это понятно.
локальная часть может состоять:
1) Из слов, разделенных точками. Слово - последовательность любых символов кроме (, ), <, >, @, "," , ; , :, \, двойной кавычки, ., [, ], пробела, ASCII-управляющих символов( с кодами 0-37, 177, 127)
2) Из почти любых символов, заключенных в кавычки - этот вариант наверно опустим

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

Соответственно, получаем такую регулярку:

Код

$word = '(?:[^()<>@,.;:\"\[\]\s\0-\37\177\127]+?)';
$local_part = $word . '(?:\.' . $word . ')*?';
$subdomain = $word . '(?:\.' . $word . ')*?';
$domain = $subdomain . '(?:\.' . $subdomain . ')+?';
$email = '/^'. $local_part . '@' . $domain . '$/';


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

Вот это я понимаю дотошно =)

Автор: Fortop 24.4.2008, 06:40
Цитата(flashaa @  23.4.2008,  23:28 Найти цитируемый пост)
Вот это я понимаю дотошно =)

1@1.ru

Добавлено через 2 минуты и 36 секунд
flashaa, считает валидным
smartov, считает невалидным.

Автор: SelenIT 24.4.2008, 10:03
Домены из одних цифр существуют (минский блог 017.by, куча фирм с доменом == номеру телефона). Имхо, вариант flashaa прав smile

Автор: smartov 24.4.2008, 11:13
Итого я подправил регулярку.
Добавил разрешение начинаться и заканчивать цифрами для всех частей, кроме tld.

В регулярке flashaa, никаких особых новшеств не нашел, может он мне пояснит доступно чем она отличается от моей с цифрами (кроме ограничения по длине tld).

Добавлено через 2 минуты и 38 секунд
Ну и лицензию на Lesser  smile  smile 

Автор: SelenIT 24.4.2008, 11:35
smartov, и все равно [0-9\-\_\w] ;)

Автор: flashaa 24.4.2008, 11:54
Цитата(Fortop @  24.4.2008,  06:40 Найти цитируемый пост)
1@1.ru

И что? Ответ SelenIT уже дал. Можно ещё с десяток циферных накидать. И читать надо коменты.

Цитата(smartov @  24.4.2008,  11:13 Найти цитируемый пост)
В регулярке flashaa, никаких особых новшеств не нашел, может он мне пояснит доступно чем она отличается от моей с цифрами (кроме ограничения по длине tld).

ну как же не нашел то? Для кого я писал на той странице отдельный пункт?
Хорошо, сейчас наскребу все отличия. Точнее попытаюсь наскрести, т.к. в памяти не держу, что было в вашей старой регулярке =) 
 1) У вас что имя что домен начинаются обязательно на букву и заканчиваются на букву, в середине могут быть буквы, цифры, точки. На самом деле первая и последняя буква ничем ни отличаюся от букв в середине. - это ваши постулаты  которые неверны
2) У вас кажется была просто ошибка того, что можно было 2 точки подрят написать

НУ и собственно все.. Сложно накопать важные момент в валидации строки с собачкой. Просто суть в том, что моя регулярка дотошна =)

Да и ещё если совсем докопаться, то rfc подразумевает, что набор символов ascii. Поэтому если есть символы с кодами больше 127, то можно сразу отбрасывать такой емейл  smile 

Автор: Fortop 24.4.2008, 12:18
Цитата(SelenIT @  24.4.2008,  10:03 Найти цитируемый пост)
Домены из одних цифр существуют (минский блог 017.by, куча фирм с доменом == номеру телефона). Имхо, вариант flashaa прав 

Да бусть себе существуют сколько угодно smile

Вы мне можете привести домены первого уровня 1.org, a.net, b.com и т.д.? нет?

Автор: SelenIT 24.4.2008, 12:58
Fortop, как минимум, есть http://z.com/.

Автор: Fortop 24.4.2008, 13:45
SelenIT, точно smile и не только он smile
был не прав.

Автор: SelenIT 24.4.2008, 15:00
Цитата(Fortop @  24.4.2008,  13:45 Найти цитируемый пост)
и не только он smile

http://www.the-end.name/archives/103 smile

Автор: smartov 24.4.2008, 15:11
Цитата(SelenIT @  24.4.2008,  11:35 Найти цитируемый пост)
и все равно [0-9\-\_\w] ;)

Черт, пропустил  smile 

Цитата(flashaa @  24.4.2008,  11:54 Найти цитируемый пост)
На самом деле первая и последняя буква ничем ни отличаюся от букв в середине. - это ваши постулаты  которые неверны

Теперь не правы вы. В RFC четско написано что в этих местах не могут быть точки, подчеркивания, дефисы.

Цитата(flashaa @  24.4.2008,  11:54 Найти цитируемый пост)
2) У вас кажется была просто ошибка того, что можно было 2 точки подрят написать

Кажется - креститься надо. Не было такой ошибки

Цитата(flashaa @  24.4.2008,  11:54 Найти цитируемый пост)
Да и ещё если совсем докопаться, то rfc подразумевает, что набор символов ascii. Поэтому если есть символы с кодами больше 127, то можно сразу отбрасывать такой емейл

Он и отбрасывается

Цитата(flashaa @  24.4.2008,  11:54 Найти цитируемый пост)
НУ и собственно все.. 

Учитывая мои ответы выше... так где же дотошность? То же самое но другими словами еще и с ограничением на вложенность доменов.

Автор: flashaa 24.4.2008, 17:48
Цитата(smartov @  24.4.2008,  15:11 Найти цитируемый пост)
Теперь не правы вы. В RFC четско написано что в этих местах не могут быть точки, подчеркивания, дефисы.

Можно цитату?
Я лично ориентировался на это:
 http://www.faqs.org/rfcs/rfc822.html , раздел 6.
Цитата(smartov @  24.4.2008,  15:11 Найти цитируемый пост)
Кажется - креститься надо. Не было такой ошибки

Не надо было править

Цитата(smartov @  24.4.2008,  15:11 Найти цитируемый пост)
Он и отбрасывается

\w - может включать не ASCII

Цитата(smartov @  24.4.2008,  15:11 Найти цитируемый пост)
Учитывая мои ответы выше... так где же дотошность? То же самое но другими словами еще и с ограничением на вложенность доменов.

Нет такого ограничения. Смотрите внимательнее.
А где дотошность - это у вас надо спросить, как у автора.



Автор: Fortop 24.4.2008, 18:23
flashaa
smartov
Ну чего вы взъелись? smile завязывайте smile меня обе устраивают smile

Автор: SelenIT 24.4.2008, 18:27
flashaa, ошибка с двумя точками подряд была у CyClonа. У smartovа это было с самого начала предусмотрено.
Цитата(flashaa @  24.4.2008,  17:48 Найти цитируемый пост)
Нет такого ограничения.

Похоже, все-таки есть, только в http://www.wast2000.de/tcp/url.htm:
Цитата

host
        The fully qualified domain name of a network host, or its IP
        address as a set of four decimal digit groups separated by
        ".". Fully qualified domain names take the form as described
        in Section 3.5 of RFC 1034 [13] and Section 2.1 of RFC 1123
        [5]: a sequence of domain labels separated by ".", each domain
        label starting and ending with an alphanumerical character and
        possibly also containing "-" characters. The rightmost domain
        label will never start with a digit, though, which
        syntactically distinguishes all domain names from the IP
        addresses.

Автор: smartov 24.4.2008, 21:06
Цитата(flashaa @  24.4.2008,  17:48 Найти цитируемый пост)
Можно цитату?

Можно

Цитата

The character . provided that it is not the first nor last character in the local-part, nor may it appear two or more times consecutively.

http://en.wikipedia.org/wiki/E-mail_address

С тире в начале и конце высмотрел где-то в другом месте как распространенное ограничение. А с подчеркиваниями сам не знаю откуда взял, думаю надо внести в список разрешенных символов.

На самом деле, конечно, ограничения очень зависят от сервера. Об этом много написано даже на Википедии, например наличие того же знака + в адресе. GMail его разрешает, а Hotmail нет. 

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

Цитата(flashaa @  24.4.2008,  17:48 Найти цитируемый пост)
Не надо было править

Гражданин, мне в общем-то глубоко плевать веришь ты мне или нет, и ради Вашей Царской Персоны (далее ВЦП) и ненужного спора хранить пост я не собирался. 

Автор: flashaa 25.4.2008, 11:00
smartov, помоему это твоя ВЦП слишком многого хочет. 
"Анука расскажи мне чем там моя от твоей отличалась" 
Я вообще-то никому ничего рассказывать не обязан. А уж я отнесся черезчур уважительно походу. Ну чтож. Больше я так делать не буду. "Ваша регулярка ацтой" напишу я. И довольствуйтесь этим.

Ваша тема называется дотошная регулярка, а написано в ней было самое что ни на есть банальное рег. выр, необоснованное. Вот в чем беда.
Как я уже писал, спор это двое человек. Если спор не нужен, чтоже мы этот ненужный спор подогреваем, постим мне ругань и перешли на ты, а? Может начнем с себя в воспитании окружающих? Я вот лично это сделать могу. В отличии от оскорбленного критикой самолюбия великого неошибающегося smartov'a, чьи посты надо читать как аксиомы. Больше в этой теме я не пишу и радуйтесь восхищенным постам тех, кто "курит форумы" и создает темы "у меня ошибка, что делать!".

Автор: SelenIT 25.4.2008, 11:45
Цитата(smartov @  22.4.2008,  15:01 Найти цитируемый пост)
[a-zA-Z0-9]*([0-9a-zA-Z\-\_]+\.)*[0-9a-zA-Z]+\.

Фхтагн, а ведь теперь действительно пропустит "домен" ......1.com (я-то был уверен, что там повтор на весь фрагмент между точками стоит, даже не вчитывался)...

Вообще, ссылку на самую сабжевую регулярку дал ksnk, а самую практичную (имхо) привел source777 smile

Автор: smartov 25.4.2008, 17:18
Цитата(SelenIT @  25.4.2008,  11:45 Найти цитируемый пост)
Фхтагн, а ведь теперь действительно пропустит "домен" ......1.com (я-то был уверен, что там повтор на весь фрагмент между точками стоит, даже не вчитывался)...

Пропустит. 

Цитата(SelenIT @  25.4.2008,  11:45 Найти цитируемый пост)
самую практичную (имхо) привел source777

ХЗ. May be. В любом случае эта более точнаяя чем от source777, если нужна будет регулярка и писать ее не надо то не все ли равно на чем делать Ctrl+C, а если сабжевая дает чуть больше контроля - то почему бы и не её smile

Автор: source777 25.4.2008, 21:20
Цитата(smartov @  25.4.2008,  17:18 Найти цитируемый пост)
В любом случае эта более точнаяя чем от source777, если нужна будет регулярка и писать ее не надо то не все ли равно на чем делать Ctrl+C, а если сабжевая дает чуть больше контроля - то почему бы и не её smile 
Копировать конечно всё равно что, но вот только то, что ты возишься со своей регуляркой уже 2 дня не дало ей этих самых "чуть больше контроля", например, мыло name@mail-.ru.net или abc.@1.ru твоя регулярка считает правильными, а моя - нет... Хотя в моей регулярке также есть недочёты, но это и понятно, учитывая что я её 5 минут писал, а не 2 дня... зато получилось как говорится быстро и сердито, хотя можно её дополнить до чего-нить типа 
^([a-z0-9][a-z0-9-]*[a-z0-9]\.?)*[a-z0-9]@([a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)+[a-z]{2,6}$

P.S. Степень контроля можно увеличивать до тех самых пор, пока регулярка не займёт полэкрана, тут самое главное вовремя вспомнить такое понятие как "достаточно", ведь чем длиннее регэксп, тем медленнее он будет обрабатываться...


Автор: smartov 25.4.2008, 23:24
Цитата(source777 @  25.4.2008,  21:20 Найти цитируемый пост)
твоя регулярка считает правильными

Второе нет.

Цитата(source777 @  25.4.2008,  21:20 Найти цитируемый пост)
но это и понятно, учитывая что я её 5 минут писал, а не 2 дня...

Ты меня за дебила считаешь? Я 10 минут потратил


Автор: bugmenot 29.5.2008, 15:04
А ведь такой имейл тоже валидный:
me@127.0.0.1

Автор: maxbrown 17.6.2008, 19:13
Ээ... Граждане, а может, начать стоит с описания формата e-mail адреса по RFC822?
Код

6.  ADDRESS SPECIFICATION
6.1.  SYNTAX
address     =  mailbox                      ; one addressee
            /  group                        ; named list
group       =  phrase ":" [#mailbox] ";"
mailbox     =  addr-spec                    ; simple address
            /  phrase route-addr            ; name & addr-spec
route-addr  =  "<" [route] addr-spec ">"
route       =  1#("@" domain) ":"           ; path-relative
addr-spec   =  local-part "@" domain        ; global address
local-part  =  word *("." word)             ; uninterpreted
                                            ; case-preserved
domain      =  sub-domain *("." sub-domain)
sub-domain  =  domain-ref / domain-literal
domain-ref  =  atom                         ; symbolic reference

Автор: Sanchezzz 25.6.2008, 11:13
/\w+@\w+\.\w{2,6}/





Автор: nerezus 12.7.2008, 14:11
Sanchezzz, в рот тебе ноги. После стольких страниц постить такое Г... додумался блин...
множесто нормальных рабочих мейлов такой "валидации" не выдержит.

Автор: americanets 14.7.2008, 16:55
filter_var + FILTER_VALIDATE_EMAIL для php  > 5.2

Автор: smartov 14.7.2008, 17:38
americanets, вротмненоги! Век живи век учись! Держи плюса.

Автор: unicross 17.1.2009, 15:04
Русские буквы в адресе E-mail функция filter_var() считает допустимыми. На мой взгляд это косяк...
E-mail привет@mail.ru врядли будет существовать...

Автор: theworldcreator 17.1.2009, 19:25
Код

function test_mail($mail){
      if(preg_match('/[а-я]/i', $mail)) return false;
      return filter_var($mail, FILTER_VALIDATE_EMAIL);
}

То-есть это — самая дотошная проверка?

Автор: unicross 17.1.2009, 21:09
theworldcreator, немного добавлю и кое-что изменю:
Код

function test_mail( $mail ) {
   if ( preg_match('/[а-яё]/i', $mail) ) return false;
   if ( filter_var($mail, FILTER_VALIDATE_EMAIL) === false ) return false;
   if ( preg_match('/\.[a-z]{2,6}$/i', $mail) ) return true;
   else return false;
}


Автор: theworldcreator 18.1.2009, 11:36
Спасибо. Самым большим откровением стало отсутствие ё в перечисление а-я. Причем только что проверил — range('а', 'я') тоже его не включает.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)