Как предотвратить повторную отправку формы при обновлении страницы (F5 / CTRL + R) - PullRequest
105 голосов
/ 12 июня 2011

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

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

Ответы [ 19 ]

79 голосов
/ 12 июня 2011

Используйте шаблон Post / Redirect / Get.http://en.wikipedia.org/wiki/Post/Redirect/Get

На моем веб-сайте я буду сохранять сообщение в файле cookie или сеансе, перенаправлять после сообщения, читать файл cookie / сеанса и затем очищать значение этого сеанса или переменной cookie.

58 голосов
/ 13 августа 2017

Я также хотел бы отметить, что вы можете использовать подход 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.

16 голосов
/ 02 мая 2013

Вы действительно должны использовать шаблон Post Redirect Get для обработки этого, но если вы каким-то образом оказались в положении, когда PRG нежизнеспособен (например, сама форма включена, предотвращая перенаправления), вы можете хешироватьпараметры запроса, чтобы создать строку на основе содержимого, а затем проверить, что вы ее еще не отправили.

//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!
    }
13 голосов
/ 04 августа 2016

вы можете предотвратить повторную отправку формы через переменную сеанса.

сначала вы должны установить rand () в текстовом поле и $ _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'] со значением текстового поля $ _POST ['randcheck'] Как

         if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
          {
         //Your Code here
         }
12 голосов
/ 12 июня 2011

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

... process complete....
header('Location: thankyou.php');

Вы также можете перенаправить на ту же страницу.

если вы делаете что-то вроде комментариев и хотите, чтобы пользователь оставался на той же странице, вы можете использовать Ajax для обработки отправки формы

11 голосов
/ 08 марта 2013
  1. Используйте заголовок и перенаправьте страницу.

    header("Location:your_page.php"); Вы можете перенаправить на ту же страницу или на другую страницу.

  2. Unset $ _POSTпосле вставки в базу данных.

    unset($_POST);

10 голосов
/ 23 сентября 2018

Я использую эту строку javascript, чтобы заблокировать всплывающее окно, запрашивающее повторную отправку формы при обновлении после отправки формы.

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}

Просто поместите эту строку в нижний колонтитул вашего файла и увидите магию

7 голосов
/ 12 ноября 2017

Я нашел следующий обходной путь.Вы можете избежать перенаправления после обработки запроса POST, манипулируя объектом history.

Итак, у вас есть HTML-форма:

<form method=POST action='/process.php'>
 <input type=submit value=OK>
</form>

Когда вы обрабатываете эту форму на своем сервере, вы вместо перенаправления пользователя на /the/result/page устанавливаете заголовок Location следующим образом:

$cat process.php
<?php 
     process POST data here
     ... 
     header('Location: /the/result/page');
     exit();
?>

enter image description here

После обработки POST отредактированных данных вы визуализируете небольшой <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>

Результат:

enter image description here

, как вы видите формуданные POST редактируются в process.php сценарий.
Этот сценарий обрабатывает POST редактирует данные и обрабатывает /the/result/page сразу с:

  1. без перенаправления
  2. нет данных POST при обновлении страницы (F5)
  3. нет данных POST при переходе на предыдущую / следующую страницу по истории браузера

UPD

В качестве другого решения я прошу запрос функции команду Mozilla FireFox , чтобы пользователи могли настроить NextPage заголовок, который будет работать как Location заголовок и сделать post/redirect/get паттрн устарел.

Короче.Когда процесс сервера формы POST данные успешно это:

  1. Настройка NextPage заголовок вместо Location
  2. Отображать результат обработки POST данных формы, как это было бы сделатьдля GET запроса в post/redirect/get шаблоне

Браузер в свою очередь, когда видит заголовок NextPage:

  1. Настройка window.location со значением NextPage
  2. Когда пользователь обновляет страницу, браузер будет согласовывать GET запрос на NextPage вместо POST данных формы

Я думаю, что это было бы превосходно, если бы реализовано, не будет?=)

7 голосов
/ 21 августа 2014

Довольно верным способом является внедрение уникального идентификатора в сообщение и кеширование его в

<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;
}
3 голосов
/ 05 февраля 2016

Изысканная версия поста Муба.Создайте хеш POST, сохраните его как файл 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
}
...