Как предотвратить повторную отправку пользователем данных формы? - PullRequest
5 голосов
/ 26 октября 2011

Я получил POST форму, и она действительно отправляет данные в тот же файл, и если вы нажмете кнопку «Назад» в своем браузере, он может легко просто повторно отправить данные, и они все равно будут прочитаны..

Есть ли способ избежать такого поведения?

Ответы [ 6 ]

4 голосов
/ 24 февраля 2013

Существует два основных подхода.

POST-Redirect-GET

Первый - это шаблон post-redirect-get, в котором пользователь заполняет форму на signup.php, которая получает POST ed до submit.php, которая при успешном завершении возвращает REDIRECT на thanks.php. Браузер видит ответ перенаправления и выдает GET для thanks.php. Это работает, потому что без перенаправления нажатие на обновление приведет к перезагрузке submit.php, в результате чего предупреждение о повторной публикации данных и двойной запрос POST будут повторены. Перенаправление решает эту проблему.

signup.php
-----------
...
<input type="text" name="email">
...

submit.php
----------
...
if ($_POST) {
  // process data
  header('Location: thanks.php');
}
...

thanks.php
----------
...
Thanks
...

NONCE

Второй подход заключается во вставке ключа nonce в форму. Этот подход имеет дополнительное преимущество предотвращения атак CSRF. Подход здесь заключается в том, чтобы ввести скрытую направляющую в вашу форму:

<input type="nonce" value="<?= uniqid(); ?>">

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

3 голосов
/ 26 октября 2011

Ссылка, отправленная Леви, ответит за вас.Но если вам нужна альтернатива, вот как я это делаю ...

Публикации пользователей в классе, как у вас.тот же файл.В начале урока я делаю постобработку.Для этого примера я сделаю это очень просто ...

<?php
session_start();

//set form vars ahead of time so you can pre-populate the value attr on post
$form = array(
    'name' => '',
    'email' => ''
);

if(!empty($_POST))
{
    //do some kind of validation...
    $errors = array();
    if(trim($_POST['name']) == '')
        $errors[] = 'Please enter your name';

    if(empty($errors))
    {
        $_SESSION['message'] = 'Thank you for participating';
        header('location: /form.php'); // same file
        exit;
    }
    else
    {
        // set the form vars to the post vars so you don't lose the user's input
        $form['name'] = $_POST['name'];
        $form['email'] = $_POST['email'];

        $message = '<span style="color:red">';
        foreach($errors AS $error)
        {
            $message .= $error."<br />";
        }
        $message .= '</span>';
        $_SESSION['message'] = $message;
    }
}

if(isset($_SESSION['message']))
{
    echo $_SESSION['message'];
    unset($_SESSION['message']);
}
?>
<form id="some_form" action="" method="post">
    <fieldset>
        <label for="name">Name</label> <input type="text" name="name" value="<?php echo $form['name']; ?>" />
        <br /><br />
        <label for="email">Email</label> <input type="text" name="email" value="<?php echo $form['email']; ?>" />
        <br /><br />
        <input type="submit" name="submit" value="Submit" />
    </fieldset>
</form>

Теперь вы можете обновлять снова и снова и не отправлять форму дважды.

Отредактировано, чтобы показать дальнейший пример. Очевидно, что ваша проверка и обработка ошибок должны быть немного более сложными, чем это, но это должно привести вас в правильном направлении.

2 голосов
/ 26 октября 2011

Вы не можете на 100% предотвратить это, если пользователь хочет сделать это, однако, чтобы избежать этого случайно, изучите Post / Redirect / Get .

1 голос
/ 14 января 2013

Это работает для меня.Я использую Smarty, но это можно сделать и без Smarty.Это всего лишь идея.Измените его, как вы хотите.

HTML-форма:

<form action="submit_file.php" method="POST">
<input type="hidden" name="submit_edit" value="1">
<input type="text" name="data"/>
</form>

PHP в globals.php

if (count($_POST) > 0) {
    if (isset($_POST['submit_edit']) && $_POST['submit_edit'] == '1'
            && time() - $_SESSION['last_request_time'] < 100
            && count($_SESSION['last_request']) > 0
            && serialize($_SESSION['last_request']) == serialize($_POST)) {

        $oSmarty->assign('display_time_alert', '1');
        unset($_POST['submit_edit']);
        unset($_REQUEST['submit_edit']);
    } else {
        $_SESSION['last_request_time'] = time();
        $_SESSION['last_request'] = $_POST;
    }
}

И это в head.tpl

{literal}
    <script>
function showTimeAlert(){
        alert('{/literal}{tr var="Cannot send the same request twice"}{literal}');
    }
    {/literal}
    {if isset($display_time_alert) AND $display_time_alert eq '1'}
    showTimeAlert();
    {/if}
    {literal}



    </script>
{/literal}

Окончательноsubmit_file.php

require_once("globals.php");

if(isset($_POST['submit_edit']) && $_POST['submit_edit'] == '1')){
//record data
}

$oSmarty->dysplay(some.tpl);//in some.tpl is included head.tpl
1 голос
/ 26 октября 2011

При отправке формы введите случайное число в значение $_SESSION['stopdupe'] и в скрытое поле.

При получении формы на обработку:

  1. Убедитесь, что $_SESSION['stopdupe'] существует и соответствует значению скрытого поля. (Если нет, игнорируйте пост)
  2. Unset $_SESSION['stopdupe']
  3. Обработайте форму как обычно.

Таким образом, если пользователь нажимает кнопку отправки дважды, второй запрос не будет обработан.

Еще один полезный прием - использование в форме события javascript onSubmit для отключения кнопки, чтобы пользователь не мог легко отправить ее несколько раз.

0 голосов
/ 19 января 2013

На первой странице используйте одну переменную сеанса и присвойте значение 1. Пример:

<form name="frm1" method="post">
    <?php $_SESSION['resend_chk']=1; ?>
    <input type="text" name="a" />
    <input type="submit" name="submit">
</form>

На второй странице:

if(isset($_REQUEST['submit'])
{
    if($_SESSION['resend_chk']==1)
    {
        insert to db OR and any transaction
        $_SESSION['resend_chk']=0;
    }
}

Он будет вставлен один раз или произойдет транзакцияОдин раз в дБ, и значение переменной сеанса изменится, в следующий раз, когда мы попытаемся отправить данные повторно, транзакция не будет выполнена, поскольку значение переменной сеанса уже изменено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...