|
Статьи
Обработка ошибочного заполнения формы
В случае ошибочного заполнения пользователем формы на веб странице, хорошим тоном считается показать ему эту же форму, заполненною введёнными данными (чтобы пользователю не пришлось перенабирать всё заново) и снабжённую сообщением об ошибке.
Чаще всего разработчики идут по пути наименьшего сопротивления, и выводят заполненную форму непосредственно после обработки запроса, т.е. в ответ на POST -обращение к серверу. Это очень просто, т.к. форму выводит тот же скрипт, что и получил данные, данные доступны скрипту "напрямую", и что именно в них неправильно — тоже известно. Однако у такого подхода есть очень серьёзные недостатки, свойственные всем страницам, выдаваемым в ответ на POST .
Во-первых, если пользователь нажмёт на такой странице Refresh, то браузер выведет сообщение о том, что страницу обновить невозможно без повторной отсылки данных. Во-вторых, если пользователь правильно заполнил форму во второй раз, и ушёл на другую страницу, то при нажатии на кнопку Back (т.е. при попытке вернуться на POST -страницу) ему опять выведется сообщение о необходимости повторной отсылки данных. Мало того, что это совершенно нелогично и неудобно с точки зрения пользователя (он ведь уже отправил данные!), так ещё и если он в этот момент нажмёт "OK", то форма и в самом деле запостится во второй раз. Наконец, чтобы не дублировать код, отображающий форму, и сама форма и её обработчик при таком методе обязаны быть реализованы в одном скрипте.
Таким образом, "лобовое" решение влечёт за собой массу проблем как с точки зрения юзабилити, так и с точки зрения структуры приложения.
Проблем этих можно избежать, если после обработки POST -запроса сразу же делать GET -редирект. Если форма заполнена правильно, то редирект делается на нужный адрес, а если неправильно — то обратно на страницу с формой. При этом ошибочно введённые данные передаются через механизм сессий.
Алгоритм обработки формы выглядит следующим образом:
- Обработчик получает данные от пользователя и проверяет их на корректность
- Если всё правильно, то данные обрабатываются и делается редирект на другую страницу сайта (согласно общей логике системы)
- Если в данных есть ошибки, то запускается сессия, и в сессионные переменные записывается следующая информация:
- Имя (идентификатор) формы. Например,
login_form . Желательно, хотя и не обязательно (об этом чуть ниже), чтобы имя было уникальным в пределах сайта;
- Все введённые пользователем данные (например, в виде ассоциативного массива "имя поля" => "значение");
- Перечень полей формы, в которых есть ошибки;
- Словесное описание ошибки.
- Делается редирект обратно на страницу с формой.
Cтраница, показывающая форму с неким именем (ту же login_form ), должна сделать следующее:
- Если в сессионных переменных нет данных по форме с нужным именем, то пользователю выдаётся чистая (или заполненная значениями по умолчанию) форма.
- Если в сессионных переменных есть данные по форме с нужным именем, то пользователю выдаются:
- Словесное описание ошибки;
- Форма с полями, заполненными введёнными пользователем данными и, возможно, с выделенными ошибочными полями.
- После вывода формы с ошибкой вся информация о ней в сессии стирается.
Последний пункт нужен для того, чтобы не возникло нежелательных взаимодействий между разными формами на сайте с одинаковыми именами (поддерживать строгую уникальность имён довольно трудоёмко) и чтобы не возникло эффекта "залипшей" формы — когда при каждом заходе форма будет показывать ошибочно введённые значения. На самом деле, их достаточно показать ровно один раз — сразу после заполнения формы. После этого информация о данном заполнении формы уже не нужна и её можно и нужно удалить. Таким образом, сессия как таковая живёт очень короткое время — между POST -запросом и выводом формы с ошибкой. При таком подходе уникальность имён не обязательна, поскольку "пересечься" формы могут только если нажать кнопку Submit одновременно в двух открытых окнах с одной и той же страницей.
Пример — регистрация нового пользователя.
<?php
// Файл addNewUserForm.php
include_once( 'header.php' );
// Если при заполнении формы были допущены ошибки
if ( isset( $_SESSION['addNewUserForm'] ) ) {
echo $_SESSION['addNewUserForm']['error'];
$login = htmlspecialchars ( $_SESSION['addNewUserForm']['login'] );
$password = htmlspecialchars ( $_SESSION['addNewUserForm']['password'] );
$confirm = '';
$mail = htmlspecialchars ( $_SESSION['addNewUserForm']['mail'] );
$www = htmlspecialchars ( $_SESSION['addNewUserForm']['www'] );
unset( $_SESSION['addNewUserForm'] );
} else {
$login = '';
$password = '';
$confirm = '';
$mail = '';
$www = '';
}
echo '<form name="addNewUser" action="addNewUser.php" method="POST">'."\n";
echo '<table border="1">'."\n";
echo '<tr>'."\n";
echo '<td><strong>Имя:</strong></td>'."\n";
echo '<td><input type="text" name="login" maxlength="30" value="'.$login.'" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo '<td><strong>Пароль:</strong></td>'."\n";
echo '<td><input type="password" name="password" maxlength="30" value="'.$password.'" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo '<td><strong>Подтвердите пароль:</strong></td>'."\n";
echo '<td><input type="password" name="confirm" maxlength="30" value="'.$confirm.'" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo '<td><strong>Адрес e-mail:</strong></td>'."\n";
echo '<td><input type="text" name="mail" maxlength="60" value="'.$mail.'" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo '<td><strong>Домашняя страничка:</strong></td>'."\n";
echo '<td><input type="text" name="www" maxlength="60" value="'.$www.'" /></td>'."\n";
echo '</tr>'."\n";
echo '<tr>'."\n";
echo '<td> </td>'."\n";
echo '<td><input type="submit" name="submitForm" value="Отправить" />'."\n";
echo '</tr>'."\n";
echo '</table>'."\n";
echo '<form>'."\n";
include_once( 'footer.php' );
?>
<?php
// Файл addNewUser.php
include_once( 'header.php' );
// Обрезаем переменные до длины, указанной в параметре maxlength тега input
$login = substr( $_POST['login'], 0, 30 );
$password = substr( $_POST['password'], 0, 30 );
$confirm = substr( $_POST['confirm'], 0, 30 );
$mail = substr( $_POST['mail'], 0, 60 );
$www = substr( $_POST['www'], 0, 60 );
// Обрезаем лишние пробелы
$login = trim( $login );
$password = trim( $password );
$confirm = trim( $confirm );
$mail = trim( $mail );
$www = trim( $www );
// Проверяем, заполнены ли обязательные поля
$error = '';
if ( empty( $login ) ) $error = $error.'<li>не заполнено поле "Имя"</li>'."\n";
if ( empty( $password ) ) $error = $error.'<li>не заполнено поле "Пароль"</li>'."\n";
if ( empty( $confirm ) ) $error = $error.'<li>не заполнено поле "Подтвердите пароль"</li>'."\n";
if ( empty( $mail ) ) $error = $error.'<li>не заполнено поле "Адрес e-mail"</li>'."\n";
// Проверяем, совпадают ли пароли
if ( !empty( $password ) and !empty( $confirm ) and $password != $confirm )
$error = $error.'<li>не совпадают пароли</li>'."\n";
// Проверяем поля формы на недопустимые символы
if ( !empty( $login ) and !eregi( "[-_[:blank:]0-9a-zа-я]+", $login ) )
$error = $error.'<li>поле "Имя" содержит недопустимые символы</li>'."\n";
if ( !empty( $password ) and !eregi( "[-_0-9a-z]+", $password ) )
$error = $error.'<li>поле "Пароль" содержит недопустимые символы</li>'."\n";
if ( !empty( $confirm ) and !eregi( "[-_0-9a-z]+", $confirm ) )
$error = $error.'<li>поле "Подтвердите пароль" содержит недопустимые символы</li>'."\n";
// Проверяем корректность e-mail
if ( !empty( $mail ) and !preg_match( "#^[0-9a-z_\-\.]+@[0-9a-z\-\.]+\.[a-z]{2,6}$#i", $mail ) )
$error = $error.'<li>поле "Адрес e-mail" должно соответствовать формату somebody@somewhere.ru</li>'."\n";
// Проверяем корректность URL домашней странички
if ( !empty( $www ) and !preg_match( "#^(http:\/\/)?(www.)?[0-9a-z\-\.]+\.[a-z]{2,6}\/?$#i", $www ) )
$error = $error.'<li>поле "Домашняя страничка" должно соответствовать формату http://www.homepage.ru</li>'."\n";
// Если были допущены ошибки при заполнении формы - перенаправляем посетителя на страницу регистрации
if ( !empty( $error ) ) {
$_SESSION['addNewUserForm'] = array();
$_SESSION['addNewUserForm']['error'] = '<p class="errorMsg">При заполнениии формы были допущены ошибки:</p>'.
"\n".'<ul class="errorMsg">'."\n".$error.'</ul>'."\n";
$_SESSION['addNewUserForm']['login'] = $login;
$_SESSION['addNewUserForm']['password'] = $password;
$_SESSION['addNewUserForm']['mail'] = $mail;
$_SESSION['addNewUserForm']['www'] = $www;
header( 'Location: addNewUserForm.php' );
die();
}
// Все поля заполнены правильно - продолжаем регистрацию
$query = "INSERT INTO ".TABLE_USERS."
(
login,
pass,
mail,
www
)
VALUES
(
'".mysql_real_escape_string( $login )."',
'".mysql_real_escape_string( md5( $password ) )."',
'".mysql_real_escape_string( $mail )."',
'".mysql_real_escape_string( $www )."'
);";
$res = mysql_query( $query );
if ( $res )
header( "Location: loginForm.php" );
else
header( "Location: addNewUserForm.php" );
include_once( 'footer.php' );
?>
|
|