hansonfox 发表于 2012-6-4 15:27:00

一个困扰了很久的问题:防止表单重提交

在CI中如何防止在刷新页面的时候表单重新提交呢?
据说是要跳转页面,但是始终搞不清怎么做
例如一个要把提交内容写入数据库 的表单,第一次已经成功并且转到成功页面去了,这个时候怎么做能不让刷新这个成功页面的时候重提交数据?
为这个问题已经困扰了N久了。。。。。。
求高人指条明路,跪谢~

幽蓝冰魄 发表于 2012-6-4 15:55:47

session 里面有个 last active,判断时间差。

jeongee 发表于 2012-6-4 17:01:29

提交成功redirect走人

suxiaolu 发表于 2012-6-4 17:30:01


if ($this->input->post('submit'))
{
......

redirect(...);
}

ciogao 发表于 2012-6-5 00:14:01

提交后重定向一次

deader 发表于 2012-6-14 16:06:43

嗯,重定向 我也是 这么干的

deader 发表于 2012-6-14 16:18:29

很久没敲代码了,现在分享一个我以前写的 MY_Controller,含有令牌验证(防止重复提交的)

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
//基础控制器

class MY_Controller extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->library('form_validation');
$this->load->library('encrypt');
$this->load->model('admin/m_resources','m_resources');
$this->load->model('admin/m_rights','m_rights');
$this->load->model('admin/m_groups','m_groups');

$this->_init(); //自动检查用户是否登录及权限判断
}

function _init()
{
//任何未登录的用户都初始化为guest组
if( ! $this->session->userdata('groups'))
{   
   $this->session->set_userdata(array('groups'=>'guest'));
}
$this->_check_url_permisson();
}

/**
* 检查url权限,如果可以访问则正常进行,若无权限则提示并终止执行
* 后续扩展字段权限
* 注意:需要严格定义资源
*/
function _check_url_permisson()
{
$current_url = $this->uri->uri_string() ? trim('/'.$this->uri->uri_string()) : '/welcome';
@$resource_id = $this->m_resources->get_resources_by_url('id',$current_url)->result();
$current_resource_id = $resource_id ? $resource_id->id : 0;

//如果当前角色为guest,则直接获取guest权限,不必登录
if($this->session->userdata('groups') && $this->session->userdata('groups') == 'guest')
{
   $res = $this->m_groups->get_group_by_name('guest')->result();
   $gid = $res->id;
   @$guest_resource = $this->m_rights->get_resources_by_gid('resource_id',$gid)->result(); //guest组所拥有的权限   
   
   if($guest_resource && is_array($guest_resource))
   {
    foreach ($guest_resource as $grs)
    {
   $rest[] = $grs->resource_id;
    }
   }
   @$current_gp_res = @$rest; //guest组所拥有的权限
   $this->session->set_userdata('resources',$current_gp_res);
}

$my_resources = $this->session->userdata('resources');

if($my_resources && is_array($my_resources) && @in_array($current_resource_id,$my_resources))
{
   return ;   
}
else
{   
   $this->_check_login();
}
}


/**
* 检查是否登录
*
*/
function _check_login()
{
if($this->session->userdata('is_login') && $this->session->userdata('is_login') === true)
{
   return ;
}
else
{   
   redirect(s_url('/admin/auth/login'),'location');
}
}

/**
* 生成在线编辑器
*
* @param string $area 编辑器输入域名称
* @param string $value 编辑器输入域值
* @param number $width 宽度
* @param unknown_type $height 高度
* @param unknown_type $autoSave 是否自动保存
* @return 编辑器域
*/
public function editor($area,$value='',$width=630,$height=400,$autoSave=false)
{
      //加载在线编缉器
      $this->load->library('seditor');
      $editor = $this->seditor->SunEditor($area);
      $editor->Value = $value;
      $editor->BasePath = 'editor';
      $editor->Height= $height;
      $editor->Width = $width;
      $editor->AutoSave = $autoSave;
      return $editor->Create();               
}

/**
* 获取表单的值
* @param $name 表单元素名称
* @param $type 提交方式,默认为post
* @param $xxsf 让取得的数据经过跨站脚本过滤(XSS Filtering),默认为false,开启为true
*/
public function obtain($name,$type='post',$xxsf=false)
{
if($type == 'post')
{
   return $this->input->post($name,$xxsf);
}
else if($type == 'get')
{
   return $this->input->get($name,$xxsf);
}
else
{
   return $this->input->get_post($name,$xxsf);
}
}

/*pagination 分页程序
* $where: 需要分页的url地址,即完整的分页控制器/方法
* $total_rows: 需要分页的数据总行数,通过查询数据库取得
* $per_page: 每页中希望显示信息的数量
* $uri_segment: URI的哪个部分包含页数
* $num_links: 显示分页提示数量
* $first_url: 分页链接首页链接
*/
function _pagination($array)
{
$this->load->library('spagination');
$config['pagination_fix'] = true; // 是否启用分页修正功能,如设置为 false 则和系统自带分页类无异
$config['base_url'] = $array['where'];
$config['total_rows'] = $array['total_rows'];
$config['per_page'] = $array['per_page'];
$config['uri_segment'] = $array['uri_segment'];
$config['num_links'] = $array['num_links'];
//$config['first_url'] = $array['first_url']; // 分页链接首页链接

//以下为默认设置,可以自行修改
$config['full_tag_open'] = '<div class="pagination">'; //可根据需要改为<p>
$config['full_tag_close'] = '</div>'; //可根据需要改为</p>
$config['first_link'] = '首页';
$config['last_link'] = '末页';
$config['next_link'] = '下一页 >';
$config['prev_link']= '< 上一页';
$config['cur_tag_open'] = '<a class="current">';
$config['cur_tag_close'] = '</a>';

//修正样式开始
$config['cur_rows_tag_open'] = '<a class="number">当前第 ';
$config['cur_rows_tag_middle'] = ' ~ ';
$config['cur_rows_tag_close'] = ' 条</a>';
$config['total_rows_tag_open'] = ' <a class="number">共 ';
$config['total_rows_tag_close'] = ' 条</a>';
$config['total_pages_tag_open'] = ' <a class="number">计 ';
$config['total_pages_tag_close'] = ' 页</a>';
//修正样式结束

/*以下配置默认关闭,可以通过css来美化分页效果,配置格式应为:
* $config['first_tag_open'] = "<div class='someclass'>";
* $config['first_tag_close'] = "</div>";
*/
//$config['first_tag_open'] = '<div>';
//$config['first_tag_close'] = '</div>';
//$config['last_tag_open'] = '<div>';
//$config['last_tag_close'] = '</div>';
//$config['num_tag_open'] = '<div>';
//$config['num_tag_close'] = '</div>';
//$config['prev_tag_open'] = '<div>';
//$config['prev_tag_close'] = '</div>';
//$config['next_tag_open'] = '<div>';
//$config['next_tag_close'] = '</div>';
   
$this->spagination->initialize($config);
}

/**
* 停止执行程序,给出错误信息,并写入错误日志。
* 所有参数由helper提供
*
* @param $error_code 错误代码,用于区分错误类别
* @param $error_level 错误级别
* @param $error_message 错误提示信息
*/
public function stop_doing($error_code='',$error_level='',$error_message='')
{
$this->load->library('slog');
//写入日志
$error_url = $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$this->slog->process_logs($error_url,$error_code,$error_level,$error_message);
$rediret_url = 'http://'.$error_url;
header("Content-type:text/html; charset=utf-8");
die("<script type=\"text/javascript\">alert(\"错误信息!\\n \\n错误代码:".$error_code."\\n错误级别:".$error_level."\\n错误信息:".$error_message."\"); window.navigate(\"$rediret_url\");</script>");
}

/**
* 令牌验证
*/
const FORM_TOKEN_KEY = 'form_token_key';
const INPUT_TOKEN_NAME = 'input_token_name';

/**
* 生成令牌
*
* @return string
*/
public function gen_token()
{
$hash = md5(uniqid(rand(), true));   
$token = sha1($hash);
return $token;
}

/**
* 生成session令牌
*
*/
public function gen_session_token()
{
//生成token
$token = $this->gen_token();
//删除session中原来的token
$this->destroy_stoken();
//将新的token注册到session
$this->session->set_userdata(self::FORM_TOKEN_KEY,$token);
}

/**
* 生成隐藏输入域表单
*
* @return 表单
*/
public function gen_input()
{
$this->gen_session_token();
$token_input ="<input type=\"hidden\" name=\"".self::INPUT_TOKEN_NAME."\" value=\"".$this->session->userdata(self::FORM_TOKEN_KEY)."\" readonly=\"true\" /> ";
return $token_input;
}

/**
* 检测token是否合法,如果合法则继续执行,否则跳出
*
* @param string $token_input 页面提交的token
*/
public function token_check($token_input)
{
// 检测session中是否已注册token
if($this->is_stoken())
{
   if($token_input)
   {
    if($token_input == $this->session->userdata(self::FORM_TOKEN_KEY))
    {
   $this->destroy_stoken();
    }
    else
    {
   $this->destroy_stoken();   
   $this->stop_doing(error_code('d'),error_level('ce'),error_message('d_add'));
    }
   }
   else
   {
    $this->destroy_stoken();
    $this->stop_doing(error_code('v'),error_level('ce'),error_message('v_null'));
   }
}
else
{
   $this->destroy_stoken();
   $this->stop_doing(error_code('s'),error_level('e'),error_message('s_check'));
}
}

/**
* 销毁token
*
* @return bool
*/
public function destroy_stoken()
{
$this->session->unset_userdata(self::FORM_TOKEN_KEY);
      return true;
}

/**
* 检测token是否存在
*
* @return bool
*/
public function is_stoken()
{
if($this->session->userdata(self::FORM_TOKEN_KEY))
         return true;
      else
         return false;
}

/**
* 合并数组中的相同项
*/
function array_multi_unique($ar)
{
   $ar = array_map('serialize', $ar);
   $ar = array_unique($ar);
   return array_map('unserialize', $ar);
}

}

gs129090 发表于 2013-5-29 08:28:54

受教了{:1_1:}{:1_1:}{:1_1:}
页: [1]
查看完整版本: 一个困扰了很久的问题:防止表单重提交