有时用户可能按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" />
使用 JavaScript 在单击按钮后立即禁用该按钮。
onclick="this.disabled=true;forms[0].submit();"
按两次提交很少会导致多次插入,但是如果您想要一个非常简单的解决方案,请使用
onsubmit="document.getElementById('submit').disabled = true"
在表单标签中,只要您提供提交按钮id="submit"
另一种创建确认页面的方法,用户最终可以在其中按下提交按钮。它可能会减少这种可能性。
我正在对 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(); 在标头中启动会话;
Aron Rotteveel 的在每个 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 阻止它发送
$(document).ready(function() {
$('#postHideBtn').show();
$('#postHideBtn').click(function() {
$('#postHideBtn').hide();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="foo.php" method="post">
<input type="text" name="bar" />
<input type="submit" value="Save" id="postHideBtn" />
</form>