表单提交的唯一标记似乎不起作用

时间:2012-02-23 11:59:35

标签: php forms token

这就是我想要做的事情:

阻止用户使用唯一令牌提交表单两次。我想我在这里有正确的代码,但它仍然不起作用。第一次提交表单时输出为“不发送两次”。我究竟做错了什么?

<?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>

2 个答案:

答案 0 :(得分:1)

Thank you for submitting将永远不会显示,因为if( isset($_SESSION['token']) )的条件总是得到满足,因为您生成令牌并将会话变量直接设置在此if子句之上...这也是您将永远的原因提交第一次后看“不要发两次”。 加载表单时,您生成一个令牌,将其保存在会话中,将其放在表单中。 提交表单后,从顶部再次启动脚本: 您的令牌现在位于post变量中。但您重新创建会话令牌。然后你比较帖子和会话。当然它们不匹配,因为你刚刚生成了一个新令牌,所以它们当然不相等。

我建议您使用此结构代码:

<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>

答案 1 :(得分:1)

这里的概念存在缺陷。

  1. 浏览器不允许用户使用POST两次提交表单。他们向用户显示警告,说明两次提交表单的危险。

  2. 如果用户加载表单两次,则此脚本无法避免两次提交,因为两个表单上的令牌都不同。

  3. 我建议将提交保存在数据库中。这可以确保同一会话(或同一用户)只能保存一条记录。