防止手动页面刷新时重复记录插入

时间:2010-09-16 13:10:42

标签: php refresh

我遇到的问题只是浮出水面。

我在MVC环境中工作。我的接口类中的方法名称与请求模块和操作的方法名称匹配,即?module=test&action=action将导致名为public function test_action() { }的方法

在这个特殊的问题中,我有一个提交给自己的表格。如果验证通过,则会创建一条记录,然后我会显示另一个模块的模板。该模块需要一系列post变量,因为它在两个模块中使用。

我遇到的问题是,如果用户成功通过验证并尝试F5页面,则会创建另一条新记录等。

如何防止这种情况发生?

通常我会在成功插入后进行头重定向,但在这种情况下我不能。

7 个答案:

答案 0 :(得分:5)

我会采取完全相反的方式。我甚至发现重定向是一种不正确的处理方式,因为更改位置并不意味着克服逻辑/形式问题。

正确的解决方案是:

  • 在隐藏输入中为表单添加唯一哈希
  • 将哈希存储在服务器端会话中
  • 发送表单时,使用服务器上的哈希验证隐藏的输入哈希值
  • 仅在表单正确验证时执行行插入。

如果您正在使用Zend Framework,那么有一个Zend_Form_Element_Hash课程。

答案 1 :(得分:2)

成功插入后,您可以/应该重定向到新页面。

当你在MVC工作时,你可以添加一个只调用你想要显示的视图的新控制器。

答案 2 :(得分:2)

开发人员错误:

您需要创建一个处理程序页面:

  • 验证发送的数据
  • 插入行
  • 重定向用户

答案 3 :(得分:1)

这就是我做的。这对我有用。希望它可以帮助其他任何人。

//+++ start token +++
//This is to prevent duplicate entry on page reload (F5). 19.   If I enter all values, press Record in journal and then press F5, the same values are recorded one more time. Need to prevent

// 3rd. $token_hash_from_input get value of input field name name="' .$_SESSION['token_hash'] .'"
$token_hash_from_input = $_SESSION['token_hash'];
//echo $token_hash_from_input .' token_hash_from_input<br>';
//echo $_POST[$token_hash_from_input] .' $_POST[$token_hash_from_input]<br>';
//var_dump($token_hash, $_POST);

// 4th. $_SESSION['token'] created/set in 1st. Then it as if goes around (at first to input field then after page reload returns here). However $_POST[$token_hash_from_input] is value received directly from input field. User click post and input field value is passed to $_POST[$token_hash_from_input]. Here I compare both.
if ( $_SESSION['token'] != htmlspecialchars($_POST[$token_hash_from_input]) ) {
$token_error .= 'yes';
//echo 'session token and token from input field are not the same <br> ';
}
else {
//echo 'session token is equal to post$token_hash)<br>';
}

// 1st. Create token and pass it to session
$token = sha1(uniqid(mt_rand(), true));
$_SESSION['token'] = $token;
//echo $_SESSION['token'] .' new $_SESSION[token]<br>';//after each page reload new token created. Then this token passed to input form (hidden field). value="' .$_SESSION['token'] .'"

// 2nd. Create token_hash and pass it to session. Token hash is to name input fields name and id. I may not use $token_hash and $_SESSION['token_hash']. Instead of this I can use name="token" and id="token".
$token_hash = sha1(uniqid($time_when_form_submitted .'token' .$_SERVER["REMOTE_ADDR"]));
//echo $token_hash .' $token_hash<br>';
$_SESSION['token_hash'] = $token_hash;
//echo $_SESSION['token_hash'] .' new SESSION$token_hash<br>';
// +++ end token +++

像这样输入字段

<input type="hidden" name="' .$_SESSION['token_hash'] .'" id="' .$_SESSION['token_hash'] .'" value="' .$_SESSION['token'] .'">

<input type="hidden" name="<?php echo $_SESSION['token_hash'] ?>" id="<?php echo $_SESSION['token_hash'] ?>" value="<?php echo $_SESSION['token'] ?>">

我想代码可以改进(我没有很好的知识php等)

答案 4 :(得分:0)

“通常情况下,我会在成功插入后进行重定向,但在这种情况下我不能。”

你在这方面遇到了一些错误吗?

答案 5 :(得分:0)

如果由于某种原因你不能重定向(听起来很奇怪)你可以使用'相同' 用于数据验证的机制,用于在成功插入后刷新表单。

但那是一种非常难看的方式。

答案 6 :(得分:0)

许多Web开发人员在其Web应用程序中面临的最常见问题之一是重复记录在页面刷新时插入到数据库中。如果网页包含一些文本框和一个用于将文本框数据提交到数据库的按钮。在这种情况下,当用户将一些数据插入文本框并单击提交按钮时,它会将记录保存到数据库中,然后如果用户立即刷新网页,则会再次将相同的记录保存到数据库中没有可用于验证数据存在的唯一键,以防止多次插入。

从这种行为我们可以肯定地知道,在页面上新鲜按钮点击事件被触发。 为了避免这个问题,我们可以尝试这种方法,如下所述。

在页面加载事件中将日期/时间戳保存在会话变量中,首次加载页面时,会使用当前日期/时间填充会话变量,如下所示:

* void Page_Load(Object sender,EventArgs e) {             如果(!的IsPostBack)             {                 Session [&#34; update&#34;] = Server.UrlEncode(System.DateTime.Now.ToString());             } } *

在页面的PreRender事件中,ViewState变量设置为Session变量的值,如下所示:

void Page_PreRender(object obj,EventArgs e)
{
    ViewState["update"] = Session["update"];
}

然后在运行数据库INSERT命令之前立即将这两个值进行比较。 如果它们相等,则允许执行命令,并使用当前日期/时间更新Session变量,否则绕过命令,如下所示:

void btnSubmit_Click(object obj, EventArgs e)
{
    string name = "";
    string qualification = "";


    if (Session["update"].ToString() == ViewState["update"].ToString())
    {
        if (txtName.Text != "" || txtName.Text != null)
        {
            name = txtName.Text.ToString();
        }

        if (txtQualification.Text != "" || txtQualification.Text != null)
        {
            qualification = txtQualification.Text.ToString();
        }

       //--- Insert data function should be execute here

       string strSql = "INSERT INTO Testdata (Name,Qualification) VALUES ('" + name + "','" + qualification + "')";

        SqlConnection ANConnection = new SqlConnection(ConnectionString);

        ANConnection.Open();
        SqlCommand ANCommand = new SqlCommand(strSql, ANConnection);
        ANCommand.ExecuteNonQuery();

        ANConnection.Close();
        ANConnection.Dispose();

        //--End of save data 

       lblMessage.Text = "Inserted Record Sucessfully 
       Session["update"] = Server.UrlEncode(System.DateTime.Now.ToString());
    }
    else
    {
        lblMessage.Text = "Failure – Due to Page Refresh";
        txtName.Text = "";
        txtQualification.Text = "";
    }
}