Блог студии веб-дизайна «Make a Site» Дизайн, верстка, программирование, наполнение и раскрутка сайтов.

Способы защиты от повторной отправки формы при перезагрузке страницы

После отправки данных формы и их обработки серверным скриптом, необходимо предпринять меры по защите от повторной отправки данных во избежании нежелательных дублей записей в базе данных и писем на почте. Давайте рассмотрим два простых способа защиты форм от повторной отправки данных.

Способы защиты от повторной отправки формы при перезагрузке страницы
Содержание статьи

Все начинается с того, что пользователь заполняет ту или иную html форму на вашем сайте, после чего, когда все ее поля заполнены, он отправляет данные на сервер, нажимая кнопку «Отправить», «Оформить заказ», «Купить» и т. д. Причем отправка данных формы на сервер может производиться двумя способами — GET и POST.

GET-данные – незашифрованные данные, которые передаются прямо через адресную строку, добавляя соответственные переменные к адресу текущей страницы, например, https://yandex.ru/search/?text=example. Как видно из примера — к основному адресу добавляется параметр text, значение которого и есть поисковый запрос, который вы отправляете через форму поиска на сервер Яндекса.

POST-данные – зашифрованные данные, которые не видны в адресной строке и ссылку на них дать нельзя. Однако есть одна небольшая проблема — при обновлении страницы, сразу после отправки POST-данных, любой из известных на данный момент браузеров заботливо переспросит у вас — «Чтобы отобразить эту страницу, Firefox должен отправить информацию, которая повторит любое ранее произведённое действие (например, запрос на поиск или онлайн-покупка)». Такой вопрос вам задаст Файерфокс, если сразу после отправки POST-данных нажать кнопку F5 или обновить страницу каким-то другим способом, например, используя специальную кнопку в панели инструментов браузера. Другие браузеры спросят то же самое, только другими словами.

Конечно не многие пользователи обновляют страницу сразу после отправки данных формы (казалось бы, зачем вообще это делать), но иногда такая же проблема может возникнуть при нажатии кнопки «Назад». Если переход будет осуществляться на страницу, с которой отправлялись данные формы, она не загрузится, а вместо этого на экране появится сообщение о том, что данные устарели или что-то в этом роде.

Проблема повторной отправки данных форм актуальна в тех случаях, когда сразу после, происходит добавление новой строки в базу данных, например, заказ в интернет-магазине, регистрация нового пользователя и т. д., а также отправляется соответствующее email-уведомление. Для того, чтобы избежать нежелательных дублей записей в базе данных и писем на почте, необходимо предотвращать повторную отправку данных. А если сказать точнее — предотвращать или игнорировать. Поэтому мы рассмотрим два основных способа:

Способ №1: «Переадресация» — предотвращение повторной отправки данных

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

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

header('Location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'?success'); exit();

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

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

Главным минусом этого способа является лишнее обновление страницы. Это конечно не критично, но и не совсем обязательно, поэтому первый способ нельзя назвать идеальным.

Способ №2: «Сессия» — игнорирование данных, отправленных повторно

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

Суть метода — к целевой форме нужно добавить дополнительное скрытое поле с произвольным именем и с произвольным значением, например так:

<input type='hidden' name='sessid' value='<?=$_SESSION['sessid']?>'>

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

/* сама функция генерации абстрактного хеша */
function setRandomSessid() {
	$_SESSION['sessid'] = md5(date('d.m.Y H:i:s').rand(1, 1000000));
}
/* создаем сессию в начале скрипта */
setRandomSessid();

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

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

setRandomSessid();

Теперь нам осталось только сверить сессию sessid со скрытым значением одноименного поля sessid, переданным нашей с вами формой. Если они идентичны, то есть смысл проверять остальные данные, а если нет — форму попытались отправить заново, при этом сама сессия переопределилась, а значение sessid, которое передавалось через форму осталось старым.

if(isset($_POST) && $_POST['sessid'] == $_SESSION['sessid']) {
	/* только в этом случае приступаем к проверке данных формы */
}

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

Как видите, все очень просто — мы с вами разобрали два простых способа повторной отправки данных формы. Оба прекрасно работают, хорошо себя зарекомендовали и неоднократно проверялись на практике на разных сайтах. Но на наш взгляд, предпочтительней все-таки использовать второй способ с сессией.



Предыдущая статья:
Красивые CSS кнопки для сайта без изображений

Читайте также:
Семантическое ядро сайта

Возможно, вам это интересно:



Блог студии веб-дизайна «Make a Site».
Дизайн, верстка, программирование, наполнение и раскрутка сайтов.

Текущий проект: «Stream Booster» — раскрутка Twitch и YouTube каналов

Студия веб-дизайна «Make a site»