Ноутбуки

Повторная отправка формы после обновления страницы. Отмена повторной отправки формы

Повторная отправка формы после обновления страницы. Отмена повторной отправки формы

Мне часто задают вопросы относительно отмены повторной отправки формы . Например, Вы сделали форму добавления комментария, добавили обработчик на эту же страницу. Затем при добавлении комментария он успешно добавляется, но стоит пользователю нажать F5 , как форма будет отправлена ещё раз . А F5 пользователь может легко нажать, если страница будет долго грузиться. В итоге, вместо 1-го комментария будет целых 2 , а то и больше. В этой статье я покажу, как этого можно избежать.

Для начала разберём более подробно проблему на примере этого кода:


echo "Квадрат числа ".$_POST["x"]." равен ".pow($_POST["x"], 2);
}
?>








Нажав на кнопку "Возвести в квадрат ", Вы увидите результат работы скрипта. Но стоит после этого пользователю нажать F5 , как скрипт снова будет выполняться. В данном случае, это не так критично, как с добавлением комментарием, однако, зачем нужна лишняя нагрузка на сервер?

Теперь поговорим о способах решения данной проблемы. Первый способ - выделить скрипт обработки в отдельный файл . Тогда в атрибуте action у тега form надо добавить путь к этому скрипту. А сам скрипт должен сохранять куда-нибудь результат своих действий, либо переменные пришедшие на скрипт, а после делать редирект обратно. В общем, смотрите код скрипта:

session_start();

header("Location: ".$_SERVER["HTTP_REFERER"]);
exit;
?>

А код страницы с формой теперь будет выглядеть так:

session_start();

}
?>








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

session_start();
if (!empty($_POST["sqr"])) {
$_SESSION["x"] = $_POST["x"];
header("Location: ".$_SERVER["REQUEST_URI"]);
exit;
}
if (isset($_SESSION["x"])) echo "Квадрат числа ".$_SESSION["x"]." равен ".pow($_SESSION["x"], 2);
?>








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

Подведу итог того, как отменить повторную отправку формы :

  • Либо делать обработку в отдельном файле , а затем оттуда делать редирект назад.
  • Либо делать обработку в том же файле, что и форма, но при этом после обработки делать редирект на ту же страницу .

Вот так это делается в простых скриптах. Да и, в сложных, в конечном счёте делается то же самое.

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

Предотвращение множественной отправки с Javascript

Вероятно, использование Javascript для предотвращения повторной отправки формы является самым легким способом. Когда пользователь отправляет форму, можно отключить кнопку «Отправить» и изменить её название на что-либо более понятное «Идет отправка, пожалуйста, подождите…»

Первым шагом является задание уникального идентификатора id , например id=»myButton»:

Вторым (и последним) шагом является задание двух Javascript команд в теге

. Первая команда будет отключать кнопку «Отправить» после отправки формы, а вторая будет изменять текст кнопки, чтобы дать пользователю представление о том, что происходит. Следующий код нужно добавить в тег :

Тег form будет выглядеть следующим образом:

onsubmit=»document.getElementById(‘myButton’).disabled=true;

document.getElementById(‘myButton’).value=’Идет отправка, пожалуйста, подождите..’;»

А после нажатия кнопка превратиться в такую

Вот и всё. Данный прием должен работать на большинстве браузеров (IE 5+, FireFox, Opera, Chrome).

Предотвращение множественной отправки с использованием Cookies

Если вы хотите избежать повторной отправки форм на протяжении всей сессии браузера (или дольше), то можете рассмотреть возможность использования cookies. Например, изменить свой сценарий редактирования формы для передачи cookie браузеру после обработки формы, но до отправки HTML заголовков. Размещение данного кода после команды mail() должно работать в большинстве случаев:

setcookie(‘FormSubmitted’, ‘1’);

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


{
die(‘Вы может отправить форму только один раз за сессию!’);
}

Вот и всё.

Вот как будет выглядеть окончательная версия сценария с использованием cookie для блокирования повторной отправки. Обратите внимание, что часть кода была добавлена вверху сценария, а код для записи cookie находится после функции mail().

/* Предотвращение повторной отправки */

if (isset($_COOKIE[‘FormSubmitted’])
{
show_error(‘Вы может отправить форму только один раз за сессию!’);
}

/* Установка получателя e-mail */

$myemail = «[email protected]»;

/* Проверка введенных на форме значений с помощью функции check_input function */

$yourname = check_input($_POST[‘yourname’], «Введите ваше имя»);
$subject = check_input($_POST[‘subject’], «Тема сообщения»);
$email = check_input($_POST[’email’]);
$website = check_input($_POST[‘website’]);
$likeit = check_input($_POST[‘likeit’]);
$how_find = check_input($_POST[‘how’]);
$comments = check_input($_POST[‘comments’], «Ваши комментарии»);

/* Если введен неправильный адрес e-mail, показать сообщение об ошибке */
if (!preg_match(«/(+@+.+)/», $email))
{
show_error(«Вы ввели неправильный E-mail»);
}

/* Если URL неправильный, устанавливаем пустое значение для переменной $website */
if (!preg_match(«/^(https?://++.+)/i», $website))
{
$website = »;
}

/* Подготовим e-mail сообщение */

$message = «Hello!
Ваши контактные данные отправлены:
Name: $yourname
E-mail: $email
URL: $website
Нравится ли веб-сайт? $likeit
Как вы нашли веб-сайт? $how_find

В свое время озадачился вопросом - как защитить страницы сайта от повторной отправки данных формы во время обновления страницы (если перед этим была отправка, естественно).
Каждый веб-мастер и разработчик наверное знает, что если на сайте вы нажали кнопку «отправить», заполнив какую-либо форму, то после отправки, если попытаться обновить страницу браузер выдаст сообщение с подтверждением повторной отправки.
В некоторых моментах это бывает недопустимо. Например, в случае элементарной формы обратной связи. Когда пользователь заполнил форму и отправил сообщение, а потом по какой-то ему одному известной причине обновил страницу, письмо ушло снова. Это может, конечно, и не такой фатальный случай, просто как пример. Все гораздо болезненнее, например, при отправке заказа в интернет-магазине.
Так вот задался вопросом поиска решения этой проблемы и понял, что решение только одно: использование перенаправления после отправки формы header (‘location: адрес’). Т.е. все просто – после отправки вызываем перенаправление (можно даже на ту же страницу) и все! Обновление страницы будет чистым, без всяких заполненных POST-ов и GET-ов.

Все бы хорошо, но лично я испытал с этим некоторые проблемы. Они заключаются в следующем. Раньше, без использования переадресации механизм отправки данных на моих сайтах работал следующим образом:
Пользователь заполняет форму, жмет «отправить», скрипт принимает отправленные данные, проверяет их на корректность (валидность, заполненность обязательных данных и т.д.) и выдает ответ – либо операция прошла успешно, либо произошла ошибка и список ошибок (например: ошибка - поле «имя» не заполнено. А на странице отправки уже в свою очередь выдается соответствующее сообщение: отправка успешна или не успешна.
В случае если отправка не успешна, то форма остается на экране и поля ее заполнены теми данными, которые пользователь ввел. Т.е. данные берутся из переменной $_POST (если метод POST) и встают в соответствующие поля (т.е. возвращаются из поста в свои поля, чтобы заново их не вводить). Ведь всех же бесит когда ты заполнил форму, и не дай бог что-то указал неправильно и при попытке отправить тебе выдается сообщение, что что-то заполнено неправильно, а форма обновляется и снова пуста. И приходится из-за одного неправильно заполненного поля заново ее заполнять.
Так вот, как уже сказал, в случае неуспешного заполнения, форма остается заполненной данными, взятыми из $_POST, и пользователь может исправить неправильные данные и снова отправить форму.
Все было хорошо и все работало.
Но потом я сделал отправку с использованием переадресации и получилось так, что после нажатия кнопки «отправить», в случае неуспешного заполнения, форма обновлялась и в ней уже не могли остаться заполненные поля, т.к. раньше они автоматом заполнялись из массива $_POST, а теперь после того как произошла переадресация $_POST подчистился как будто и не было никакой отправки.
Но и на этот случай нашелся выход. Использовать сессии. Т.е. до вызова header передавать в переменные сессии данные из POST и уже потом после переадресации ими оперировать.
В итоге код усложнился значительно. Отладка усложнилась, т.к. вообще трудно определить что происходит с функциями в тот момент когда случается переадресация. Если ты сделал какую-то ошибку в кодах (которая проявляется именно в момент отправки), то она даже не высветится, т.к. произойдет переадресация и ты даже не увидишь сообщение об ошибке.
В общем, мне после внедрения в свои коды header стало сложнее работать с моими приложениями. Разработка/доработка/поиск ошибок усложнился. Но и отказаться я от этого не могу.
И продолжаю задаваться вопросом: а есть ли другие, более элегантные решения?

В свое время озадачился вопросом - как защитить страницы сайта от повторной отправки данных формы во время обновления страницы (если перед этим была отправка, естественно).
Каждый веб-мастер и разработчик наверное знает, что если на сайте вы нажали кнопку «отправить», заполнив какую-либо форму, то после отправки, если попытаться обновить страницу браузер выдаст сообщение с подтверждением повторной отправки.
В некоторых моментах это бывает недопустимо. Например, в случае элементарной формы обратной связи. Когда пользователь заполнил форму и отправил сообщение, а потом по какой-то ему одному известной причине обновил страницу, письмо ушло снова. Это может, конечно, и не такой фатальный случай, просто как пример. Все гораздо болезненнее, например, при отправке заказа в интернет-магазине.
Так вот задался вопросом поиска решения этой проблемы и понял, что решение только одно: использование перенаправления после отправки формы header (‘location: адрес’). Т.е. все просто – после отправки вызываем перенаправление (можно даже на ту же страницу) и все! Обновление страницы будет чистым, без всяких заполненных POST-ов и GET-ов.

Все бы хорошо, но лично я испытал с этим некоторые проблемы. Они заключаются в следующем. Раньше, без использования переадресации механизм отправки данных на моих сайтах работал следующим образом:
Пользователь заполняет форму, жмет «отправить», скрипт принимает отправленные данные, проверяет их на корректность (валидность, заполненность обязательных данных и т.д.) и выдает ответ – либо операция прошла успешно, либо произошла ошибка и список ошибок (например: ошибка - поле «имя» не заполнено. А на странице отправки уже в свою очередь выдается соответствующее сообщение: отправка успешна или не успешна.
В случае если отправка не успешна, то форма остается на экране и поля ее заполнены теми данными, которые пользователь ввел. Т.е. данные берутся из переменной $_POST (если метод POST) и встают в соответствующие поля (т.е. возвращаются из поста в свои поля, чтобы заново их не вводить). Ведь всех же бесит когда ты заполнил форму, и не дай бог что-то указал неправильно и при попытке отправить тебе выдается сообщение, что что-то заполнено неправильно, а форма обновляется и снова пуста. И приходится из-за одного неправильно заполненного поля заново ее заполнять.
Так вот, как уже сказал, в случае неуспешного заполнения, форма остается заполненной данными, взятыми из $_POST, и пользователь может исправить неправильные данные и снова отправить форму.
Все было хорошо и все работало.
Но потом я сделал отправку с использованием переадресации и получилось так, что после нажатия кнопки «отправить», в случае неуспешного заполнения, форма обновлялась и в ней уже не могли остаться заполненные поля, т.к. раньше они автоматом заполнялись из массива $_POST, а теперь после того как произошла переадресация $_POST подчистился как будто и не было никакой отправки.
Но и на этот случай нашелся выход. Использовать сессии. Т.е. до вызова header передавать в переменные сессии данные из POST и уже потом после переадресации ими оперировать.
В итоге код усложнился значительно. Отладка усложнилась, т.к. вообще трудно определить что происходит с функциями в тот момент когда случается переадресация. Если ты сделал какую-то ошибку в кодах (которая проявляется именно в момент отправки), то она даже не высветится, т.к. произойдет переадресация и ты даже не увидишь сообщение об ошибке.
В общем, мне после внедрения в свои коды header стало сложнее работать с моими приложениями. Разработка/доработка/поиск ошибок усложнился. Но и отказаться я от этого не могу.
И продолжаю задаваться вопросом: а есть ли другие, более элегантные решения?