Как правильно предотвратить повторную отправку формы?

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

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

- Если после добавления сообщения в базу делать перенаправление на страницу вида index.php?message=Сообщение%20успешно%20добавлено! , то это сообщение после обновления страницы так и будет появляться.

+ Поэтому я хочу сделать так: на сайте используются свои сессии в базе MySQL, но чтобы не напрягать базу, я хочу использовать встроенные в php сессии как раз для этого дела, а именно: в месте вывода сообщения об успешной отправке, то есть после физического добавления информации в базу, стартовать сессию, в нее добавить переменную с сообщением "Сообщение успешно добавлено!", затем сделать перенаправление на эту же страницу, где выводятся все сообщения. А в коде самой страницы, стартовать сессию, и если есть в ней переменная с сообщением, то вывести его и удалить переменную.

+ А еще лучше, сделать массив сообщений и выводить их все, но если вдруг открыто несколько вкладок, то есть очень малая вероятность, что будет что-то одновременно и отобразится сообщение не в той вкладке, поэтому наверно стоит сделать какое-то случайное имя переменной, и передавать это имя GET параметром в url перенаправления, и уже по нему выводить и удалять переменную. Тогда вроде всё нормально.

Как Вам такой вариант, и как вообще это правильно делать, может, всё-таки отдельную страницу, как на многих форумах "Сообщение добавлено, сейчас Вы будете перенаправлены"?

Заранее всем спасибо за ответы!
  • Вопрос задан
  • 22393 просмотра
Решения вопроса 2
akubintsev
@akubintsev
Опытный backend разработчик
Я бы не стал хранить массив сообщений в сессии, это вообще дурная практика что-либо складировать в неё, кроме пары-тройки идентификаторов.
Для гарантии от дублирования есть приём:
- на сервере генерируется идентификатор нового сообщения
- сервер передает этот идентификатор клиенту
- клиент заполняет сообщение и отсылает его серверу с тем же самым идентификатором
- сервер при получении ставит в соответствие идентификатору сообщение (т.е. заполняет соответствующее поле в БД, если оно было пустым)

Рассмотрим теперь сценарии при попытке отправки с клиента сообщения:
- идентификатор сообщения задан:
-- на сервере уже есть сообщение с таким id => отказ
-- на сервере нет такого id => отказ (возможно попытка поиска уязвимости)
- идентификатор не задан => отказ
Ответ написан
maxaon
@maxaon
Да, вы вполне корректно описали решение проблемы с повторной отправкой формы.
Однако лучше остановится на чем-то одном.
Перенаправлять пользователя и хранить массив сообщений в сессии. Выводить сообщения, потом удалять. Беспокоится о том, что пользователь заполнит форму, откроет другую вкладку с вашим сайтом, потом перейдет обратно, где была форма и это за 50-200 мс, думаю не стоит. Так сделано в ZF1 и ZF2 и много наверное где.
Второй вариант - перенаправлять пользователя по другому адресу, тоже можно, но это не так элегантно как в первом варианте.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
Весь текст вопроса не читал, лень :)
Вот так делаю я, после чтения и обработки полей (полученных данных)
$_POST = NULL;
header("Location: " . Url::$url);
exit();

данные передаются POST-ом
Url::$url - содержит ссылку на текущую страницу.
Ответ написан
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Отправлять данные ajax'ом и пусть обновляют страницу, если надо.
Ответ написан
@coderxOne
Короче все просто..
после обработки данных сохраняете массив в сессии и делаете редирект на другую функцию, в другой функции проверяете на наличие сессии и выводите массив. Вот и все теперь при переходе на другую страницу не будет запроса на перезагрузку)).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы