PHP-приложение гарантирует отсутствие повторной публикации - PullRequest
1 голос
/ 10 января 2010

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

Теперь у меня есть небольшая пользовательская CMS, и я хочу гарантировать, что пользователи не будут повторно отправлять свои данные $ _POST, обновляя страницу. Итак, я сделал что-то вроде этого:

<?
  //Start a session to hold variables I want after my redirect
  session_start();
  if($_POST){ 

    //Do some php stuff and if I'm happy with the results...
    $_SESSION['some_vars'] = $whatever;

    //Bring me back here but without the $_POST data
    header('Location: '.THIS_PAGE);
    exit;

  }
?>

Когда скрипт перезагружается, я использую переменные сеанса и удаляю сеанс.

Мне интересно, есть ли у кого-нибудь лучший способ справиться с этим. Это довольно не громоздко, но я всегда ищу больше эффективности.

Спасибо.

РЕДАКТИРОВАТЬ : Кстати, stackoverflow.com делает это как-то, когда вы отправляете вопрос, если то, что я делаю, кажется неясным, но они также делают постоянную ссылку, пока они там.

Ответы [ 4 ]

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

Вы фактически реализовали так называемый шаблон Post-Redirect-Get , и это абсолютно правильный способ сделать это. Я делаю это сам. Я использую его так часто, что обычно внедряю некоторые вспомогательные вспомогательные функции в классы базового контроллера, чтобы помочь мне использовать его:

public function prgRedirect($url = null, $sessionData = null)
{
    if ($sessionData !== null) {
        if (! isset($_SESSION)) session_start();
        $_SESSION['_PRG'] = $sessionData;
    }
    if ($url === null) $url = $_SERVER['HTTP_REFERER'];
    header("Location: ".$url);
}

public function getPrgData()
{
    if (! isset($_SESSION)) session_start();
    if (isset($_SESSION['_PRG'])) {
        $data = $_SESSION['_PRG'];
        unset($_SESSION['_PRG']);
    }
    else {
        $data = null;
    }
    return $data;
}

Я обычно использую его с URL-адресами в стиле REST, поэтому запрос POST будет делать все, что от него требуется, сохраняя некоторые данные в сеансе, используя prgRedirect(), который затем перенаправляет обратно на URL GET для того же ресурса / страницы. Обработчик метода GET вызовет getPrgData() в начале выполнения и увидит, есть ли что-нибудь в данных сеанса.

0 голосов
/ 10 января 2010

Здесь на самом деле две проблемы:

  • пользователи нажимают кнопку обновления в своем браузере, когда данные уже сохранены, и вы находитесь на странице, которая сохраняет данные
  • пользователь нажимает кнопку «назад» в браузере и снова нажимает кнопку «отправить».

В первом сценарии лучшая схема состоит в том, чтобы следовать шаблону GET-after-POST, где вы используете вызов header("location:somewhere_else.php") для перенаправления пользователя. Таким образом, вам не нужно беспокоиться о двухкратном вызове подряд, поскольку страница, на которой вы разместили данные, отсутствует в списке истории браузера (поскольку сервер вернул заголовок 302).

Второй сценарий причиняет больший вред, потому что GET-after-POST не помогает. Если пользователь отправляет форму дважды, вы можете сохранить данные дважды. В этом случае может быть несколько решений:

  • вставьте «идентификатор формы» (случайную строку) в каждую форму, которую вы отправляете клиенту. Когда клиент отправляет форму, проверьте, есть ли у вас такой идентификатор в данных сеанса. Если у вас его нет, сохраните данные формы и запомните идентификатор в сеансе пользователя как «уже использованный». Если вы найдете идентификатор в данных сеанса, ничего не сохраняйте - это дубликат.
  • проверить базу данных на наличие точно таких же значений, что и отправленные. Если они совпадают, не сохраняйте дубликаты. Однако пользователь, возможно, нажал кнопку «назад», изменил часть данных и затем повторно отправил форму.
0 голосов
/ 10 января 2010

А как насчет:
1. Сгенерируйте случайную строку (uniqid или md5)
2. Сохраните его в сеансе и вставьте в скрытый ввод в форме
3. Проверьте значение формы и значение сеанса - если оно совпадает - обработайте форму. Очистить значение сеанса.

0 голосов
/ 10 января 2010

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

...