Класс Validator для валидации POST данных. Валидация и очистка данных средствами PHP Безбрежный validation php

Почти всем интерактивные веб-приложения необходимо проверить вводимые данные. Например, в регистрационной форме, вероятно, потребует пароль для подтверждения. Может быть, адрес электронной почты должен быть уникальным. Проверка данных может быть громоздким процессом. К счастью,только не в Laravel.Класс Validator обеспечивает удивительный набор помощников для проверки, максимально облегчая проверку данных. Давайте рассмотрим пример:

Получение массива данных для валидации:

$input = Input::all();

Определение правил валидации данных:

$rules = array("name" => "required|max:50", "email" => "required|email|unique:users",);

Создание экземпляра Validator и валидация данных:

$validation = Validator::make($input, $rules); if ($validation->fails()) { return $validation->errors; }

При наличии свойства errors вы получаете доступ к сборщику сообщений, позволяющему легко создавать свои сообщения об ошибках. Конечно же, все правила валидации имеют соощения об ошибках по умолчанию. Стандартные сообщения об ошибках находятся в language/en/validation.php .

Теперь вы знакомы с основными правилами использования класса Validator. Вы готовы к исследованию и изучению правил используемых для проверки ваших данных!

Правила валидации

Обязательные данные

Проверка на обязательное не пустое значение параметра:

"name" => "required"

Alpha, Alpha Numeric, & Alpha Dash

Проверка на наличие только букв:

"name" => "alpha"

Проверка на наличие только букв и цифр:

"username" => "alpha_num"

Проверка на наличие только букв, цифр, тире и символа подчеркивания:

"username" => "alpha_dash"

Размер

Проверка на размер строки строчного атрибута, или диапазон значений числового атрибута:

"name" => "size:10"

Проверка на диапазон значений:

"payment" => "between:10,50"

Примечание: Минимум и максимум включены в диапазон.

Проверка минимального размера атрибута:

"payment" => "min:10"

Проверка максимального размера атрибута:

"payment" => "max:50"

Числовые типы

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

"payment" => "numeric"

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

"payment" => "integer"

Вхождения и исключения

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

"size" => "in:small,medium,large"

Проверка атрибута на исключение из массива значений:

"language" => "not_in:cobol,assembler"

Подтверждение

Правило confirmed проверяет, что для данного атрибута есть соответствующее подтверждение * attribute_confirmation *.

Проверка атрибута на подтверждение:

"password" => "confirmed"

В этом примере Validator проверяет, что параметр password удовлетворяет условиям password_confirmation из массива валидации.

Акцептирование

Правило accepted проверяет параметр на значение yes или 1 . Это правило проверяет установку обязательных чекбоксов, таких, как, например, флажок согласия с "Условиями предоставления услуг".

Проверка акцептирования:

"terms" => "accepted"

Соответствия и различия

Проверка, что атрибут такой же как, и сравниваемый другой артибут:

"token1" => "same:token2"

Проверка на то, что атрибут имеет разное значение:

"password" => "different:old_password",

Регулярные выражения

Правило match проверяет атрибут на удовлетворение регулярному выражению.

Поверка на удовлетворение регулярному выражению:

"username" => "match:/+/";

Уникальность и существование

Проверка параметра на уникальность в базе данных:

"email" => "unique:users"

В этом примере параметр email проверяется на уникальность в таблице users . Необходимо проверить уникальность атрибута другого столбца, кроме этого? Нет проблем:

Указание другого столбца для проверки:

"email" => "unique:users,email_address"

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

Игнорирование указанного ID:

"email" => "unique:users,email_address,10"

Проверка на наличие атрибута в указанной базе данных:

"state" => "exists:states"

Указание имени столбца для правила exists:

"state" => "exists:states,abbreviation"

Даты

Проверка того, что параметр даты имеет значение до...:

"birthdate" => "before:1986-28-05";

Проверка того, что параметр даты имеет значение после...:

"birthdate" => "after:1986-28-05";

Примечание: Проверка before и after использует функцию PHP strtotime .

E-Mail адреса

Проверка того, что параметр является E-Mail адресом:

"address" => "email"

Примечание: Это правило использует встроенный в PHP метод filter_var .

URLs

Проверка того, что параметр есть URL:

"link" => "url"

Проверка того, что параметр есть активный URL:

"link" => "active_url"

Примечание: Правило active_url используетs checkdnsr для проверки активности URL.

Загрузки

Правила mimes проверяют, что загружаемый файл соответствует MIME типу. Это правило использует расширение PHP Fileinfo проверяющее содержимое файла и определяющее его тип. Любые расширения файлов, применимые к этому правилу, определяются в config/mimes.php .

Проверка принадлежности файла определенному типу:

"picture" => "mimes:jpg,gif"

Примечание: При проверке не забудьте использовать Input::file() или Input::all().

Проверка того, что файл изображение:

"picture" => "image"

Проверка на размер файла:

"picture" => "image|max:100"

Запрос сообщения об ошибке

Laravel позволяет работать с сообщениями об ошибках с помощью простого класса - сборщика ошибок. После вызова методов passes или fails экземпляра Validator, вы можете получить доступ к ошибке при помощи свойства errors . Сборщик ошибок имеет простые функции для запроса сообщений об ошибках:

Определение, что атрибут имеет сообщение об ошибке:

if ($validation->errors->has("email")) { // The e-mail attribute has errors... }

Запрос первого сообщения об ошибке для атрибута:

echo $validation->errors->first("email");

Вам может понадобиться обернуть ваше сообщение об ошибке в HTML тэги. Нет проблем. Вызывая:message place-holder, определите формат вторым параметром метода.

Форматирование сообщения об ошибке:

echo $validation->errors->first("email", "");

Получение всех сообщений об ошибках для атрибута:

$messages = $validation->errors->get("email");

Форматирование всех сообщений об ошибках для аттрибута:

$messages = $validation->errors->get("email", "");

Получение всех сообщений об ошибках для всех атрибутов:

$messages = $validation->errors->all();

Форматирование всех сообщений об ошибках для всех атрибутов:

$messages = $validation->errors->all("");

Прохождение валидации

После того как вы выполнили вашу проверку, нужен простой способ отображения ошибок в представлении. Laravel делает его очень легко. Давайте рассмотрим типичный сценарий. Это может быть определено двумя путями:

Route::get("register", function() { return View::make("user.register"); }); Route::post("register", function() { $rules = array(...); $validation = Validator::make(Input::all(), $rules); if ($validation->fails()) { return Redirect::to("register")->with_errors($validation); } });

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

Но, обратите внимание, мы явно не связываем ошибки с целью в нашем GET маршруте . Тем не менее, переменная ошибки будет доступна в представлении. Laravel разумно определяет, есть ли ошибки в работе сессии, и если они есть, присоединяет сообщения к представлению. Если ошибок нет, пустой контейнер сообщения об ошибке все равно будет присоединен к представлению. В представлении всегда будет доступен контейнер сообщений об ошибках. Нам нравится облегчать вам жизнь.

Пользовательские сообщения об ошибках

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

Создание массива собственных сообщений об ошибках для Validator:

$messages = array("required" => "The:attribute field is required.",); $validation = Validator::make(Input::get(), $rules, $messages);

Отлично! Теперь наши пользовательских сообщения будет использоваться всегда при проверке. Но, что за выражение :attribute в нашем сообщении. Для облегчения вашей жизни, класс Validator заменяет :attribute на атрибут, ввод которго вызвал ошибку. Он даже удалит символ подчеркивания из имени атрибута. Вы также можете использовать :other , :size , :min , :max , и :values заполнители для конструирования ваших сообщений об ошибках.

Примеры пользовательских сообщений об ошибках:

$messages = array("same" => "The:attribute and:other must match.", "size" => "The:attribute must be exactly:size.", "between" => "The:attribute must be between:min - :max.", "in" => "The:attribute must be one of the following types: :values",);

Что, если вам нужно определить необходимое сообщение, но только для атрибута электронной почты? Без проблем. Просто укажите сообщение, используя attribute_rule именование:

Определение сообщения для конктретного атрибута:

$messages = array("email_required" => "We need to know your e-mail address!",);

В данном примере, пользовательское сообщение об ошибке будет использовано только для атрибута email, в остальных случаях будут использоваться стандартные сообщения.

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

Добавление собственного массива в языковый файл:

"custom" => array("email_required" => "We need to know your e-mail address!",)

Собственные правила валидации

Laravel предоставляет ряд мощных правил проверки. Тем не менее, вы можете создать свои собственные. Есть два простых способа создания правил проверки. И тот и другой надежны в использовании. Вам остается только выбрать более подходящий для вашего проекта.

Регистрация собственного валидационного правила:

Validator::register("awesome", function($attribute, $value, $parameters) { return $value == "awesome"; });

В этом примере мы зарегистрировали новые правила проверки для класса Validator. Это правило получает три параметра. Во-первых, это имя проверяемого атрибута, второй - значение проверяемого атрибута, а третий представляет собой массив из параметров, которые были заданы для правила.

Так выглядит вызов вашего правила:

$rules = array("username" => "required|awesome",);

Конечно, вам нужно определить сообщение об ошибке для нового правила. Вы можете сделать это либо в специальных сообщениях массива:

$messages = array("awesome" => "The attribute value must be awesome!",); $validator = Validator::make(Input::get(), $rules, $messages);

или, добавив запись для правила в language/en/validation.php :

"awesome" => "The attribute value must be awesome!",

Как уже упоминалось выше, вы даже можете указать и получить список параметров в пользовательском правиле:

// При построении правила... $rules = array("username" => "required|awesome:yes",); // В правиле... Validator::register("awesome", function($attribute, $value, $parameters) { return $value == $parameters; }

В данном примере параметр аргументов вашего правила проверки будет получать массив, содержащий один элемент: "да".

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

Сначала, создаете класс Validator который наследует класс Laravel\Validator и размещаете его в application/libraries :

Определение собственного класса:

Теперь, добавим наше правило "awesome" и определим его в новом классе:

Добавление нового правила:

Обратите внимание, что метод validate_awesom именуется согласно соглашению имен. Т.е. для правила "awesome" метод должен иметь имя "validate_awesome". Это один из многих способов расширения класса Validator. Класс Validator просто требует возврата значения "true" или "false". И все!

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


В предыдущей статье я обещал написать сравнение своей собственной библиотеки с другими имеющимися решениями, так что сегодня мы рассмотрим валидацию с помощью Aura.Filter , Respect Validation , Sirius Validation и Valitron .


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

  1. name. Должно содержать ровно два слова, где первое - имя пользователя, а второе - фамилия.
  2. login. Если значение передано, то оно должно только латинские буквы, дефисы и нижнее подчеркивание.
  3. email. Должно содержать валидный адрес электронной почты.
  4. password. Должен быть установлен и иметь длину не более 64 символов.
  5. agreed. Типичный флажок, который пользователь должен установить, чтобы подтвердить своё согласие с условиями сервиса.

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


$data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" =>

Aura.Filter

Валидация с использованием Aura.Filter начинается с фабрики фильтров. Нам необходимо создать так называемый «фильтр субъекта», так как мы будет валидировать массив, а не индивидуальное значение.

Определяем правила

use Aura\Filter\FilterFactory; $filter = (new FilterFactory)->newSubjectFilter(); $filter->validate("name") ->isNotBlank() ->is("two_words") ->setMessage("Имя должно состоять из двух слов."); $filter->validate("login") ->isBlankOr("alnum") ->setMessage("Если вы указываете логин, он должен содержать только латинские символы."); $filter->validate("email") ->isNotBlank() ->is("email") ->setMessage("Пожалуйста, напишите корректный адрес эл. почты."); $filter->validate("password") ->isNotBlank() ->is("strlenMax", 64) ->setMessage("Пожалуйста, напишите пароль."); $filter->validate("agreed") ->is("callback", function($subject, $field) { return $subject->{$field} === true; })->setMessage("Вам необходимо согласиться с условиями сервиса.");

Как видите, описание правил достаточно простое. Aura.Filter предоставляет целый набор полезных правил «из коробки» и некоторые из них были использованы в примере выше:

  1. метод isNotBlank. Указывает, что поле не может иметь пустое значение.
  2. alnum. Это правило допускает только латинские буквы.
  3. email. И так понятно:)
  4. strlenMax. Указывает, что поле не может превышать длину, указанную вторым аргументом метода is .
  5. callback. Этот тип правила похож на замыкания из Kontrolio. Он позволяет определить правило в виде замыкания. В это замыкание Aura.Filter передает «субъект», наш массив данных из формы, и поле, в данном случае agreed .

Наверняка вы заметили, что я не указал правило two_words . Естественно, в Aura.Filter такого правила нет, поэтому нам необходимо его создать. Как гласит документация, это делается с помощью отдельного класса для правила:


/** * Правило, которое валидирует имя пользователя. * Имя пользователя состоит из двух слов: имени и фамилии, разделенных одним пробелом. */ class UserNameRule { /** * Валидирует имя пользователя. * * @param object|array $subject * @param string $field * @param int $max * * @return bool */ public function __invoke($subject, $field, $max = null) { $value = $subject->{$field}; if (! is_scalar($value)) { return false; } return (bool) preg_match("/^+\s+$/u", $value); } }

The second step is to let the filter factory know about our new rule. It’s done by passing the first argument as an array of rules to the filter factory:


Следущий шаг - уведомить Aura.Filter о том, что мы создали новое правило и хотим его использовать. Это делается с помощью передачи массива правил в первый аргумент фабрики:


use Aura\Filter\FilterFactory; $rules = [ "two_words" => function() { return new UserNameRule; } ]; $filter = (new FilterFactory($rules))->newSubjectFilter();

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

Обратная связь

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


Валидируем с Aura.Filter мы следующим образом:


$valid = $filter->apply($data); if (! $valid) { $failures = $filter->getFailures(); $messages = $failures->getMessages(); }

В $messages записывается массив, поэтому для вывода сообщений нам потребуется два вложенных foreach:


    $errors) { foreach ($errors as $error) { printf("", $error); } } ?>

Respect Validation

Вторая библиотека, использованная мной в сравнении, - относительно популярное решение под названием Respect Validation . Раз люди ей доверяют, думаю, там есть что посмотреть.


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


use Respect\Validation\Validator as v; $data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" => "" // Пароль вообще не указан // "agreed" нет в массиве, потому что пользователь не установил флажок ];

Определяем правила

Как и в случае с Aura.Filter, нам необходимо собственное правило валидации для имени пользователя, поэтому давайте с него и начнем:


namespace MyNamespace; use Respect\Validation\Rules\AbstractRule; class UserNameRule extends AbstractRule { public function validate($input) { return (bool) preg_match("/^+\s+$/u", $input); } }

Внешнее API правил практически идентично Aura.Filter, только используется метод validate() вместо магии __invoke(). Мне оно, это API, показалось более простым и понятным. Ну, и к Kontrolio оно ближе:)


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


use Respect\Validation\Exceptions\NestedValidationException; class UserNameRuleException extends NestedValidationException { // }

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


v::with("MyNamespace\\");

Теперь все нестандартные правила, находящиеся в пространстве имен MyNamespace , будут «опознаны» валидатором. Следующий шаг - описать необходимые правила и выполнить валидацию.


v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) ->attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data);

Обратите внимание на то, как мы применяем наше правило к атрибуту name . Здесь название класса правило трансформировалось в название метода валидатора. Остальные правила, в общем-то, интуитивно понятны.


Отдельно стоит сказать о том, зачем мы приводим массив $data к объекту. Дело в том, что Respect Validation принимает на вход объекты, а не массивы. Это следует учесть при разработке с использованием данной библиотеки.

Обратная связь

В отличие от Aura.Filter валидатор Respect выбрасывает исключение, когда валидация провалена. И в этом исключении содержатся сообщения об ошибках валидации. Поэтому пример, который только что был показан, должен быть записан следующим образом:


try { v::with("RespectValidationExample\\"); v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) ->attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data); } catch (NestedValidationException $ex) { $messages = $ex->getMessages(); }

Используя getMessages() , мы получим плоский массив всех сообщений, который валидатор собрал в процессе валидации. Задампив массив, мы получим примерно такой результат:


array(5) { => string(29) “Data validation failed for %s” => string(60) “login must contain only letters (a-z), digits (0–9) and “-_”” => string(25) “email must be valid email” => string(26) “password must not be empty” => string(32) “Attribute agreed must be present” }

Можно поменять сообщения на свои собственные. Возможно, я как-то не так понял эту библиотеку, но мне этот процесс не показался таким уж очевидным: необходимо использовать метод findMessages() на обработанном исключении, в котором вы определяете сообщения не для атрибутов, а для правил.


$ex->findMessages([ "userNameRule" => "Имя пользователя должно состоять из двух слов.", "alnum" => "Ваш логин нам не нравится.", "email" => "Вы явно не хотите давать нам свой e-mail.", "notEmpty" => "Ну и где же ваш пароль?", "agreed" => "Жаль, что вы не согласны." ]);

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


array(5) { => string(40) “Имя пользователя должно состоять из двух слов.” => string(31) “Ваш логин нам не нравится.” => string(25) “email must be valid email” => string(5) “Ну и где же ваш пароль?” => string(9) “Жаль, что вы не согласны.” }

Как видите, сообщение для поля электронной почты не применилось, осталось стандартное. А вот сообщение за индексом 4 наоборот! И это при том, что я использовал не название правила, а название поля. В то время как если бы я использовал название правила (trueVal), моё сообщение бы куда-то затерялось. Комментарии опытных пользователей данной библиотеки очень приветствуются.

Sirius Validation

Ок, давайте перейдем к следующей библиотеке и посмотрим, как она справится со схожими задачами.

Определяем правила

И снова нам необходимо определить правило для имени пользователя. Мы его напишем как-то так:


class UserNameRule extends AbstractRule { // Сообщения об ошибках const MESSAGE = "Имя пользователя должно состоять из двух слов."; const LABELED_MESSAGE = "{label} должно состоять из двух слов."; public function validate($value, $valueIdentifier = null) { return (bool) preg_match("/^+\s+$/u", $value); } }

Обратите внимание на разницу в подходах в сравнении с уже рассмотренными библиотеками. Мы определяем два вида сообщений в константах, нежели используя свойства, методы или аргументы правила.


Теперь давайте опишем логику валидации:


$validator = new Validator; $validator ->add("name", "required | MyApp\Validation\Rule\UserNameRule") ->add("login", "required | alphanumhyphen", null, "Логин может содержать только латинские буквы, черточки и подчеркивания.") ->add("email", "required | email", null, "Пожалуйста, укажите корректный e-mail.") ->add("password", "required | maxlength(64)", null, "Ваш пароль, сударь.") ->add("agree", "required | equal(true)", null, "Почему же вы не согласились?");

Как видите, набор правил весьма прост и читабелен. Для описания мы используем названия, разделенные горизонтальными черточками. Этот подход похож на тот, что используется в Laravel и Kontrolio.


Четвертый аргумент метода add() описывает сообщение об ошибке валидации, которое Sirius использует, если валидация будет провалена. А почему же мы не добавили сообщение для нашего нового правила UserNameRule ?


$validator->add("name", "required | MyApp\Validation\Rule\UserNameRule")

Так это потому, что сообщения уже описаны в константах класса:


class UserNameRule extends AbstractRule { // Сообщения об ошибках const MESSAGE = "Имя пользователя должно состоять из двух слов."; ...

Другой вариант - использовать метод addMessage() самого валидатора:


$validator->addMessage("email", "Пожалуйста, укажите корректный e-mail.");

Обратите внимание, что кастомные правила идентифицируются по полному названию их класса, в то время как в Kontrolio можно задать псевдоним/алиас.

Обратная связь

Чтобы выполнить валидацию, мы вызываем метод валидатора validate() , передавая в него данные:


$data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" => "" // Пароль вообще не указан // "agreed" нет в массиве, потому что пользователь не установил флажок ]; $validator->validate($data);

В отличие от Respect, Sirius не выкинет исключение, а просто вернет false . Сообщения об ошибках валидации можно получить через метод валидатора getMessages() . Он возвращает ошибки, сгруппированные по атрибутам, так что для прохода по ошибкам нам понадобится два цикла foreach:


foreach ($validator->getMessages() as $attribute => $messages) { foreach ($messages as $message) { echo $message->getTemplate() . "\n"; } }

Здесь $message - объект класса Sirius\Validation\ErrorMessage , у которого есть метод getTemplate() , возвращающий то самое необходимое нам сообщение.

Valitron

Определяем правила

Первое отличие: чтобы добавить новое правило, не нужно создавать отдельный класс. Можно просто использовать замыкание, возвращающее булевский результат.


Для добавления кастомных правил в Valitron есть статический метод addRule() , в котором первые два аргумента обязательны, а третий - по желанию. Мне понравился такой способ, так как тут сразу в одном месте указывается идентификатор правила, логика и сообщение об ошибке.


use Valitron\Validator; Validator::addRule("two_words", function($field, $value) { return (bool) preg_match("/^+\s+$/u", $value); }, "Имя пользователя должно состоять ровно из двух слов.");

Второе отличие - то, как правила применяются к атрибутам. Во всех предыдущих случаях мы видели, что атрибут - вещь как бы первичная.


В Valitron пошли другим путем и на первое место поставили именно правила валидации. Описывая правила, вы как бы применяете атрибуты к этим правилам, а не наоборот.


$validator = new Validator($data); $validator ->rule("two_words", "name")->label("") ->rule("required", [ "name", "login", "email", "password", "agreed" ]) ->rule("slug", "login") ->rule("email", "email") ->rule("accepted", "agreed");

Как видно из примера, в методе rule() мы сначала пишем название правила, а уже затем указываем атрибуты, которые должны соответствовать этому правилу. Более явный пример - правило required , где показано, как атрибуты «принадлежат» этому правилу.


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


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


$validator->rule("two_words", "name")->label("")

Обратная связь

Конкретно что касается валидации, API библиотеки Valitron практически ничем не отличается от того, что мы уже видели в статье. Чтобы выполнить валидацию мы вызываем метод валидатора validate() :


$validator->validate();

Сообщения об ошибках валидации можно получить с помощью метода getErrors() :


$validator->errors();

Сообщения здесь группирутся по атрибутам точно так же, как и в Sirius Validation, за исключеним того, что для сообщения нет отдельного класса, и мы получаем обычный многомерный массив.


foreach ($validator->errors() as $attribute => $messages) { foreach ($messages as $message) { echo $message . "\n"; } }

Kontrolio

Ну и наконец, последняя библиотека на сегодня - моя собственная разработка под названием Kontrolio .

Определяем правила

Снова, в пятый раз мы создадим правило валидации для имени пользователя. Всё относительно просто и стандартно:


namespace MyProject\Validation\Rules; use Kontrolio\Rules\AbstractRule; class TwoWords extends Kontrolio\Rules\AbstractRule { public function isValid($input = null) { return (bool) preg_match("/^+\s+$/u", $input); } }

Теперь мы создаем фабрику и регистриуем правило в ней, используя метод extend() :


namespace MyProject; use Kontrolio\Factory; use MyProject\Validation\Rules\TwoWords; $factory = Kontrolio\Factory::getInstance()->extend();

После регистрации правила мы можем воспользоваться им в том числе по имени - two_words . Давайте создадим валидатор:


$data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" => "" // Пароль вообще не указан // "agreed" нет в массиве, потому что пользователь не установил флажок ]; $rules = [ "name" => "two_words", "login" => "sometimes|alphadash", "email" => "email", "password" => "length:1,64", "agreed" => "accepted" ]; $messages = [ "name" => "Имя пользователя должно состоять из двух слов.", "login" => "Ваш логин нам не нравится.", "email" => "Вы явно не хотите давать нам свой e-mail.", "password" => "Ну и где же ваш пароль?", "agreed" => "Жаль, что вы не согласны." ]; $validator = $factory->make($data, $rules, $messages);

Мы описали правила, используя синтаксис, схожий с тем, что используется в Laravel, хотя могли использовать и более многословный вариант:


$rules = [ "name" => new TwoWords, "login" => , "email" => new Email, "password" => new Length(1, 64), "agreed" => new Accepted ];

Обратная связь

Валидация запускается всё тем же методом validate() :


$validator->validate();

Теперь мы можем получить сообщения об ошибках, используя один из методов getErrors() или getErrorsList() . Первый метод позволяет сделать более сложный вывод ошибок, тогда как второй возвращает плоский массив. Используя getErrors() мы можем вывести сообщения как-то так:


    $messages): ?>

А с getErrorsList() можно сделать более простой список сообщений:


getErrorsList(); ?>

Итог

В данной статье я показал примеры использования следующих библиотек:

  1. Aura.Filter
  2. Respect Validation
  3. Sirius Validation
  4. Valitron
  5. Kontrolio

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


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


Благодарю за прочтение. Сделайте правильный выбор.

Теги: Добавить метки

Доброго всем вечера (скорее ночи – прим.ред.). Сегодня мы будем немного совершенствовать ту . Для начала научимся делать проверку формы на php и сделаем некоторые манипуляции по защите .

Итак, смотрим на код ниже и отмечаем для себя следующие изменения и следующие причины изменений. Все новые строки я выделил цветом.

    Изменено название полей формы . Вы спросите – на кой хрен нам это надо? А всё просто, отвечу я вам. Насколько мне известно, то некоторые спам боты рыскают по сайтам в поисках форм, и заполняют их, ориентируясь на названия этих полей. По идее если они не находят совпадений, то уходят восвояси, чего нам и надо. Конечно степень этой защиты не думаю, что особо велик, но от нас не убудет, а если писем спама уменьшится на 1 письмо, это уже будет хорошо=).

    Проверка на правильность ввода адреса почты . В 17 строке используется оператор elseif, который будет проверяться, если if вернул нам положительный ответ, то есть сказал, что адрес почты вообще отсутствует, то есть не был введён. Здесь мы используем функцию preg_match, которая позволяет сравнить введённый адрес с регулярным выражением . Про регулярные выражения возможно я напишу кратко потом, а пока стоит знать, что регулярное выражение создаёт некий шаблон, с которым сверяется наша строка. И если, в нашем случае, введённый адрес не совпадает с выражением, то опять же будет выведена ошибка. Для примера вот ещё парочку регулярных выражений:
    |^[-а-яе\s\.,;:\?!]+$|i – это регулярное выражение позволяет использовать только русский алфавит и некоторые символы типа пробела, точки, запятой и пр.
    #http://[-a-z0-9_.]+[-a-z0-9_:@&?=+,.!/~*’%$]*\.(html?|php)#i – а это выражение позволяет проверить правильность написание адреса в интернете.

Далее используется оператор else, куда уже перенесён весь наш код по отправке письма. Правила проверки можно создать самому в любом количестве, просто дописывайте новые elseif, как например для проверки адреса почты, и будет вам счастье.

$mailto = "[email protected]";
$charset = "windows-1251";
$subject = "Имя письма";
$content = "text/html";
$status="
";
if (!empty($_POST))
{
$name = htmlspecialchars (stripslashes ($_POST ["imko" ]));
$message = htmlspecialchars (stripslashes ($_POST ["tikstik" ]));
$mail = htmlspecialchars (stripslashes ($_POST ["posta" ]));

if (empty ($_POST ["posta" ]))
{
$status = "Вы не указали свой E-mail!" ;
}
elseif (!preg_match ("/^+@+\.{2,6}$/i" , $mail ))
{
$status = "Вы ввели некорректный E-mail!" ;
}
else
{
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: ".$content." charset=".$charset."\r\n";
$headers .= "From: \"".$name ."\" <".$mail .">\r\n";
$headers .= "Bcc: [email protected]\r\n";
$headers .= "X-Mailer: E-mail from my super-site \r\n";
$sendmessage = "

E-mail для связи: ".$mail ."


Сообщение: ".$message ."


";
if (mail($mailto,$subject,$sendmessage,$headers))
{
unset($name , $mail , $message );
$status = "Ваше сообщение отправлено!";
}
else
{
$status = "По техническим причинам сообщение не было отправлено. Попробуйте снова, а если не получится, обратитесь к разработчикам";
}
}
}
?>

















Вот так можно проверять ваши формы на PHP, не прибегая ни к чему постороннему. В следующий раз в посте на тему форм, думается мне, будет рассмотрена валидация форм на jQuery. А пока жду ваших комментариев и пожеланий. Всем спокойной ночи и весёлого утра=).


В предыдущей статье я обещал написать сравнение своей собственной библиотеки с другими имеющимися решениями, так что сегодня мы рассмотрим валидацию с помощью Aura.Filter , Respect Validation , Sirius Validation и Valitron .


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

  1. name. Должно содержать ровно два слова, где первое - имя пользователя, а второе - фамилия.
  2. login. Если значение передано, то оно должно только латинские буквы, дефисы и нижнее подчеркивание.
  3. email. Должно содержать валидный адрес электронной почты.
  4. password. Должен быть установлен и иметь длину не более 64 символов.
  5. agreed. Типичный флажок, который пользователь должен установить, чтобы подтвердить своё согласие с условиями сервиса.

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


$data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" =>

Aura.Filter

Валидация с использованием Aura.Filter начинается с фабрики фильтров. Нам необходимо создать так называемый «фильтр субъекта», так как мы будет валидировать массив, а не индивидуальное значение.

Определяем правила

use Aura\Filter\FilterFactory; $filter = (new FilterFactory)->newSubjectFilter(); $filter->validate("name") ->isNotBlank() ->is("two_words") ->setMessage("Имя должно состоять из двух слов."); $filter->validate("login") ->isBlankOr("alnum") ->setMessage("Если вы указываете логин, он должен содержать только латинские символы."); $filter->validate("email") ->isNotBlank() ->is("email") ->setMessage("Пожалуйста, напишите корректный адрес эл. почты."); $filter->validate("password") ->isNotBlank() ->is("strlenMax", 64) ->setMessage("Пожалуйста, напишите пароль."); $filter->validate("agreed") ->is("callback", function($subject, $field) { return $subject->{$field} === true; })->setMessage("Вам необходимо согласиться с условиями сервиса.");

Как видите, описание правил достаточно простое. Aura.Filter предоставляет целый набор полезных правил «из коробки» и некоторые из них были использованы в примере выше:

  1. метод isNotBlank. Указывает, что поле не может иметь пустое значение.
  2. alnum. Это правило допускает только латинские буквы.
  3. email. И так понятно:)
  4. strlenMax. Указывает, что поле не может превышать длину, указанную вторым аргументом метода is .
  5. callback. Этот тип правила похож на замыкания из Kontrolio. Он позволяет определить правило в виде замыкания. В это замыкание Aura.Filter передает «субъект», наш массив данных из формы, и поле, в данном случае agreed .

Наверняка вы заметили, что я не указал правило two_words . Естественно, в Aura.Filter такого правила нет, поэтому нам необходимо его создать. Как гласит документация, это делается с помощью отдельного класса для правила:


/** * Правило, которое валидирует имя пользователя. * Имя пользователя состоит из двух слов: имени и фамилии, разделенных одним пробелом. */ class UserNameRule { /** * Валидирует имя пользователя. * * @param object|array $subject * @param string $field * @param int $max * * @return bool */ public function __invoke($subject, $field, $max = null) { $value = $subject->{$field}; if (! is_scalar($value)) { return false; } return (bool) preg_match("/^+\s+$/u", $value); } }

The second step is to let the filter factory know about our new rule. It’s done by passing the first argument as an array of rules to the filter factory:


Следущий шаг - уведомить Aura.Filter о том, что мы создали новое правило и хотим его использовать. Это делается с помощью передачи массива правил в первый аргумент фабрики:


use Aura\Filter\FilterFactory; $rules = [ "two_words" => function() { return new UserNameRule; } ]; $filter = (new FilterFactory($rules))->newSubjectFilter();

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

Обратная связь

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


Валидируем с Aura.Filter мы следующим образом:


$valid = $filter->apply($data); if (! $valid) { $failures = $filter->getFailures(); $messages = $failures->getMessages(); }

В $messages записывается массив, поэтому для вывода сообщений нам потребуется два вложенных foreach:


    $errors) { foreach ($errors as $error) { printf("", $error); } } ?>

Respect Validation

Вторая библиотека, использованная мной в сравнении, - относительно популярное решение под названием Respect Validation . Раз люди ей доверяют, думаю, там есть что посмотреть.


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


use Respect\Validation\Validator as v; $data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" => "" // Пароль вообще не указан // "agreed" нет в массиве, потому что пользователь не установил флажок ];

Определяем правила

Как и в случае с Aura.Filter, нам необходимо собственное правило валидации для имени пользователя, поэтому давайте с него и начнем:


namespace MyNamespace; use Respect\Validation\Rules\AbstractRule; class UserNameRule extends AbstractRule { public function validate($input) { return (bool) preg_match("/^+\s+$/u", $input); } }

Внешнее API правил практически идентично Aura.Filter, только используется метод validate() вместо магии __invoke(). Мне оно, это API, показалось более простым и понятным. Ну, и к Kontrolio оно ближе:)


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


use Respect\Validation\Exceptions\NestedValidationException; class UserNameRuleException extends NestedValidationException { // }

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


v::with("MyNamespace\\");

Теперь все нестандартные правила, находящиеся в пространстве имен MyNamespace , будут «опознаны» валидатором. Следующий шаг - описать необходимые правила и выполнить валидацию.


v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) ->attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data);

Обратите внимание на то, как мы применяем наше правило к атрибуту name . Здесь название класса правило трансформировалось в название метода валидатора. Остальные правила, в общем-то, интуитивно понятны.


Отдельно стоит сказать о том, зачем мы приводим массив $data к объекту. Дело в том, что Respect Validation принимает на вход объекты, а не массивы. Это следует учесть при разработке с использованием данной библиотеки.

Обратная связь

В отличие от Aura.Filter валидатор Respect выбрасывает исключение, когда валидация провалена. И в этом исключении содержатся сообщения об ошибках валидации. Поэтому пример, который только что был показан, должен быть записан следующим образом:


try { v::with("RespectValidationExample\\"); v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) ->attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data); } catch (NestedValidationException $ex) { $messages = $ex->getMessages(); }

Используя getMessages() , мы получим плоский массив всех сообщений, который валидатор собрал в процессе валидации. Задампив массив, мы получим примерно такой результат:


array(5) { => string(29) “Data validation failed for %s” => string(60) “login must contain only letters (a-z), digits (0–9) and “-_”” => string(25) “email must be valid email” => string(26) “password must not be empty” => string(32) “Attribute agreed must be present” }

Можно поменять сообщения на свои собственные. Возможно, я как-то не так понял эту библиотеку, но мне этот процесс не показался таким уж очевидным: необходимо использовать метод findMessages() на обработанном исключении, в котором вы определяете сообщения не для атрибутов, а для правил.


$ex->findMessages([ "userNameRule" => "Имя пользователя должно состоять из двух слов.", "alnum" => "Ваш логин нам не нравится.", "email" => "Вы явно не хотите давать нам свой e-mail.", "notEmpty" => "Ну и где же ваш пароль?", "agreed" => "Жаль, что вы не согласны." ]);

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


array(5) { => string(40) “Имя пользователя должно состоять из двух слов.” => string(31) “Ваш логин нам не нравится.” => string(25) “email must be valid email” => string(5) “Ну и где же ваш пароль?” => string(9) “Жаль, что вы не согласны.” }

Как видите, сообщение для поля электронной почты не применилось, осталось стандартное. А вот сообщение за индексом 4 наоборот! И это при том, что я использовал не название правила, а название поля. В то время как если бы я использовал название правила (trueVal), моё сообщение бы куда-то затерялось. Комментарии опытных пользователей данной библиотеки очень приветствуются.

Sirius Validation

Ок, давайте перейдем к следующей библиотеке и посмотрим, как она справится со схожими задачами.

Определяем правила

И снова нам необходимо определить правило для имени пользователя. Мы его напишем как-то так:


class UserNameRule extends AbstractRule { // Сообщения об ошибках const MESSAGE = "Имя пользователя должно состоять из двух слов."; const LABELED_MESSAGE = "{label} должно состоять из двух слов."; public function validate($value, $valueIdentifier = null) { return (bool) preg_match("/^+\s+$/u", $value); } }

Обратите внимание на разницу в подходах в сравнении с уже рассмотренными библиотеками. Мы определяем два вида сообщений в константах, нежели используя свойства, методы или аргументы правила.


Теперь давайте опишем логику валидации:


$validator = new Validator; $validator ->add("name", "required | MyApp\Validation\Rule\UserNameRule") ->add("login", "required | alphanumhyphen", null, "Логин может содержать только латинские буквы, черточки и подчеркивания.") ->add("email", "required | email", null, "Пожалуйста, укажите корректный e-mail.") ->add("password", "required | maxlength(64)", null, "Ваш пароль, сударь.") ->add("agree", "required | equal(true)", null, "Почему же вы не согласились?");

Как видите, набор правил весьма прост и читабелен. Для описания мы используем названия, разделенные горизонтальными черточками. Этот подход похож на тот, что используется в Laravel и Kontrolio.


Четвертый аргумент метода add() описывает сообщение об ошибке валидации, которое Sirius использует, если валидация будет провалена. А почему же мы не добавили сообщение для нашего нового правила UserNameRule ?


$validator->add("name", "required | MyApp\Validation\Rule\UserNameRule")

Так это потому, что сообщения уже описаны в константах класса:


class UserNameRule extends AbstractRule { // Сообщения об ошибках const MESSAGE = "Имя пользователя должно состоять из двух слов."; ...

Другой вариант - использовать метод addMessage() самого валидатора:


$validator->addMessage("email", "Пожалуйста, укажите корректный e-mail.");

Обратите внимание, что кастомные правила идентифицируются по полному названию их класса, в то время как в Kontrolio можно задать псевдоним/алиас.

Обратная связь

Чтобы выполнить валидацию, мы вызываем метод валидатора validate() , передавая в него данные:


$data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" => "" // Пароль вообще не указан // "agreed" нет в массиве, потому что пользователь не установил флажок ]; $validator->validate($data);

В отличие от Respect, Sirius не выкинет исключение, а просто вернет false . Сообщения об ошибках валидации можно получить через метод валидатора getMessages() . Он возвращает ошибки, сгруппированные по атрибутам, так что для прохода по ошибкам нам понадобится два цикла foreach:


foreach ($validator->getMessages() as $attribute => $messages) { foreach ($messages as $message) { echo $message->getTemplate() . "\n"; } }

Здесь $message - объект класса Sirius\Validation\ErrorMessage , у которого есть метод getTemplate() , возвращающий то самое необходимое нам сообщение.

Valitron

Определяем правила

Первое отличие: чтобы добавить новое правило, не нужно создавать отдельный класс. Можно просто использовать замыкание, возвращающее булевский результат.


Для добавления кастомных правил в Valitron есть статический метод addRule() , в котором первые два аргумента обязательны, а третий - по желанию. Мне понравился такой способ, так как тут сразу в одном месте указывается идентификатор правила, логика и сообщение об ошибке.


use Valitron\Validator; Validator::addRule("two_words", function($field, $value) { return (bool) preg_match("/^+\s+$/u", $value); }, "Имя пользователя должно состоять ровно из двух слов.");

Второе отличие - то, как правила применяются к атрибутам. Во всех предыдущих случаях мы видели, что атрибут - вещь как бы первичная.


В Valitron пошли другим путем и на первое место поставили именно правила валидации. Описывая правила, вы как бы применяете атрибуты к этим правилам, а не наоборот.


$validator = new Validator($data); $validator ->rule("two_words", "name")->label("") ->rule("required", [ "name", "login", "email", "password", "agreed" ]) ->rule("slug", "login") ->rule("email", "email") ->rule("accepted", "agreed");

Как видно из примера, в методе rule() мы сначала пишем название правила, а уже затем указываем атрибуты, которые должны соответствовать этому правилу. Более явный пример - правило required , где показано, как атрибуты «принадлежат» этому правилу.


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


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


$validator->rule("two_words", "name")->label("")

Обратная связь

Конкретно что касается валидации, API библиотеки Valitron практически ничем не отличается от того, что мы уже видели в статье. Чтобы выполнить валидацию мы вызываем метод валидатора validate() :


$validator->validate();

Сообщения об ошибках валидации можно получить с помощью метода getErrors() :


$validator->errors();

Сообщения здесь группирутся по атрибутам точно так же, как и в Sirius Validation, за исключеним того, что для сообщения нет отдельного класса, и мы получаем обычный многомерный массив.


foreach ($validator->errors() as $attribute => $messages) { foreach ($messages as $message) { echo $message . "\n"; } }

Kontrolio

Ну и наконец, последняя библиотека на сегодня - моя собственная разработка под названием Kontrolio .

Определяем правила

Снова, в пятый раз мы создадим правило валидации для имени пользователя. Всё относительно просто и стандартно:


namespace MyProject\Validation\Rules; use Kontrolio\Rules\AbstractRule; class TwoWords extends Kontrolio\Rules\AbstractRule { public function isValid($input = null) { return (bool) preg_match("/^+\s+$/u", $input); } }

Теперь мы создаем фабрику и регистриуем правило в ней, используя метод extend() :


namespace MyProject; use Kontrolio\Factory; use MyProject\Validation\Rules\TwoWords; $factory = Kontrolio\Factory::getInstance()->extend();

После регистрации правила мы можем воспользоваться им в том числе по имени - two_words . Давайте создадим валидатор:


$data = [ "name" => "Альберт", // Должно быть два слова "login" => "@lbert", // "Запрещенный" символ @ "email" => "что-то не то", // Здесь должен быть e-mail "password" => "" // Пароль вообще не указан // "agreed" нет в массиве, потому что пользователь не установил флажок ]; $rules = [ "name" => "two_words", "login" => "sometimes|alphadash", "email" => "email", "password" => "length:1,64", "agreed" => "accepted" ]; $messages = [ "name" => "Имя пользователя должно состоять из двух слов.", "login" => "Ваш логин нам не нравится.", "email" => "Вы явно не хотите давать нам свой e-mail.", "password" => "Ну и где же ваш пароль?", "agreed" => "Жаль, что вы не согласны." ]; $validator = $factory->make($data, $rules, $messages);

Мы описали правила, используя синтаксис, схожий с тем, что используется в Laravel, хотя могли использовать и более многословный вариант:


$rules = [ "name" => new TwoWords, "login" => , "email" => new Email, "password" => new Length(1, 64), "agreed" => new Accepted ];

Обратная связь

Валидация запускается всё тем же методом validate() :


$validator->validate();

Теперь мы можем получить сообщения об ошибках, используя один из методов getErrors() или getErrorsList() . Первый метод позволяет сделать более сложный вывод ошибок, тогда как второй возвращает плоский массив. Используя getErrors() мы можем вывести сообщения как-то так:


    $messages): ?>

А с getErrorsList() можно сделать более простой список сообщений:


getErrorsList(); ?>

Итог

В данной статье я показал примеры использования следующих библиотек:

  1. Aura.Filter
  2. Respect Validation
  3. Sirius Validation
  4. Valitron
  5. Kontrolio

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


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


Благодарю за прочтение. Сделайте правильный выбор.

Теги:

  • валидация данных
  • php
  • велосипедостроение
Добавить метки

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

Общее правило безопасности - не доверять никому, так что нельзя надеяться на то, что пользователи всегда будут вводить в формы правильные значения. Например, вместо ввода в поле правильного email-адреса, пользователь может ввести неверный адрес, или вообще какие-нибудь вредоносные данные.

Когда дело доходит до валидации пользовательских данных, ее можно проводить как на стороне клиента (в веб-браузере), так и на серверной стороне.

Ранее валидацию на стороне клиента можно было провести только с помощью JavaScript. Но все изменилось (или почти изменилось), так как с помощью HTML5 валидацию можно проводить средствами браузера, без необходимости писать сложные скрипты для валидации на JavaScript.

Валидация форм с помощью HTML5

HTML5 предоставляет довольно надежный механизм, основанный на следующих атрибутах тега : type , pattern и require . Благодаря этим новым атрибутам вы можете переложить некоторые функции проверки данных на плечи браузера.

Давайте рассмотрим эти атрибуты, чтобы понять, как они могут помочь в валидации форм.

Атрибут type

Этот атрибут говорит, какое поле ввода отобразить для обработки данных, например, уже знакомое поле типа

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

Попробуйте поиграться со значениями поля email в нижеприведенной демонстрации .

Также существуют другие стандартные типы полей, вроде , и для валидации чисел, URL’ов и телефонных номеров соотвествено.

Замечание: формат телефонного номера различается для разных стран из-за несоответствия количества цифр в телефонных номерах и разности форматов. Как результат, спецификация не определяет алгоритм проверки телефонных номеров, так что на время написания статьи данная возможность слабо поддерживается браузерами.

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

Атрибут pattern

Атрибут pattern , скорее всего, заставит многих фронтенд-разработчиков прыгать от радости. Этот атрибут принимает регулярное выражение (аналогичное формату регулярных выражений JavaScript), по которому будет проверяться корректность введенных в поле данных.

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

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

Регулярные выражения (RegEX) являются мощным, кратким и гибким инструментом для сопоставления строки текста, вроде отдельных символов, слов или шаблонов символов.

Передав регулярное выражение в качестве значения атрибута pattern можно указать, какие значения приемлемы для данного поля ввода, а также проинформировав пользователя об ошибках.

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

Телефонные номера

Как упоминалось ранее, тип поля tel не полностью поддерживается браузерами из-за несоответствия форматов номеров телефонов в разных странах.

Например, в некоторых странах формат телефонных номеров представляется в виде xxxx-xxx-xxxx , и сам телефонный номер будет что-то вроде этого: 0803-555-8205 .

Регулярное выражение, которому соответствует данный шаблон, такое: ^\d{4}-\d{3}-\d{4}$ . В коде это можно записатьтак :

Буквенно-цифровые значения

Атрибут required

Это атрибут булевого типа, использующийся для указания того, что значение данного поле обязательно заполнить для того, чтобы отправить форму. При добавлении этого атрибута полю браузер потребует от пользователя заполнить данное поле перед отправкой формы.

Это избавляет нас от реализации проверки полей с помощью JavaScript, что может сохранить немного времени разработчикам.

Например: или (для совместимости с XHTML)

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

Заключение

Поддержка валидации форм браузерами довольно хороша , а для старых браузеров вы можете использовать полифиллы.

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

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