Добро пожаловать!
Здесь вы можете найти ответ на интересующий вас вопрос в отрасли сайтостроения, познакомится ближе с web технологиями и web стандартами.

Статьи

Обработка ошибочного заполнения формы

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

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

Во-первых, если пользователь нажмёт на такой странице Refresh, то браузер выведет сообщение о том, что страницу обновить невозможно без повторной отсылки данных. Во-вторых, если пользователь правильно заполнил форму во второй раз, и ушёл на другую страницу, то при нажатии на кнопку Back (т.е. при попытке вернуться на POST-страницу) ему опять выведется сообщение о необходимости повторной отсылки данных. Мало того, что это совершенно нелогично и неудобно с точки зрения пользователя (он ведь уже отправил данные!), так ещё и если он в этот момент нажмёт "OK", то форма и в самом деле запостится во второй раз. Наконец, чтобы не дублировать код, отображающий форму, и сама форма и её обработчик при таком методе обязаны быть реализованы в одном скрипте.

Таким образом, "лобовое" решение влечёт за собой массу проблем как с точки зрения юзабилити, так и с точки зрения структуры приложения.

Проблем этих можно избежать, если после обработки POST-запроса сразу же делать GET-редирект. Если форма заполнена правильно, то редирект делается на нужный адрес, а если неправильно — то обратно на страницу с формой. При этом ошибочно введённые данные передаются через механизм сессий.

Алгоритм обработки формы выглядит следующим образом:

  1. Обработчик получает данные от пользователя и проверяет их на корректность
  2. Если всё правильно, то данные обрабатываются и делается редирект на другую страницу сайта (согласно общей логике системы)
  3. Если в данных есть ошибки, то запускается сессия, и в сессионные переменные записывается следующая информация:
    • Имя (идентификатор) формы. Например, login_form. Желательно, хотя и не обязательно (об этом чуть ниже), чтобы имя было уникальным в пределах сайта;
    • Все введённые пользователем данные (например, в виде ассоциативного массива "имя поля" => "значение");
    • Перечень полей формы, в которых есть ошибки;
    • Словесное описание ошибки.
  4. Делается редирект обратно на страницу с формой.

Cтраница, показывающая форму с неким именем (ту же login_form), должна сделать следующее:

  1. Если в сессионных переменных нет данных по форме с нужным именем, то пользователю выдаётся чистая (или заполненная значениями по умолчанию) форма.
  2. Если в сессионных переменных есть данные по форме с нужным именем, то пользователю выдаются:
    • Словесное описание ошибки;
    • Форма с полями, заполненными введёнными пользователем данными и, возможно, с выделенными ошибочными полями.
  3. После вывода формы с ошибкой вся информация о ней в сессии стирается.

Последний пункт нужен для того, чтобы не возникло нежелательных взаимодействий между разными формами на сайте с одинаковыми именами (поддерживать строгую уникальность имён довольно трудоёмко) и чтобы не возникло эффекта "залипшей" формы — когда при каждом заходе форма будет показывать ошибочно введённые значения. На самом деле, их достаточно показать ровно один раз — сразу после заполнения формы. После этого информация о данном заполнении формы уже не нужна и её можно и нужно удалить. Таким образом, сессия как таковая живёт очень короткое время — между 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>&nbsp;</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'], 030 );
$password  substr$_POST['password'], 030 );
$confirm   substr$_POST['confirm'], 030 );
$mail      substr$_POST['mail'], 060 );
$www       substr$_POST['www'], 060 );

// Обрезаем лишние пробелы
$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_stringmd5$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' );

?>