Как предотвратить повторную отправку формы при обновлении страницы (F5 / CTRL+R)
У меня есть простая форма, которая отправляет текст в моей таблице SQL. Проблема в том, что после отправки текста пользователь может обновить страницу, и данные будут отправлены снова без повторного заполнения формы. Я могу перенаправить пользователя на другую страницу после отправки текста, но я хочу, чтобы пользователи оставались на той же странице.
Я помню, что читал что-то о предоставлении каждому пользователю уникального идентификатора сеанса и сравнении его с другим значением, которое решило проблему, которую я имею, но я забыл, где он.
18 ответов
используйте шаблон Post/Redirect/Get. http://en.wikipedia.org/wiki/Post/Redirect/Get
с моим веб-сайтом Я сохраню сообщение в cookie или сеансе, перенаправлю после публикации, прочитаю cookie/session, а затем очищу значение этой переменной сеанса или cookie.
Я также хотел бы отметить, что вы можете использовать подход javascript,window.history.replaceState
чтобы предотвратить повторную подачу на кнопку обновления и возврата.
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
доказательство концепции здесь:https://dtbaker.net/files/prevent-post-resubmit.php
Я бы все равно рекомендовал подход Post/Redirect/Get, но это новое решение JS.
вы действительно должны использовать шаблон Post Redirect Get для обработки этого, но если вы каким-то образом оказались в положении, когда PRG не жизнеспособен (например, сама форма находится в include, предотвращая перенаправления), вы можете хэшировать некоторые параметры запроса, чтобы сделать строку на основе содержимого, а затем проверить, что вы ее еще не отправили.
//create digest of the form submission:
$messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);
//and check it against the stored value:
$sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';
if($messageIdent!=$sessionMessageIdent){//if its different:
//save the session var:
$_SESSION['messageIdent'] = $messageIdent;
//and...
do_your_thang();
} else {
//you've sent this already!
}
вы можете pervent формы повторной отправки через переменную сеанса, как
сначала вы должны установить rand () в textbox и $_SESSION['rand'] на странице формы
<form action="" method="post">
<?php
$rand=rand();
$_SESSION['rand']=$rand;
?>
<input type="hidden" value="<?php echo $rand; ?>" name="randcheck" />
Your Form's Other Field
<input type="submit" name="submitbtn" value="submit" />
</form>
после проверки $_SESSION ['rand'] со значением textbox $_POST['randcheck'] Как
if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
{
//Your Code here
}
-
используйте заголовок и перенаправьте страницу.
header("Location:your_page.php");
вы можете перенаправить на ту же страницу или другую страницу. -
Unset $_POST после вставки его в базу данных.
unset($_POST);
при обработке формы вы перенаправляете на другую страницу:
... process complete....
header('Location: thankyou.php');
вы также можете перенаправить на ту же страницу.
Если вы делаете что-то вроде комментариев и вы хотите, чтобы пользователь оставался на той же странице, вы можете использовать AJAX для обработки формы представления
довольно верный способ реализовать уникальный идентификатор в пост и кэшировать его в
<input type='hidden' name='post_id' value='".createPassword(64)."'>
тогда в вашем коде сделайте следующее:
if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
$_SESSION['post_id'] = $_POST['post_id'];
//do post stuff
} else {
//normal display
}
function createPassword($length)
{
$chars = "abcdefghijkmnopqrstuvwxyz023456789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= ($length - 1)) {
$num = rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
я нашел следующее решение. Вы можете избежать перенаправления после обработки POST
запрос манипулируя history
такой:
$cat process.php
<?php
process POST data here
...
header('Location: /the/result/page');
exit();
?>
после обработки POST
ed данные, которые вы делаете маленькими <script>
и результат /the/result/page
<?php
process POST data here
render the <script> // see below
render `/the/result/page` // OK
?>
на <script>
вы должны предоставить:
<script>
window.onload = function() {
history.replaceState("", "", "/the/result/page");
}
</script>
результат:
как вы можете видеть данные формы POST
ed to process.php
сценарий.
Этот скрипт процесс POST
ed данных и рендеринга /the/result/page
сразу с:
- нет перенаправления
- нет re
POST
данные при обновлении страницы (F5) - нет re
POST
при переходе к предыдущей / следующей странице через историю браузера
UPD
в качестве другого решения я прошу запрос the Mozilla Для Firefox команда, чтобы пользователи могли настроить NextPage
заголовок, который будет работать как и сделать post/redirect/get
шаблон устарел.
короче. Когда серверная форма процесса POST
данные успешно это:
- настройка
NextPage
заголовок вместоLocation
- рендеринг результата обработки
POST
данные формы, как это было бы дляGET
запросpost/redirect/get
шаблон
браузер, в свою очередь, когда вижу NextPage
заголовок:
- настройки
window.location
СNextPage
стоимостью - когда пользователь обновит страницу, браузер будет согласовывать
GET
запросNextPage
вместо rePOST
данные формы
я думаю, это было бы отлично, если реализовано, не так ли? =)
просто перенаправьте его на ту же страницу после использования данных формы, и он работает. Я пробовал.
header('location:yourpage.php');
уточненная версия сообщения Moob. Создайте хэш сообщения, сохраните его как файл cookie сеанса и сравните хэши каждого сеанса.
// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );
$post_hash = md5( json_encode( $_POST ) );
if( session_start() )
{
$post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
$_SESSION[ 'post_hash' ] = $post_hash;
session_write_close();
}
else
{
$post_resubmitted = false;
}
if ( $post_resubmitted ) {
// POST was resubmitted
}
else
{
// POST was submitted normally
}
после вставки в базу данных вызовите метод unset () для очистки данных.
и unset($_POST, где);
чтобы предотвратить вставку данных обновления, выполните перенаправление страницы на ту же страницу или другую страницу после вставки записи.
заголовок('Location:'.В $_SERVER['ТАКИ']);
в основном, вам нужно перенаправить с этой страницы, но это все еще может сделать проблему, пока ваш интернет медленный (перенаправление заголовка с сервера)
пример базового сценария :
нажмите на кнопку Отправить дважды
способ решить
-
стороне клиента
- отключить кнопку отправки, как только клиент нажмет на нее
- если вы используете Jquery:С помощью jQuery.один
- PRG Шаблон
-
сервер
- использование дифференцировать на основе хэширования отметка времени / отметка времени при отправке запроса.
- токены Userequest. Когда основная загрузка назначает временный запрос tocken, который, если повторяется, игнорируется.
Как предотвратить повторную отправку формы php без перенаправления. Если вы используете $_SESSION (после session_start) и форму $_POST, вы можете сделать что-то вроде этого:
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
// do your stuff, save data into database, etc
}
в вашей html-форме поставьте это:
<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>">
<?php
if ( $_POST['act'] == $_SESSION['act'] ){
if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){
$_SESSION['act'] = 1;
} else {
$_SESSION['act'] = 2;
}
}
?>
таким образом, каждый раз, когда форма представляется, генерируется новый акт, сохраняется в сеансе и сравнивается с post act.
Ps: Если вы используете форму Get, вы можете легко изменить все сообщения с GET, и это тоже работает.
Я использую эту строку javascript, чтобы заблокировать всплывающее окно с запросом повторной отправки формы при обновлении после отправки формы.
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
просто поместите эту строку в нижний колонтитул вашего файла и посмотрите magic
Использование шаблона Post/Redirect/Get из ответа Keverw-хорошая идея. Однако вы не можете оставаться на своей странице (и я думаю, что это было то, о чем вы просили?) Кроме того, это может иногда не:
если веб-пользователь обновляется до завершения первоначальной отправки из-за задержки сервера, что приводит к дублированию запроса HTTP POST в некоторые агенты пользователей.
другой вариант-Сохранить в сеансе, если текст должно быть записано в вашу базу данных SQL следующим образом:
if($_SERVER['REQUEST_METHOD'] != 'POST')
{
$_SESSION['writeSQL'] = true;
}
else
{
if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
{
$_SESSION['writeSQL'] = false;
/* save $_POST values into SQL */
}
}
Как говорили другие, невозможно выйти из использования post/redirect/get. Но в то же время довольно легко сделать то, что вы хотите сделать на стороне сервера.
на странице POST вы просто проверяете ввод пользователя, но не действуете на нем, вместо этого вы копируете его в массив сеанса. Затем вы снова перенаправляетесь на главную страницу отправки. Главная страница отправки начинается с проверки наличия используемого массива сеансов, и если да, то скопируйте его в локальный массив и снимите его. Оттуда вы можете действовать по нему.
таким образом, Вы делаете всю свою основную работу только один раз, добиваясь того, что хотите сделать.
Я искал решение, чтобы предотвратить повторную подачу в огромный проект после этого. Код высоко работает с $_GET и $_POST, и я не могу изменить поведение элементов формы без риска непредвиденных ошибок. Итак, вот мой код:
<!-- language: lang-php -->
<?php
// Very top of your code:
// Start session:
session_start();
// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
// Store Post Form Data in Session Variable
$_SESSION["POST"] = $_POST;
// Reload Page if there were no outputs
if ( ! headers_sent() ) {
// Build URL to reload with GET Parameters
// Change https to http if your site has no ssl
$location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// Reload Page
header( "location: " . $location, true, 303 );
// Stop any further progress
die();
}
}
// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
$_POST = $_SESSION["POST"];
// Tell PHP that POST is sent
$_SERVER['REQUEST_METHOD'] = 'POST';
}
// Your code:
?><html>
<head>
<title>GET/POST Resubmit</title>
</head>
<body>
<h1>Forms:</h1>
<h2>GET Form:</h2>
<form action="index.php" method="get">
<input type="text" id="text_get" value="test text get" name="text_get"/>
<input type="submit" value="submit">
</form>
<h2>POST Form:</h2>
<form action="index.php" method="post">
<input type="text" id="text_post" value="test text post" name="text_post"/>
<input type="submit" value="submit">
</form>
<h2>POST Form with GET action:</h2>
<form action="index.php?text_get2=getwithpost" method="post">
<input type="text" id="text_post2" value="test text get post" name="text_post2"/>
<input type="submit" value="submit">
</form>
<h2>File Upload Form:</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file">
<input type="submit" value="submit">
</form>
<h1>Results:</h1>
<h2>GET Form Result:</h2>
<p>text_get: <?php echo $_GET["text_get"]; ?></p>
<h2>POST Form Result:</h2>
<p>text_post: <?php echo $_POST["text_post"]; ?></p>
<h2>POST Form with GET Result:</h2>
<p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
<p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
<h2>File Upload:</h2>
<p>file:
<pre><?php if ( ! empty( $_FILES ) ) {
echo print_r( $_FILES, true );
} ?></pre>
</p>
<p></p>
</body>
</html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );
он работает только для того, чтобы избежать повторной отправки $_POST, а не $_GET. Но мне нужно именно такое поведение. Проблема повторной отправки не работает с загрузкой файлов!
почему бы просто не использовать $_POST['submit']
переменная как логическое утверждение, чтобы сохранить все, что находится в форме. Вы всегда можете перенаправить на одну и ту же страницу (в случае их обновления и при нажатии go back
в браузере переменная submit post больше не будет установлена. Просто убедитесь, что ваша кнопка отправки имеет name
и id
of submit
.