Удобное сохранение значений форм в сессию в случае ошибок при добавлении информации

15 апреля 2011 г.

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

Для этого используют несколько разных инструментов

  1. Данные сохраняются в куках, и при следующем показе формы достаются оттуда
  2. Пишется javascript, который не дает отправить форму пока не будут заполнены все неоходимые поля
  3. Данные сохраняются в сесиии

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

Javascript — это сила. C помощью него можно не только не дать данным отправиться, пока не будут заполнены все поля, что уменьшает вероятность потери данных, но и посылать данные вообще не перезагружая страницу, с помощью ajax. В этом случае данные не только не пропадут с экранов, напротив, часто стоит проблема какие действия принимать после отправки данных, чтобы эту форму убрать. Этот способ не потерять данные формы довольно надежный, но к сожалению не все браузеры его поймут. Например не все мобильники и смартфоны поодерживают javascript, а тем более ajax, так что им скорее всего не повезет, если забыть заполнить какое-то поле. Будут матюкаться, особенно если большой текст пропадет. А его на мобильнике писать — это не клавиатуре быстро набрать. Так что если кому и не повезет — то только тем, кто меньше всего этого хотелбы.

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

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

Но писать форм приходилось много и каждую последующую форму приходилось упрощать. И так я упрощал то тех пор, пока меня не осенило как это правильно нужно делать.

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

И так, определим эти самые действия.
Начнем с обработчиков.

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

// cохранение значения поля в сессию
 function insert_value($key, $name)
 {
 if (isset($_POST[$name]))
 {
 if (!empty($_POST[$name]))
 {
 $_SESSION[$key . $name] = $_POST[$name];
 }
 }
 }
 

$key — идентификатор формы, чтобы не было путаницы.
$name — имя поля, значение которого требуется сохранить.

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

// занесение ошибок в сессию
 function insert_error($key, $error)
 {
 $_SESSION[$key] = $error;
 }

$key — здесь так же идентификатор формы, думаю больше об этом писать не стоит.
$error — ошибки (строка), вызванные в процессе проверки данных на корректность.

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

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

// очистка сессии от мусора
 function delete_value($key, $name)
 {
 if (isset($_SESSION[$key . $name])) unset($_SESSION[$key . $name]);
 }
 // очистка сессии от мусора
 function delete_error($key)
 {
 if (isset($_SESSION[$key])) unset($_SESSION[$key]);
 }
 

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

 // показ ошибок
 function select_error($key)
 {
 if (isset($_SESSION[$key])) return $_SESSION[$key];
 }

Ну и для вывода сохраненной информации в соответствующие поля последний штрих

// безопасное представление value поля
 function select_value($key, $name)
 {
 if (isset($_SESSION[$key . $name])) return htmlspecialchars($_SESSION[$key . $name]);
 }

Здесь лучше сразу учесть вопрос безопасности, и забыть о том, что кто-либо исполнит в вашей форме код раз и навсегда.

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

Форма:

<?php
 session_start();
 include 'function.php';
?>

<?php echo select_error('addpost');?>

<?php echo select_value('addpost', 'smalltext');?>

<?php echo select_value('addpost', 'bigtext');?>

Обработчик:

<?php

session_start();
 include 'function.php';

$name = isset($_POST['name']) ? trim($_POST['name']) : '';
 $smalltext = isset($_POST['smalltext']) ? trim($_POST['smalltext']) : '';
 $bigtext = isset($_POST['bigtext']) ? trim($_POST['bigtext']) : '';

$error = '';

if (empty($name)) $error .= 'Не указано имя
';
 else insert_value('addpost', 'name');

if (empty($smalltext)) $error .= 'Не указан малый текст
';
 else insert_value('addpost', 'smalltext');

if (empty($bigtext)) $error .= 'Не указан большой текст
';
 else insert_value('addpost', 'bigtext');

// контрольное условие
 if (!empty($error))
 {
 // сохраняем ошибки заполнения формы
 insert_error('addpost', $error);
 header('Location: form.php'); exit;
 }
 else
 {
 // в случае успешного прохождения формы
 // обязательно очищаем сессию от ненужного мусора
 delete_value('addpost', 'name');
 delete_value('addpost', 'smalltext');
 delete_value('addpost', 'bigtext');
 delete_error('addpost');

// говорим ок
 echo 'Данные сохранены
<a href="http://form.php">Перейти к форме</a>';
 }

?>

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

<?php

// сохранение value поля в сессию
 function insert_value($key, $name)
 {
 if (isset($_POST[$name]))
 {
 if (!empty($_POST[$name]))
 {
 $_SESSION[$key . $name] = $_POST[$name];
 }
 }
 }

// безопасное представление value поля
 function select_value($key, $name)
 {
 if (isset($_SESSION[$key . $name])) return htmlspecialchars($_SESSION[$key . $name]);
 }

// очистка сессии от мусора
 function delete_value($key, $name)
 {
 if (isset($_SESSION[$key . $name])) unset($_SESSION[$key . $name]);
 }

// занесение ошибок в сессию
 function insert_error($key, $error)
 {
 $_SESSION[$key] = $error;
 }

// показ ошибок
 function select_error($key)
 {
 if (isset($_SESSION[$key])) return $_SESSION[$key];
 }

// очистка сессии от мусора
 function delete_error($key)
 {
 if (isset($_SESSION[$key])) unset($_SESSION[$key]);
 }

?>
Теги: рубрика PHP, Интернет
  • Похожие статьи
  • Предыдущие из рубрики