Предотвращение дублирования представления формы - PullRequest
12 голосов
/ 06 января 2011

Я придумала технику, чтобы предотвратить повторную отправку формы, переходя назад / вперед или обновляя страницу.И я подумал о том, чтобы обсудить это здесь, я уже тестировал образец, не находящийся в производственной среде, какие недостатки вы можете определить?

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

-Создайте идентификатор формы для каждой формы и используйте его как скрытое поле в форме:

$formid = microtime(true)*10000;

- При отправке формы :

  • Проверка по данным

  • Вычисление хеша данных полей формы

    $allvals = '';
    foreach($_POST as $k=>$v){
        $allvals .= $v;
    }
    $formHash = sha1($allvals);
    
  • Проверка хеша формы путем сравнения с ранеесохраненные хешизначение сеанса связывается с каждой формой переменной $ formid.

    $allowAction = true;
    if(isset($_SESSION['formHash'][$_POST['formid']]) && ($_SESSION['formHash'][$_POST['formid']] == $formHash)){
         $allowAction = false;
    }
    
  • , если хэш формы не был найден, это означает, что форма отправляется впервые или данные формы изменяются.
  • Если данные сохранены (например, в базе данных), сохраните хэш формы в сеансе:

    $_SESSION['formHash'][$_POST['formid']] = $formHash;
    

Полная версия кода: http://thebusy.me/2011/01/06/preventing-duplicate-form-submissions/

Ответы [ 3 ]

7 голосов
/ 07 января 2011

Более простой способ достичь желаемого - использовать перенаправление при отправке. После обработки запроса POST вы перенаправляете, возможно, даже на ту же страницу. Это общий шаблон, называемый «Redirect after POST» или POST / Redirect / GET .

Например:

<?php
if($_POST) {
    // do something

    // now redirect
    header("Location: " . $_SERVER["REQUEST_URI"]);
    exit;
}
?>

<html> ...
<form method="post" action=""> ... </form>

Установив действие "", оно будет отправлено самому себе, после чего блок кода if ($ _ POST) подтвердит значение true и обработает форму, а затем перенаправит ее обратно на себя.

Конечно, вы, вероятно, хотите перенаправить на другую страницу, на которой показан ответ «Ваша форма отправлена», или поместить форму на другую страницу, и ответом будет HTML-код этой страницы.

Преимущество этого метода в том, что когда вы нажимаете кнопку "Назад", он выполняет запрос GET, поэтому форма не отправляется повторно.

В Firefox он на самом деле извлекает представление из истории браузера, поэтому, когда пользователи просматривают веб-сайт и затем наносят ответный удар, вместо просмотра страницы «спасибо» они видят страницу формы.

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

Похоже, вы слишком усложняетесь с этим. Мой любимый способ, потому что он также предотвращает некоторые хаки сессионного взлома, описан здесь:

http://www.spotlesswebdesign.com/blog.php?id=11

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

0 голосов
/ 06 февраля 2013

Оба решения хороши, но немного коротки.

как насчет остановки последующих вставок в течение следующих нескольких минут от того же пользователя с возможно незначительными изменениями в данных?

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

возможно, кто-то может прокомментировать обоснованность и эффективность моего предложения, или я лаю не на том дереве ???

...