CodeIgniter中重复数据插入的问题

4

我只是在 codeigniter 的控制器部分插入数据,代码在 pastebin 上:http://pastebin.com/KBtqrAkZ

  public function add_product()
  {
    $this->lang->load('log_in', 'english');
        log_in_check($this->lang->line('log_in_authentication_error'), 'admin/log_in');
        $this->lang->load('common', 'english');
        $data['title'] = $this->lang->line('admin_index_title');
        $this->load->view('admin_template/header', $data);
        $this->load->view('admin_template/left_menu');
    $data['error_msg'] = '';
        if ($this->form_validation->run('add_product') === TRUE)
        {
      $this->admin_model->add_product($this->input->post());
            $this->session->set_flashdata('status_msg', $this->lang->line('add_product_success'));
            redirect(uri_string(), 'refresh');
      exit ;
          $data['error_msg'] = $this->lang->line('add_product_invalid_data');
        }
        $this->load->view('admin/add_product');
        //$this->load->view('admin_template/notification');
        $this->load->view('admin_template/footer');  
  }

然后我的模型部分很简单,可以在pastebin上添加 http://pastebin.com/WiLHV2sr

  public function add_product($data = array())
  {
    $this->db->insert('ishop_product', $data);
    return $this->db->insert_id();
  }

我的问题是,在重定向后,如果我按下ctrl + F5或F5,那么数据会被插入。我是CodeIgniter中的新手,请帮帮我。非常感谢您的任何帮助。

你应该阅读这个问题:https://dev59.com/m2445IYBdhLWcg3wydFk - Gustav Bertram
这个也有一个很好的答案:http://stackoverflow.com/questions/3313582/token-method-on-forms-double-submit-issue - Gustav Bertram
2个回答

19

这是“双重提交问题”。

解决此问题的方法有几种:

  1. Post/Redirect/Get模式:可以避免提交多次,但会破坏浏览器的返回按钮,无法防止用户返回并重新提交。不能处理多个点击。

  2. 禁用提交按钮:部分时间可以处理多个点击,但不能解决用户返回并重新提交的问题。

  3. 在会话中存储令牌:如果在浏览器中打开多个标签页,则可能会混淆存储在会话中的令牌。(注意:使用JavaScript可能会创建特定于浏览器标签页的cookie,但我自己没有尝试过。)

  4. 更改数据库以不允许重复:最好的解决方案,但需要投入最大的精力。如果检测到一组重复数据,请忽略第二个请求。

  5. 唯一的事务ID:在PHP hacks页面答案中描述过。

  6. 在会话中存储多个令牌:选项3的变体。如果在会话中存储所有生成的令牌,则无需涉及数据库。由于令牌在会话内是唯一的,重复的概率要小得多。可能存在的问题包括令牌集不断增长。可以通过限制大小的堆栈来解决问题,将新令牌添加到堆栈顶部,并使额外的令牌从底部掉落。未经测试。

我喜欢这种独特的交易ID方法,它的工作原理如下:

  1. 生成一个随机的transaction_id并将其放入您的Web表单中,在用户点击提交时一起发送。

  2. 当您收到添加产品的请求时,在交易表中检查transaction_id

  3. 如果该ID在表中不存在,则进行交易并将transaction_id插入表中。

  4. 如果该ID在表中存在,则该交易已经完成。

您还应该搜索[double-submit-prevention]以查看是否可以找到更好的解决方案。


2
这可能实际上是最好的与 double-submit-prevention 标签相关的 PHP 答案,因为它非常广泛(而且带有该标签的问题相对较少)。就个人而言,我从未完全喜欢维基百科上描述的 PRG。例如,能够将“成功”页面添加到书签或发送链接似乎是错误的。 - Wesley Murch
1
到未来读者看到这里的时候,可能会有更好的解决方案。比如说,在会话中使用多个令牌。实际上...那可能行得通。嗯。 - Gustav Bertram

2

有一个简单的解决方案,您可以在添加产品后重定向到其他页面,例如:

redirect(base_url(). "yourcontrollername/index");

这样做将删除帖子数据,并且数据不会重新添加到数据库中。


我已将 redirect(uri_string(), 'refresh'); 更改为 redirect(uri_string());,并且问题已经解决。我本可以采用您的答案,但它并不是最优化的。 - ARIF MAHMUD RANA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接