Тема данной статьи — валидация, т.е. проверка входных данных на соответствие каким-то заранее определенным правилам. Самый простой пример — проверка URL или адреса Email на корректность, т.е. на наличие домена, «собачки» и т.д. В общем, вешь полезная во всех отношениях. Поэтому мы с ней в этой статье попробуем подружиться. За валидацию отвечает библиотека Validation (system/libraries/Validation.php).
Методы объекта Validation
- Конструктор. В качестве параметра передается массив переменных (обычно это глобальный массив $_POST или $_GET), которые надо проверить. Вызывать можно различным образом, самое простое:
$valid = new Validation($_POST); // или $valid = Validation::factory($_POST);
Обратите внимание, что массив не копируется, а передается по ссылке, т.е. доступен для изменений (вообще он преобразовывается в объект ArrayObject).
- Метод add_rules(). Для того, чтобы проверять переменные, надо указать правила. Первый параметр всегда имя переменной (т.е. ключ в переданном массиве). Кроме того, можно передать в качестве имени поля звездочку (символ ‘*’) или TRUE, тогда правило будет применено ко всем проверяемым полям. Далее следуют правила, которые могут быть встроенными (это наиболее распространенные правила, такие как required и email), так и определенными пользователем (в этом случае необходимо указать объект и имя метода этого объекта) — такие правила называют callback (или custom callback). Примеры использования:
// Поле 'email' должно присутствовать и соответствовать стандартному правилу email $valid->add_rules('email', 'required', 'email'); // Поле 'username' должно присутствовать и длина от 5 до 30 символов $valid->add_rules('username', 'required', 'length[5,30]'); // Поле 'username' должно присутствовать и быть уникальным // Метод unique_username должен быть определен в текущем классе (т.к. передали $this) $valid->add_rules('username', 'required', array($this, 'unique_username'));
Правила можно задать отдельно:
$valid->add_rules('email', 'required'); $valid->add_rules('email', 'email');
- Метод add_callbacks(). По сути дублирует метод add_rules в части добавления собственных правил (callback‘ов). Параметры те же — имя поля и массив( объект, имя метода). Например:
// свое правило для проверки пароля $valid->add_callbacks('password', array($this, 'check_password'));
- Метод add_error(). Добавляет ошибку валидации в список ошибок. Первый параметр — имя поля, второй — текст ошибки (даже скорее что-то вроде метки). Стандартные правила сами составляют список ошибок, этот метод обычно используется в теле callback‘а.
- Методы pre_filter() и post_filter(). Позволяют выполнять строковые преобразования над значениями полей до или после проверки. В качестве первого параметра выступает имя функции, второй — имя поля (если не указано, то распространяется на все поля). Пример:
$valid->pre_filter('trim'); // указываем правила $valid->post_filter('ucfirst', 'username');
Функции trim() и ucfirst() являются встроенными php-функциями.
- Метод validate(). Тут-то и происходит собственно валидация. Метод возвращает TRUE (ошибок нет) или FALSE (что-то не совпало).
Стандартные правила
Поскольку в 90% случаев используются стандартные правила, посмотрим, что мы имеем:
- required. Поле должно существовать. Дополнительных параметров нет.
- matches. Поле должно совпадать с указанным или указанными полями. Необходимо указать массив полей для сравнения.
- length. Проверка на длину поля. Если передан один параметр, то проверяется равенство длины поля этому параметру. Если два, то первый принимается за минимальную длину, второй за максимальную. Пример:
$valid->add_rules('password', 'length[5,10]'); // пароль от 5 до 10 символов $valid->add_rules('username', 'length[7]'); // все логины должны быть длиной 7 символов
- depends_on. Ставим поле в зависимость от внесения другого поля или полей. Если хотя бы одно поле отсутствует или равно NULL, правило возвращает FALSE. Пример:
// Поле total_price зависит от наличия полей price и count $valid->add_rules('total_price', 'depends_on[price, count]');
- chars. Указывается перечень допустимых символов, из которых должно состоять значение проверяемого поля. Пример:
// Поле должно быть в восьмеричной системе счисления $valid->add_rules('oct_value', 'chars[0,1,2,3,4,5,6,7]');
Эти правила описаны в самом классе Validation. Также можно использовать правила из хэлпера valid:
- email. Проверка на корректность составления адреса email.
- email_domain. Проверка домена email на существование в DNS записях по типу «MX» (выполняется функцией checkdnsrr()). Т.к. на windows-платформах такой функции нет, вернет TRUE.
- email_rfc. Проверка email на корректность в соответствии с документом rfc822.
- url. Проверяет url на валидность.
- ip. Проверяет ip-адрес, в качестве дополнительных параметров можно указать поддержку адресов IPv6 и приватных сетей (диапазоны 10.0.0.0 — 10.255.255.255, 172.16.0.0 — 172.31.255.255, 192.168.0.0 — 192.168.255.255), указав TRUE в качестве соответствующего параметра.
- credit_card. Проверка номеров кредитных карт на состав, длину, также используется алгоритм «mod 10«. Можно передавать тип или типы кредитных карт, известные системе типы карт хранятся в system/config/credit_cards.php. Пример:
$valid->add_rules('card_num', 'credit_card[american express, mastercard]');
- phone. Проверка номера телефона. Проверяется только длина номера (отбрасываются все символы, кроме чисел), для чего можно передать массив допустимых длин, по умолчанию берется [7, 10, 11].
- alpha. Поле должно содержать только буквы алфавита. Необязательный параметр — режим UTF-8 (т.е. символы в UTF-8 виде), по умолчанию FALSE.
- alpha_numeric. Поле должно содержать только буквы и цифры. Необязательный параметр режим UTF-8.
- alpha_dash. Поле должно состоять только из букв, цифр, знаков подчеркивания и дефисов. Необязательный параметр режим UTF-8.
- digit. Поле должно состоять из цифр. Необязательный параметр режим UTF-8.
- numeric. Поле должно быть числом (цифры, тире и разделитель дробной части).
- standard_text. Значение должно быть текстом (буквы, цифры, пробелы, тире, знаки подчеркивания и пунктуации).
- decimal. Значение должно быть десятичным числом. Необязательный параметр — формат в виде массива чисел (если одно число, то это количество знаков после запятой, а если больше — то до и после запятой соответственно). Пример:
$valid->add_rules('price', 'decimal[2]'); // цена с двумя знаками после запятой
- date. Значение должно быть датой. Просто проверка strtotime($str) !== FALSE.
Как писать свое правило
Правило — это просто публичный (public) метод класса, в котором формируются правила для Validation. В качестве первого параметра указывается объект Validation, далее имя поля. В случае несоответствия правилу необходимо добавлять ошибку с помощью метода add_error(). Пример callback‘а:
public function username_available($id) { return !$this->db ->where($this->unique_key($id), $id) ->count_records($this->table_name); } |
Примечание. Тут-то и обнаружилось расхождение с документацией. В callback передается только имя поля. Соответственно негде вызывать метод add_error(). Зато ошибка в случае возврата FALSE из функции записывается системой самостоятельно. В общем, очередная «непонятка» в документации.
Что в итоге? Сам по себе метод validate() возвращает результат проверки — TRUE/FALSE. Массив ошибок доступен через метод errors(), примененный к массиву, который мы передавали в конструктор Validate:
if ($valid->validate()) { // Делаем что-то, все прошло успешно } else { // Не прошли через все правила, выводим пользователю ошибки $errors = $_POST->errors(); $olddata = $_POST->as_array(); } |
Как правило, в случае ошибки валидации пользователю показывают снова ту же последнюю заполненную форму, список ошибок (можно в строковом виде, очень удобно, когда конкретное поле подсвечивается). Не забывайте о заполнении всех полей формы кроме паролей исходными данными (в моем примере это переменная $olddata) — пользователь может уйти с сайта, т.к. заново все вводить не у каждого хватит терпения. Ну и конечно, желательно делать хотя бы первичную проверку (заполнение обязательных полей) еще на стороне клиента средствами JavaScript, это экономит время и трафик.
Вау, отличный цикл статей! С них можно начать локализацию документации.
Спасибо вам!
В общем-то рубрика «Справочник» как раз предназначена для документирования возможностей Kohana, только в более удобном и «художественном» стиле.
Некоторые нюансы выясняются только после анализа исходников и в оригинальной документации не упоминаются, поэтому я и решил создать этакие «записки охотника».
Спасибо, особенно про пользовательские ф-ии.
Собираюсь в ближайшее время этот вопрос изучить, и если есть расхождения с документацией, то это, безусловно, грустно.
По поводу javascript — это полезно, особенно для создания дружественного интерфейса, грустно то, что это легко обходится и на сервере данные всеравно приходится обрабатывать
А ничего грустного, как мне кажется. Все равно еще встречаются пользователи с отключенным JS, поэтому серверную валидацию никто не отменял
Прошу помощи! Что-то не могу разобраться с валидацией в ORM.
Проблема вот в чем: в форме много полей, но в проверять мне все поля не нужно, поэтому класс модели такой:
class firm_Model extends ORM {
public function validate(array & $array, $save = FALSE)
{
$array = Validation::factory($array)
->pre_filter(‘trim’)
->add_rules(‘rub_id’, ‘required’, ‘is_natural_no_zero’)
->add_rules(‘name’, ‘required’);
return parent::validate($array, $save);
}
}
После того как я в контроллере делаю проверку
if ($firm->validate ($post))
{
$firm->save();
}
в объект $firm попадают только те поля которые описаны в function validation для модели.
Это так и должно быть? Или я чего-то не догоняю…
Если мне не нужно проверять все поля, что делать?
В Kohana v2.3 так и должно быть. Из массива загружаются только те поля, которые участвуют в валидации и не указаны в ignored_columns. Для загрузки используйте метод load_values(), например в случае успешного save()
ничего не понимаю, что не так?
if ($firm->validate ($post))
{
$firm->load_values($post->as_array());
$firm->save();
}
все равно не сохраняются те поля которые не описаны в function validation для модели.
Что нужно сделать? Не могу я применять required ко всем полям, но если оно заполнено должен сохранить его.
Если передать массив в метод validate(), он становится объектом класса Validation, лишние значения потеряются. Попробуйте сделать копию массива $post до валидации
Спасибо вам за желание помочь, но что-то все равно у меня не получается. Создал тему на форуме Kohana
http://forum.kohanaphp.com/comments.php?DiscussionID=3654