Как предотвратить множественные вставки при отправке формы в PHP? - PullRequest
29 голосов
/ 25 января 2010

Иногда пользователь может нажать Enter дважды, и сообщение вставляется дважды.

Есть ли решение для предотвращения этого, кроме проверки, если уже есть сообщение с такими же title и content?

Ответы [ 14 ]

49 голосов
/ 25 января 2010

Существует несколько решений этой проблемы:

  1. Используйте Javascript, чтобы отключить кнопку отправки формы, когда она публикуется. Недостатком является то, что это АБСОЛЮТНО не надежный способ. Очень просто отправлять формы без фактического нажатия кнопки, и это также не будет работать для пользователей с отключенным JavaScript. Я бы определенно не рекомендовал этот метод.

    Пример:

    <script language="javascript">
    <!--
        function disableSubmitButton() {
            // you may fill in the blanks :)
        }
    -->
    </script>
    <form action="foo.php" method="post">
        <input type="text" name="bar" />
        <input type="submit" value="Save" onclick="disableSubmitButton();">
    </form>
    
  2. Используйте PHP-сеансы , чтобы установить переменную сеанса (например, $ _SESSION ['posttimer']) в текущую метку времени после публикации. Перед фактической обработкой формы в PHP, проверьте, существует ли переменная $ _SESSION ['posttimer'], и определите разницу в метках времени (IE: 2 секунды). Таким образом, вы можете легко отфильтровать двойные отправки.

    Пример:

    // form.html
    <form action="foo.php" method="post">
        <input type="text" name="bar" />
        <input type="submit" value="Save">
    </form>
    
    // foo.php
    if (isset($_POST) && !empty($_POST)) 
    {
        if (isset($_SESSION['posttimer']))
        {
            if ( (time() - $_SESSION['posttimer']) <= 2)
            {
                // less then 2 seconds since last post
            }
            else
            {
                // more than 2 seconds since last post
            }
        }
        $_SESSION['posttimer'] = time();
    }
    
  3. Включите уникальный токен в каждый POST. В этом случае вы также должны установить переменную сеанса для токена, который хотите включить, и затем отобразить токен в форме. После отправки формы вы заново генерируете токен. Если представленный токен не совпадает с токеном в сеансе, форма повторно отправляется и должна быть объявлена ​​недействительной.

    Пример:

    // form.php
    <?php
        // obviously this can be anything you want, as long as it is unique
        $_SESSION['token'] = md5(session_id() . time());
    ?>
    <form action="foo.php" method="post">
        <input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" />
        <input type="text" name="bar" />
        <input type="submit" value="Save" />
    </form>
    
    // foo.php
    if (isset($_SESSION['token']))
    {
        if (isset($_POST['token']))
        {
            if ($_POST['token'] != $_SESSION['token'])
            {
                // double submit
            }
        }
    }
    
30 голосов
/ 25 января 2010

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

Отключение кнопки отправки не очень хорошее решение, так как люди могут отключить JavaScript или делать другие странные вещи. Проверка на стороне клиента - хорошее начало, но ее всегда следует подкреплять обработкой на стороне сервера.

5 голосов
/ 25 января 2010

Создание уникального одноразового ключа для отправки с формой.

Использование Javascript - плохая идея, поскольку он может быть отключен пользователем на клиенте. В схеме ключей, когда отправка получена сервером, отправка для этого ключа может быть заблокирована. Вы можете отвечать на дубликаты, если хотите.

Чтобы этот подход работал, ключи должны быть уникальными и их очень трудно предсказать. В противном случае некоторые формы могут быть заблокированы из-за столкновений клавиш. Таким образом, вам не нужно отслеживать ключи для каждой отправки формы и избегать коллизий, ключи должны истечь с сеансом этого пользователя. Еще одна вещь, на которую следует обратить внимание: если злоумышленники смогут предсказать ключ, ваш код может оказаться уязвимым для какого-либо взлома или использования DOS.

2 голосов
/ 25 января 2010

Предотвращение повторной отправки формы показывает способ сделать это без JavaScript.

1 голос
/ 26 января 2010

Я использую это:

$form_token = $_SESSION['form_token'] = md5(uniqid());

отправить $ form_token с формой, затем ...

Я проверяю form_token:

if($_SESSION['form_token'] != $_POST['form_token']) {
   echo 'Error';
}
1 голос
/ 25 января 2010

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

1 голос
/ 25 января 2010

Отключите кнопку отправки, используя Javascript, как только форма будет отправлена ​​(onsubmit).

Обратите внимание, что если пользователь отключил Javascript, он все равно может отправить дважды. Будет ли это происходить достаточно часто, чтобы оправдать проверку вашего кода (как вы предложили в своем вопросе), решать вам.

0 голосов
/ 30 июля 2018

Я делаю следующее на action.php

if($_SESSION && isset($_SESSION['already_submitted'])) {

  # If already submitted just redirect to thank you page

} else {

    # If first submit then assign session value and process the form
    $_SESSION['already_submitted'] = true;

    # Process form

}

Примечание. Всегда инициируйте сеансы в заголовке с помощью session_start ();

0 голосов
/ 20 июля 2017

Еще один способ создать страницу подтверждения, где пользователь может наконец нажать кнопку отправки Это может уменьшить возможности такого рода.

0 голосов
/ 27 января 2012

Используйте JavaScript, чтобы остановить отправку

...