Может войдёшь?
Черновики Написать статью Профиль

Создание и проверка форм

перевод

  1. 1. Создание форм в Laravel
  2. 2. Подделка межсайтовых запросов (CSRF)
  3. 3. Проверка введённых данных
  4. 4. Отображение ошибок
  5. 5. Собственные правила и ошибки

Формы — непременная часть любого вёб-приложения. Мы используем их для авторизации и регистрации нового пользователя, на странице обратной связи, при отправки комментария и для множества других задач. Однако их создание и последующая проверка может быть неприятным процессом — и здесь на сцену выходит Laravel, который даёт нам несколько аккуратных классов для интуитивно понятной работы с формами и их данными.

Создание форм в Laravel

Создавать формы в Laravel неожиданно просто. По большей части ничего не мешает вам использовать стандартные теги HTML, но Laravel может значитель облегчить вам жизнь. Скажем, класс PHPForm имеет метод PHPlabel(), позволяющий вам связать метки с полями формы используя соответствующие (автосгенерированные) ID. Давайте в качестве примера создадим простую форму:

PHP
<h2>Register!</h2>

<?php

echo Form::open('register''POST');

echo 
Form::label('username''Username') . Form::text('username'Input::old('username'));
echo 
Form::label('email''E-mail') . Form::text('email'Input::old('email'));
echo 
Form::label('password''Password') . Form::password('password');

echo 
Form::submit('Register!');

echo 
Form::token() . Form::close();

?>

Всё очевидно, не так ли? Мы открываем форму POST-запроса на маршруте register, создаём несколько меток и полей ввода и добавляем CSRF-ключ, после чего закрываем форму. Если нам нужен безопасный маршрут (с использованием HTTPS), то заменим вызов PHPForm::open() на вызов PHPForm::open_secure(), а если нам нужно создать форму для загрузки файлов, то пригодится PHPForm::open_for_files().

Вы наверняка заметили некие вызовы PHPInput::old() — о них мы поговорим чуть позже, а пока просто запомните, что они здесь есть.

Класс Form содержит множество методов для простого создания форм — вы можете ознакомиться с ними в документации.

Подделка межсайтовых запросов (CSRF)

Я не буду вдаваться в подробности о CSRFJeff Atwood написал очень наглядную статью о том, что это такое и как этого избежать.

Метод Form::token() создаёт случайную последовательность символов, сохраняет её в данных сессии (это значит, что вам нужно включить их поддержку в application/config/session.php) и выводит её в виде скрытого поля формы. При обработке запроса от формы, использующей CSRF-ключ мы можем использовать встроенный фильтр csrf для проверки того, что никто не «поработал» над запросом и он действительно исходит от пользователя.

Вот как выглядит код фильтра (файл application/routes.php):

PHP
Route::filter('csrf', function () {
  if (
Request::forged()) return Response::error('500');
});

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

Начнём писать наш POSTмаршрут, который будет обрабатывать регистрацию (файл application/routes.php):

PHP
Route::post('register', array('before' => 'csrf', function () {
  
// регистрация нового пользователя.
}));

Вот и всё, что нам нужно для включения CSRF-фильтра — просто убедится, что он указан в списке before.

Проверка введённых данных

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

Несколько человек заметили, что проверка не должна выполняться в контроллере. Обычно лучше всего делать это в модели — моя следующая статья «Продвинутая проверка ввода в Laravel» описывает именно этот способ решения задачи.

PHP
// файл application/routes.php.

Route::post('register', array('before' => 'csrf', function () {
  
$rules = array(
    
'username' => array('required''unique:users,username'),
    
'email'    => array('required''email''unique:users,email'),
    
'password' => array('required''min:7')
  );

  
$validation Validator::make(Input::all(), $rules);

  if (
$validation->fails()) {
    
// проверка не пройдена.
    
return Redirect::to('register')->with_input()->with_errors($validation);
  }

  
// данные прошли проверку - можем создавать нового пользователя.
}));

Вот, что мы здесь делаем:

  1. Определяем массив правилключи соответствуют именам полей ввода формы, значения — правилам, которым они должны соответствовать. В нашем случае поле username («имя пользователя») должно быть заполнено (required) и уникально (unique).
  2. Создаём объект PHPValidatorпервым параметром он принимает данные для проверки (в нашем случае данные формы, полученные через POST), вторым — набор правил.
  3. Затем мы выполняем проверку — если она не прошла, переадресуем пользователя обратно к маршруту register (используя GET) со старым вводом и сообщениями об ошибках.
  4. Если же все поля заполнены верно — регистрируем новую учётную запись, авторизуем пользователя, либо делаем что-то ещё.

Последовательность действий, которые мы здесь выполняем, называют шаблоном «Post/Redirect/Get» (PRG) — это отличный способ предотвратить двойную отправку формы.

Теперь посмотрим на правила, которые мы определили выше.

required — обозначает, что поле должно быть заполнено — иными словами, оно должно иметь значение.

unique — здесь немного более сложный момент. Это правило принимает 3 параметра, 2 из которых можно опустить. Первый параметр — имя таблицы, в котором нужно проверять значение на уникальность; второй — имя поля в таблице, если оно не соответствует имени поля в форме (в этом случае его можно пропустить); третий и последний параметр — значение (id) для первичного ключа.

Предположим, что мы обновляем существующий профиль пользователя — мы точно так же хотим, чтобы его e-mail был уникальным, но если он решил не изменять свой адрес, то нам не стоит говорить, что введённый e-mail уже занят — им самим. Для этого мы и передаём ID пользователя — Laravel исключит соответствующую запись из проверки.

PHP
  $rules = array(
    
'email' => array('required''email''unique:users,email,' $user->id)
  );

e-mail — проверяет, что введённое значение похоже на правильный e-mail адрес, но не проверяет его на существование.

min — устанавливает минимально допустимую длину значения данного поля.

Полный список доступных правил можно найти в документации.

Отображение ошибок

В Laravel все представления («views») уже имеют предустановленную переменную PHP$errors — если вы не установили её сами. Эта переменная содержит объект Messages — тот самый, который возвращает нам Validator. Вы могли заметить, что в предыдущем примере мы переадресовывали клиента со вводом (PHPwith_input()) и с ошибками (PHPwith_errors()).

Свойство PHP$validation->errors содержит тот же объект Messages со всеми ошибками, найденными во входных данных. Laravel определит, что была выполнена переадресация с ошибками и автоматически привяжет этот объект к представлению. Вы скоро поймёте, что я имею в виду.

Помните вызовы PHPInput::old() в нашей форме? Когда мы переадресовываем запрос со вводом они вернут значения, которые пользователь ввёл в форму ранее. Поэтому если я сказал, что моё имя — «Jason», но регистрация не произошла, «Jason» останется введённым даже после переадресации меня обратно на форму. Отлично!

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

PHP
echo Form::password('password', array('value' => Input::old('password')));

Вернёмся к нашей форме. Как вы помните, у нас есть переменная $errors — объект PHPMessages. Давайте сделаем нашу форму более дружелюбной, отображая ошибки, когда она была неверно заполнена:

PHP
<h2>Register!</h2>

<?php

echo Form::open('register''POST');

echo 
Form::label('username''Username') . Form::text('username'Input::old('username'));

if (
$errors->has('username')) {
  echo 
$errors->first('username');
}

echo 
Form::label('email''E-mail') . Form::text('email'Input::old('email'));

if (
$errors->has('email')) {
  echo 
$errors->first('email');
}

echo 
Form::label('password''Password') . Form::password('password');

if (
$errors->has('password')) {
  echo 
$errors->first('password');
}

echo 
Form::submit('Register!');

echo 
Form::token() . Form::close();

?>

Сообщения будут показаны только в случае, когда определённое поле содержит ошибки.

Вы можете отформатировать сообщение в нужный HTML передав его во втором параметре:

PHP
echo $errors->first('username''<span class="error">:message</span>');

Либо, если вы хотите отобразить первое сообщение об ошибке для любого поля, а не только для username:

PHP
echo $errors->first();

Наконец, вы можете отобразить все возникшие ошибки:

PHP
<?php if ($errors->has()): ?>

Мы обнаружили следующие ошибки:
<ul>
  <?php echo implode(''$errors->all('<li>:message</li>')); ?>
</ul>

<?php endif; ?>

PHP$errors->all() возвращает массив отформатированных сообщений, поэтому мы объединяем его в строку.

Собственные правила и ошибки

Часто вам понадобится создавать собственные правила для проверки ввода. До Laravel 3 это делалось наследованием класса Validator и добавлением к нему методов. С поддержкой пакетов потребовалось более надёжное решение, чтобы не создавать множество подклассов. Laravel 3 позволяет регистрировать произвольные правила с помощью PHPValidator::register():

PHP
// этот код может быть помещён, например, в application/start.php:
Validator::register('starts_with', function ($attribute$value$parameters) {
  return 
starts_with($value$parameters[0]);
});

В этом простом обработчике мы просто возвращаем true, если значение начинается на указанную строку (переданную в первом и единственном параметре), и false в противном случае. Здесь используется одна из немногих глобальных функций Laravel — PHPstarts_with().

Использование нового правила:

PHP
$rules = array(
  
'website' => array('required''starts_with:http://')
);

Здесь нам потребовалось определить поле как обязательное («required»). Крмое этого нам также нужно добавить сообщение об ошибке в файл application/language/en/validation.php:

PHP
'custom' => array(
  
'website_starts_with' => 'Website must start with http://'
)

Либо можно это сделать при создании экземпляра Validator, передав его в третьем параметре:

PHP
$rules = array(
  
'website' => array('required''starts_with:http://')
);

$messages = array(
  
'website_starts_with' => 'Website must start with http://'
);

$validation Validator::make(Input::all(), $rules$messages);

Вот и всё!

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

Как вы считаете, полезен ли этот материал? Да Нет

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.