将表单发布到同一个PHP页面时,如果页面被意外刷新而不是再次提交,找到正确的方法是什么?
这就是我现在正在使用的内容:
$tmp = implode('',$_POST);
$myHash = md5($tmp);
if(isset($_SESSION["myHash"]) && $_SESSION["myHash"] == $myHash)
{
header("Location: index.php"); // page refreshed, send user somewhere else
die();
}
else
{
$_SESSION["myHash"] = $myHash;
}
// continue processing...
这个解决方案有什么问题吗?
UPDATE:此方案的一个示例是在注册表中插入一行。您只希望此操作执行一次。
答案 0 :(得分:2)
让我们从无法区分意外刷新有目的刷新开始。因此,您只能决定不允许刷新,换句话说,要求每个表单提交必须是唯一的。最好的方法是在表单中插入一个随机标记。
<?php
$token = /* a randomly generated string */;
$_SESSION['_token'] = $token;
?>
<input type="hidden" name="_token" value="<?php echo $token; ?>" />
每次提交后,您都会使会话令牌失效。如果会话中的令牌与使用表单提交的令牌不同,则可以放弃POST。
评论:您可以按项目执行此操作。例如,在SO上,您可能会打开几个问题窗口并立即回答几个问题。您可以基于每个问题制作令牌,因此用户可以同时拥有多个有效令牌,但每个问题只能有一个。
此方案的一个示例是在注册表中插入一行。您只希望此操作执行一次。
在这种情况下,您可能不应该过于关注实际的POST,而是关注数据的一致性。您应该为每个用户提供某种形式的唯一标识,例如他的电子邮件地址。如果地址已在数据库中注册,则不会再次注册该用户。这与用户尝试注册两次(双重提交或实际再次注册)的原因无关。
答案 1 :(得分:1)
我通常更喜欢让POST处理程序执行任何需要执行的操作,然后将用户重定向到新页面
header("Location: new-page.php");
所以他们可以刷新而不会弄乱任何东西
答案 2 :(得分:1)
将令牌与POST/REDIRECT/GET设计模式结合使用似乎是最佳解决方案。