这就是我想要做的:
防止用户使用唯一令牌两次提交表单。我想我这里有正确的代码,但它仍然不起作用。第一次提交表单时,输出为"不要发送两次"。我做错了什么?
<?php session_start(); ?>
<html>
<body>
<?php
$_SESSION['token'] = md5(session_id() . time());
?>
<?php
if (isset($_SESSION['token']))
{
if (isset($_POST['token']))
{
if ($_POST['token'] != $_SESSION['token'])
{
echo "Don't send twice!";
}
}
}
else {
echo "Thank you for submitting";
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" />
<input type="text" name="bar" />
<input type="submit" value="Save" />
</form>
这里的概念有缺陷。
-
浏览器不允许用户使用POST两次提交表单。他们向用户显示一个警告,告知提交两次表格的危险。
-
如果用户两次加载表单,则此脚本无法避免两次提交,因为两个表单上的令牌不同。
我建议将提交的内容保存在数据库中。这样可以确保同一会话(或同一用户)只能保存一条记录。
Thank you for submitting
永远不会显示,因为if( isset($_SESSION['token']) )
的条件总是满足的,因为您生成了令牌并将会话变量设置在if子句的正上方。。。这也是为什么你在第一次提交后总是会看到"不要发送两次"。加载表单时,您生成一个令牌,将其保存在会话中,并将其放入表单中。提交表单后,您将从顶部重新启动脚本:您的代币现在位于后变量中。但是您重新创建了会话令牌。然后比较post和session。它们当然不匹配,因为您刚刚生成了一个NEW令牌,所以它们当然不相等。
我为您的代码推荐这种结构:
<html>
<body>
<?php
session_start();
//HAS THE FORM BEEN SUBMITTED?
if(isset($_POST))
{
//THE FORM HAS BEEN SUBMITTED
//VALIDATE THE TOKEN
if($_POST['token'] == $_SESSION['token'])
{
//THE TOKEN WAS VALID, CONTINUE WITH PROCEDURES
}
else
{
echo 'Invalid token, please try again!';
}
}
else
{
//FORM NOT SUBMITTED YET
$token = $_SESSION['token'] = md5( session_id() . time(). rand() );
//i recommend adding rand() otherwise there is always a 1 second window in which the token could be doubled up...
echo '<form action="'. $_SERVER['PHP_SELF'] .'" method="post">';
echo '<input type="hidden" name="token" value="'. $token .'" />';
echo '<input type="text" name="bar" />';
echo '<input type="submit" value="Save" />';
echo '</form>';
}
?>
</body>
</html>