Иногда пользователь может дважды нажать Enter
, и сообщение будет вставлено дважды.
Есть ли решение, чтобы предотвратить это, кроме как проверить, есть ли уже сообщение с теми же title
и content
?
Иногда пользователь может дважды нажать Enter
, и сообщение будет вставлено дважды.
Есть ли решение, чтобы предотвратить это, кроме как проверить, есть ли уже сообщение с теми же title
и content
?
Есть несколько решений этой проблемы:
Используйте 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>
Используйте сеансы 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();
}
Включите уникальный токен в каждый 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
}
}
}
Используйте уникальный токен с сообщением, чтобы каждое сообщение/постбэк обрабатывалось только один раз.
Отключение кнопки отправки — не очень хорошее решение, поскольку люди могут отключить javascript или делать другие странные вещи. Проверка на стороне клиента — хорошее начало, но она всегда должна сопровождаться обработкой на стороне сервера.
Создайте уникальный одноразовый ключ для отправки вместе с формой.
Полагаться на Javascript — плохая идея, потому что он может быть отключен пользователем в клиенте. С ключевой схемой, когда отправка получена сервером, отправка для этого ключа может быть заблокирована. Вы можете отвечать на повторяющиеся сообщения, как вам нравится.
Чтобы этот подход работал, ключи должны быть уникальными, и их очень трудно предсказать. В противном случае некоторые формы могут быть заблокированы из-за конфликтов клавиш. Таким образом, вам не нужно отслеживать ключи для каждой отправки формы и избегать конфликтов, срок действия ключей должен истекать вместе с сеансом этого пользователя. Еще одна вещь, на которую следует обратить внимание, это то, что если злоумышленники могут предсказать ключ, ваш код может быть уязвим для какого-либо взлома или эксплойта DOS.
Предотвратить повторную отправку формы показывает способ сделать это без JavaScript.
Отключите кнопку отправки с помощью Javascript после отправки формы (onsubmit
).
Обратите внимание, что если пользователь отключил Javascript, он все равно может отправить дважды. Происходит ли это достаточно часто, чтобы оправдать также проверку вашего кода (как вы предложили в своем вопросе), зависит от вас.
В качестве альтернативы используйте одноразовые ключи формы.
Я использую это:
$form_token = $_SESSION['form_token'] = md5(uniqid());
отправьте $form_token вместе с формой, затем...
Я проверяю form_token:
if($_SESSION['form_token'] != $_POST['form_token']) {
echo 'Error';
}
отключите кнопку отправки, как только пользователь отправит форму, используя JavaScript. Это то, что, например, использует StackOverflow, когда вы отвечаете на вопрос.
Например
<input type="submit" onclick="this.disabled=true" />
Двойное нажатие отправки довольно редко приводит к множественным вставкам, но если вам нужно очень простое решение, используйте
onsubmit="document.getElementById('submit').disabled = true"
в теге формы, если вы дадите кнопку отправки id="submit"
Используйте JavaScript, чтобы отключить кнопку, как только она будет нажата.
onclick="this.disabled=true;forms[0].submit();"
onclick
не запустится, если форма отправляется с помощью нажатия на клавиатуре, например. пользователь нажимает клавишу ввода, фокусируясь на кнопке отправки. Лучше используйте onsubmit
, как предложил один из других плакатов.
- person Asaph; 25.01.2010
Еще один способ создать страницу подтверждения, на которой пользователь, наконец, может нажать кнопку отправки. Это может уменьшить возможности такого рода.
Я делаю следующее на 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();
Мне помогло включение уникального токена в каждый POST Арона Роттевила. Однако моя форма по-прежнему отправляется, когда пользователь обновляет страницу (F5). Мне удалось решить это, добавив сброс:
// reset session token
$_SESSION['token'] = md5( $_POST['token'] . time() );
мои окончательные сценарии выглядят так:
if (isset($_SESSION['token'])) {
if (isset($_POST['token'])) {
if ($_POST['token'] != $_SESSION['token']) {
echo '<h3>Oops! You already submitted this request.</h3>';
} else {
// process form
// reset session token
$_SESSION['token'] = md5( $_POST['token'] . time() );
}
} else {
echo 'post token not set';
$_SESSION['token'] = md5( $somevariable . time() );
}
}
ой! не забудьте добавить session_start();
перед <!DOCTYPE>
Я новичок в PHP, поэтому, пожалуйста, поправьте меня, если вы обнаружите нарушения.
Используйте JavaScript, чтобы остановить его отправку