Pull to refresh

Comments 93

Вещь полезная, но «смерть регуляркам» — громко сказано: они годятся только для валидации.
Вероятно, внутренняя реализация этих фильтров всё же сводится к прекомпилированному регекспу :-)
По сути не «смерть регуляркам», а «инкапсулируйте свой код». Никто не мешал и до этого на системном слое приложения написать свою функцию validateEmail, которая внутри содержит правильный регексп, и использовать эту функцию, где надо, а не писать регекспы в бизнес-логике. Тогда с появлением кириллических доменов вы патчите свою функцию и радуетесь жизни дальше. PHP просто предоставил предопределённый набор функций. Почему нет, но причём здесь регекспы?
Кстати о регекспах на email, случайно не копались в исходниках Swift mailer? ;)
упс… уже писали :)
никогда не понимал этого фанатизма с проверкой в соответствии с RFC.
имхо, такой фильтр должен пропускать все, что корректно поймет программа, которой мы дальше этот адрес передаем (sendmail, например).

пример: при установке локально всяких движков (для тестирования), требующих email вбиваю адрес admin@localhost
возможно, он «расово неправильный», но отправленное туда через mail() письмо прекрасно доходит куда мне надо.
но некоторые «особо умные» скрипты на это начинают ругаться.
другой пример: новые зоны первого уровня, тот же рф.

проверка все же должна помогать пользователю (что он в поле email нечаянно не ввел что-то другое), а не мешать.
А что не так с admin@localhost?
Здесь «пропускает» значит «позволяет».
admin@localhost — нормальный адрес по мнению модуля Mail::RFC822::Address.
Я это понимаю.
А этот адрес «ненормальный»?
PHP говорит что ненормальный

php -r 'var_dump(filter_var("admin@localhost", FILTER_VALIDATE_EMAIL));'
bool(false)
Ну пхп можно ещё простить. Но мой комментарий адресовался изначально OlegTar, который, судя по его комментарию, считает, что этот адрес невалидный.
Я не считаю этот адрес невалидным.
А, тогда пардон, показалось :-)
Всё так, я не против этого адреса. Просто zibada думал, что возможно RFC822 его не пропускает.
Так именно по этой причине и надо соответствовать RFC, а не своим догадкам какой email может быть. Мне уже далеко не раз приходилось доделывать чужую валидацию (email'ов в том числе), потому что предыдущий программист считает, что RFC — это для зануд. Перед ем как работать со стандартами — ВСЕГДА почитай сначала RFC!
Пхп далеко… интересно, а такой фильтр:
$var = 'mail@example.com';
var_dump(filter_var($var, FILTER_VALIDATE_EMAIL));

на e-mail: «медведев@президент.рф» споткнется? Т.е. он адекватно кушает utf-8 и предполагает наличие других языков вообще?
shock@localhost:~> php -r "var_dump(filter_var('медведев@президент.рф', FILTER_VALIDATE_EMAIL));"
bool(false)
shock@localhost:~> php -v
PHP 5.3.2 (cli)
Copyright © 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright © 1998-2010 Zend Technologies

К счастью, споткнулся)
К чьему, блин, счастью то? Вам клиент\начальник скажет — хочу поддержку кириллических доменов и никуда вы не денетесь. Еба**ся придется как всегда технарям…
за его деньги — хоть китайские
сконвертить в xn-- это просто ну архисложная задача, да…
Действительно, ведь и через почтовик нельзя отправить письмо на медведев@президент.рф
В любом случае сначала в punycode.
Голову на отсечение даю, что споткнется!
в случае с РНР можно за голову не волноваться.
вообще-то в адресе запрещены не ascii символы, так что с русским еще предстоит поиметь секса.
Validates value as URL (according to » www.faqs.org/rfcs/rfc2396), optionally with required components. Note that the function will only find ASCII URLs to be valid; internationalized domain names (containing non-ASCII characters) will fail.
Раз уж смерть регуляркам — было бы классно если бы вы показали сравнение по скорости например этого email фильтра и регулярного выражения.
Регулярки — это как секс с настоящей женщиной, фильтры — как секс с женщиной резиновой. :)
И никаких сравнений скорости не надо. :)
UFO just landed and posted this here
Зато когда финал… :))
смерть регуляркам означает что мы останемся без секса? (:
по скооорости?
это разве-что для спамбота актуально. неужели вы проверяете тысячи email адресов в секунду? или откуда эта забота о скорости?

мне кажеться, что на проверку ВСЕХ email адресов в небольшом проекте на несколько десятков тысяч юзеров (ха!) уйдет меньше времени, чем вы потратили на прочтение этого комментария.
Вы бы в код глянули, прежде чем писать
void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
  /* From cvs.php.net/co.php/pear/HTML_QuickForm/QuickForm/Rule/Email.php?r=1.4 */
  const char regexp[] = "/^((\\\"[^\\\"\\f\\n\\r\\t\\b]+\\\")|([A-Za-z0-9_][A-Za-z0-9_\\!\\#\\$\\%\\&\\'\\*\\+\\-\\~\\/\\=\\?\\^\\`\\|\\{\\}]*(\\.[A-Za-z0-9_\\!\\#\\$\\%\\&\\'\\*\\+\\-\\~\\/\\=\\?\\^\\`\\|\\{\\}]*)*))@((\\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9])(([A-Za-z0-9\\-])*([A-Za-z0-9]))?(\\.(?=[A-Za-z0-9\\-]))?)+[A-Za-z]+))$/D";

  pcre    *re = NULL;
  pcre_extra *pcre_extra = NULL;
  int preg_options = 0;
  int     ovector[150]; /* Needs to be a multiple of 3 */
  int     matches;

  re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
  if (!re) {
    RETURN_VALIDATION_FAILED
  }
  matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);

  /* 0 means that the vector is too small to hold all the captured substring offsets */
  if (matches < 0) {
    RETURN_VALIDATION_FAILED
  }

}

* This source code was highlighted with Source Code Highlighter.

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

PS: объем regex'a доставляет))
писец))
а что она проверяет?
Другие регулярные выражения.
а проходит само проверку=)?
Она проверяет валидность email по RFC. И, говорят, не 100% точно.
UFO just landed and posted this here
Ну да, как я и подозревал. А регексп злой, да. Я не сразу понял, что мрачный кусок с цифрами в середине матчит айпишники, причём следит, чтобы не подсунули цифры больше 255.
Может здесь проверяются мыла только вида name@domain только.

по RFC 822, ведь проходят ещё такие мыла:

«user» <user@domain>
И ещё такие.
Wilt. (the Stilt) Chamberlain@NBA.US
Cruisers: Port@Portugal, Jones@SEA;
$@[]
*()@[]
«quoted ( brackets» ( a comment )@example.com
/^((\"[^\"\f\n\r\t\b]+\")|([A-Za-z0-9_][A-Za-z0-9_\!\#\$\%\&\'\*\+\-\~\/\=\?\^\`\|\{\}]*(\.[A-Za-z0-9_\!\#\$\%\&\'\*\+\-\~\/\=\?\^\`\|\{\}]*)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9])(([A-Za-z0-9\-])*([A-Za-z0-9]))?(\.(?=[A-Za-z0-9\-]))?)+[A-Za-z]+))$/

В начале зачем-то вставили поддержку кавычек, типа «mailbox»@example.org, причем в кавычки можно впихать что угодно.
Без кавычек тоже забавные варианты имеются, типа _@example.org и _........@example.org
Про IP тут уже говорили — вроде как умеет user@[1.2.3.4] так и user@1.2.3.4. Соответственно больше 255 нельзя вписать, но 0.0.0.0 и 255.255.255.255 или 239.0.0.1 такие же невалидные адреса.

При этом регэксп недоделанный. Местами * вместо + стоит. Зачем-то повторили 8 раз комбинацию цифр для IP, когда можно было бы сделать 2 раза.
А чем плох адрес _@example.org?
Если допускается в имени "_", то может быть имя из одного этого символа.

Насчёт 255.255.255.255 не знаю… Не регулярское это дело, её дело проверять только форму записи.
Проблема не в том что регулярка пропускает такие IP адреса, проблема в том что их пропускает фильтр.

Адрес плох тем что он не существует. Я обычно требую хотя бы одну букво-цифру между знаками в имени пользователя. Была сделана попытка с точкой, но кривая.
По контрасту в имени домена таких проблем нет, видимо стырили.
ну вот хочу я, например, получить список всех ссылок на странице…
через фильтры этого не сделать,
либо делать html валидным xhtml и далее искать через xpath,
либо старым проверенным способом — через регулярные выражения

так что заголовок сильно отдает желтизной
По моему речь идет о использованию регулярок в фильтрах а не вообще
я обычно через DOM делаю, особых граблей (грабель… тьфу, да какая к черту разница, пятница сегодня) не встречал.
если не сложно, хотелось бы краткую реализацию поиска по DOM с помощью PHP. спасибо :)
$dom = new DOMDocument();
$dom->loadHTML( $html) ;
$anchors = $dom->getElementsByTagName("a");
foreach ($anchors as $anchor) {
	$href = $anchor->getAttribute("href");
	....
}
ну что вы
вот здесь описывается как с помощью DOMDocument->getElementsByTagName() найти все ссылки те же. без задумывания о регулярках.

нехай компутер думает у него голова для этого больше заточена
А по теме, действительно, писать смерть регуляркам очень громко.
Даже в самой filter_var() есть параметр FILTER_VALIDATE_REGEXP
тоже сразу подумал про этот фильтр.
На самом деле довольно часто приходится его использовать при нестандартных запросах.
Читайте в следующем номере:
Регулярки: смерть фильтрам и правильная валидация!
:-)
а почему не упомянули про filter_input? это как раз тоже важно
UFO just landed and posted this here
UFO just landed and posted this here
Никуда не годные эти фильтры
$var = "#mail@example.com";
var_dump(filter_var($var, FILTER_VALIDATE_EMAIL));

выводит false, а ведь "#mail@example.com" — корректный адрес электронной почты согласно RFC 3696
Там в регулярке что внутри сидит, первой должна быть буква-цифра-подчерк. Дальше по списку разрешенных симоволов.
Либо имя юзера в кавычках ( не помню — так можно по RFC? )
У меня уже есть готовый класс с набором статических методов, таких как Validator::isEmail($var); И если заказчик попросит дописать поддержку кирилических доменов, то я допишу. А с filter_var() я что делать буду?

Кроме того в этих ПХП-фильтрах нет очень нужных фильтров: isDate(), isTime(), isDateTime(), isPhone(), isMoney()

Если их ф-ция окажется лучше моей, то я могу в тело своей ф-ции вставить вызов filter_var(). А вот обратно — никак.
Дата и время, валюта — зависят от локали, страны и языка.
1. Формат времени точно не зависит от локали. Везде «HH:mm:ss». Хотя секунд может не быть.
2. Самый часто используемый формат — тот который в БД DATE: «ГГГГ-ММ-ДД». Любой DatePicker можно настроить. А сепаратор принимать в качестве аргумента. У меня Validator::isDate($var, $separator='-');
3. php.net/manual/en/function.setlocale.php

Короче, слабоваты эти встроенные ф-ции.
>а может просто мануал плохо читали

а может потому, что ман на эти фильтры Кэп, причем ленивый. Особенности работы не расписаны, мне вот проще самому написать, чем лезть в сорцы и парсить чужой бред.
Задумка неплохая, но получился кривой черный ящик. Умилило примечание в мане:
Numbers +0 and -0 are not valid integers but validate as floats

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

Так что в печь такие фильтры.
UFO just landed and posted this here
Хотел как-то написать подобный топик, но вы опередили. Молодец, что подняли тему.

Ну и понятно, что регекспам не смерть: самописные функции и валидаторы включают произвольную логику, среди которой запросто могут затесаться регекспы :)
Исправили бы досадные описки, просто перечитайте свою статью и поймете:)
Уже краем глаза видел. Спасибо, как раз есть где опробовать)
Пытался использовать. Имхо — не удобно. Гораздо удобнее и приятнее собственные классы для валидации.
А разбираться в чужом коде, как и писали выше, не всегда есть желание и время.
Ээ, встроенные функции расширения языка хуже самописного кода? Очень спорно. Равно как и забивать на мануал по языку.

Но понятно, что если нет валидации и фильтра под конкретный тип и формат данных — придется писать свои валидатор и фильтр. Но изобретать велосипеды — т.е. придумывать заново то, что уже написано до вас (без определенной оправдывающей цели с вашей стороны) — как-то нерационально.
Интересная фича, но наверное придумана больше — для легкого изучения пхп новичками. Ясное дело тот кто (хотябы пол-года пишет сайт) способен написать свою валидацию — не будет рисковать и использовать эту, т к понятно(точнее непонятно) в какие бока это может вылезти потом.
UFO just landed and posted this here
filter_* по-моему полезен не столько для проверки входных параметров на соответствие определенному RFC или узкому типу данных, сколько для отрезания html-тэгов (с потенциальным XSS) в тривиальном тексте. То есть, это такой шаг в сторону мысли «фильтровать данные из браузера — это хороший тон и все такое», а вовсе не про регулярные выражения. Хотя даже тут могут быть проблемы, конечно.

Если речь идет о фреймворках, которые позволяют вызывать методы кода в зависимости от браузерного запроса, то как раз там важно, чтобы аргументы методов фильтровались самим фреймворком, а разработчик был вынужден указывать по какому типу фильтра, что какбе намекнет ему, что без фильтров теперь не принято.
ололо… очередной топик из серии «смотрите, я прочитал мануал!»…
почему такое пропускает?
var_dump(filter_var('http://aaa<&gt', FILTER_VALIDATE_URL)); //string(12) «aaa<&gt»
Смотрите RFC2068

unsafe = CTL | SP | <"> | "#" | "%" | "<" | ">"

Characters other than those in the "reserved" and "unsafe" sets (see
section 3.2) are equivalent to their ""%" HEX HEX" encodings.
Особенно напрягают «валидаторы» у которых не проходит email со знаком "+". типа «mail+sometext@example.com» чтоб проще выяснить откуда спам сыпется…
Кстати, интересная идея :) У вас еще не набралась статистика тех, кто сливает или допускает слив email?
пробовал, в некоторых случаях удобно
но к сожалению, например, валидация по урлу как-то криво реализована, пользуюсь своей регуляркой
бывают достаточно тонкие моменты, где работать с «черным ящиком» в виде filter_validate не приемлемо
Юзаю уже несколько лет Zend Framework. Там реализованы и валидаторы, и фильтры, есть набор с десяток дефолтных плюс своих написано порядком уже.
Фильтры данных впервые появились в PHP 5.0, и по какому-то стечению обстоятельств остались незамечеными большй частью кодеров.

Мануал по фильтрам находится здесь

Вообще-то, по данной же ссылке документации PHP указывается, что все функции Data Filtering:
PHP 5 >= 5.2.0
а не 5.0
Sign up to leave a comment.

Articles