Как предотвратить повторную отправку формы при обновлении страницы (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
         }

  1. используйте заголовок и перенаправьте страницу.

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

  2. 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();
?>

enter image description here

после обработки POSTed данные, которые вы делаете маленькими <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

как вы можете видеть данные формы POSTed to process.php сценарий.
Этот скрипт процесс POSTed данных и рендеринга /the/result/page сразу с:

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

UPD

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

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

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

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

  1. настройки window.location С NextPage стоимостью
  2. когда пользователь обновит страницу, браузер будет согласовывать 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['ТАКИ']);


в основном, вам нужно перенаправить с этой страницы, но это все еще может сделать проблему, пока ваш интернет медленный (перенаправление заголовка с сервера)

пример базового сценария :

нажмите на кнопку Отправить дважды

способ решить

  • стороне клиента

  • сервер

    • использование дифференцировать на основе хэширования отметка времени / отметка времени при отправке запроса.
    • токены 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.