【问题标题】:Using hash to check if page with $_POST values was refreshed使用哈希检查具有 $_POST 值的页面是否已刷新
【发布时间】:2010-04-16 01:55:08
【问题描述】:

将表单发布到同一个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...

这个解决方案有什么问题吗?

更新:这个场景的一个例子是在注册表中插入一行。您只希望此操作执行一次。

【问题讨论】:

  • 如果您不介意我问,您想通过检测 $_POST 与刷新来解决什么问题?
  • 请参阅下面对 Mrozek 回答的评论。检查重复的 $_POST 值告诉我页面被意外重新提交。

标签: php forms post hash form-submit


【解决方案1】:

让我们从您无法区分 意外 刷新和 有目的 刷新这一点开始。所以你只能决定根本不允许刷新,或者换句话说,要求每个表单提交必须是唯一的。最好的方法是在表单中插入一个随机标记。

<?php
    $token = /* a randomly generated string */;
    $_SESSION['_token'] = $token;
?>
<input type="hidden" name="_token" value="<?php echo $token; ?>" />

每次提交后,您都会使会话令牌无效。如果会话中的令牌与随表单提交的令牌不同,您可以丢弃 POST。

重新评论:您可以按项目执行此操作。例如,在 SO 上,您可能会打开多个问题窗口并同时回答多个问题。您可以针对每个问题制作令牌,因此用户可以在任何时候拥有多个有效令牌,但每个问题只有一个。

这个场景的一个例子是在注册表中插入一行。您只希望此操作执行一次。

在这种情况下,您可能不应该太关心实际的 POST,而应该关心数据的一致性。您应该为每个用户提供某种形式的唯一标识,例如他的电子邮件地址。如果该地址已在数据库中注册,则无需再次注册用户。这与用户尝试注册两次的原因无关(重复提交或实际尝试再次注册)。

【讨论】:

  • 此方法需要注意的一个问题是,当涉及多个窗口/选项卡时它会中断 - 第二个选项卡会覆盖第一个选项卡的会话值,然后如果提交第一个选项卡,则令牌不再匹配。
  • @Brenton 非常正确,但我想说任何按任何标准丢弃 POST 的方法都会有这个问题。
【解决方案2】:

我通常更喜欢让 POST 处理程序做它需要做的任何事情,然后将用户重定向到一个新页面

header("Location: new-page.php");

这样他们就可以刷新而不会弄乱任何东西

【讨论】:

  • 是的,这将是显而易见的解决方案,而且我以这种方式进行基本的 CRUD 操作没有问题。我想知道是否有一种可接受的解决方案来检查页面刷新是否意外提交了表单。
  • 但是如果用户点击返回表单页面并再次点击提交,你最终不会得到两个相同的帖子吗?
  • @ggfan: 是的,但这听起来像是故意的行为。
【解决方案3】:

将标记与POST/REDIRECT/GET 设计模式结合使用似乎是最好的解决方案。

  • 设置一次性令牌会阻止用户点击后退按钮并尝试再次提交表单。
  • 重定向用户并使用视图显示输入允许他们随意点击刷新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 2013-07-06
    • 2023-03-11
    • 2011-05-09
    • 1970-01-01
    • 2016-04-09
    相关资源
    最近更新 更多