在ThinkPHP下分析表单令牌错误和解决方案

电脑杂谈  发布时间:2020-06-13 09:30:40  来源:网络整理

表单令牌原理_thinkphp表单令牌验证_表单令牌验证

本文中的示例描述了ThinkPHP下表单令牌的错误和解决方案. 与您分享以供参考,如下:

在项目的开发过程中,我偶尔会在添加和编辑数据时遇到系统提示的“表单令牌错误”. 我一开始并不在意. 直到今天下午,质量检查人员将此问题提交给了错误系统,我也有空. 我按照TP3.13的源代码进行阅读. 几分钟后,我了解了整个故事.

在项目中打开表单令牌,通常在配置文件中进行以下配置

// 是否开启令牌验证
'TOKEN_ON' => true,
// 令牌验证的表单隐藏字段名称
'TOKEN_NAME' => '__hash__',
//令牌哈希验证规则 默认为MD5
'TOKEN_TYPE' => 'md5',
//令牌验证出错后是否重置令牌 默认为true
'TOKEN_RESET' => true

表单令牌验证_表单令牌原理_thinkphp表单令牌验证

以编辑后的数据为例表单令牌验证,服务器上通常有一个Model编写字段过滤规则,而Action则编写用于数据检测的代码,例如

$table = D('table');
if(!$table->create()){
  exit($this->error($table->getError()));
}

这时,在IDE上双击create(),以在TP框架的Model.class.php中找到create方法.

/**
* 创建数据对象 但不保存到
* @access public
* @param mixed $data 创建数据
* @param string $type ״̬
* @return mixed
*/
public function create($data='',$type='') {
  ……省略……
  // 表单令牌验证
  if(!$this->autoCheckToken($data)) {
    $this->error = L('_TOKEN_ERROR_');
    return false;
  }
  ……省略……
}

表单令牌验证_表单令牌原理_thinkphp表单令牌验证

看到代码将了解,当autoCheckToken方法失败时,它将报告一个错误,然后遵循此方法

// 自动表单令牌验证
// TODO ajax无刷新多次提交暂不能满足
public function autoCheckToken($data) {
  // 支持使用token(false) 关闭令牌验证
  // 如果在Action写了D方法,但没有对应的Model文件,那么$this->options为空
  if(isset($this->options['token']) && !$this->options['token']) return true;
  if(C('TOKEN_ON')){
    $name  = C('TOKEN_NAME');
    if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效
      return false;
    }
    // 令牌验证
    list($key,$value) = explode('_',$data[$name]);
    if($value && $_SESSION[$name][$key] === $value) { // 防止重复提交
      unset($_SESSION[$name][$key]); // 验证完成销毁session
      return true;
    }
    // 开启TOKEN重置
    if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]);
    return false;
  }
  return true;
}

阅读这段代码后,您会发现第一个判断中有$ _SESSION [$ name],那么该变量是从哪里来的?这必须从生成令牌开始,然后找到TokenBuildBehavior.class .php文件

// 创建表单令牌
private function buildToken() {
  $tokenName = C('TOKEN_NAME');
  $tokenType = C('TOKEN_TYPE');
  if(!isset($_SESSION[$tokenName])) {
    $_SESSION[$tokenName] = array();
  }
  // 标识当前页面唯一性
  $tokenKey  = md5($_SERVER['REQUEST_URI']);
  if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session
    $tokenValue = $_SESSION[$tokenName][$tokenKey];
  }else{
    $tokenValue = $tokenType(microtime(TRUE));
    $_SESSION[$tokenName][$tokenKey]  = $tokenValue;
  }
  $token   = '<input type="hidden" name="'.$tokenName.'" value="'.$tokenKey.'_'.$tokenValue.'" />';
  return $token;
}

表单令牌原理_表单令牌验证_thinkphp表单令牌验证

此代码主要是在TP启用表单验证时,以TOKEN_NAME和当前URI的md5作为键来生成令牌值,然后在用户提交表单时表单令牌验证,首先验证会话是否存在,如果不存在,返回false,如果存在,则使用表单字段TOKEN_NAME进行验证. 如果会话是一致的,请首先删除该会话(以避免下次提交时提交第一个表单令牌的错误),返回true,否则返回false.

好,回到主题,在TP下提交表单时会出现令牌错误的原因,那么只有两种可能性

1. 启用令牌后,提交的表单中没有TOKEN_NAME字段或相应的会话(在当前表单提交环境中,不会生成相应的会话,这主要是在用户提交错误并随后报告刷新当前消息之后)页,然后编辑页面并同时显示该页面)

2. 有会话变量,但是前后的值不一样

表单令牌验证_表单令牌原理_thinkphp表单令牌验证

我们的项目出现此错误的原因,您可以查看下面的配置

return array (
  'TOKEN_ON' => 'false',
  'TOKEN_NAME' => '__hash__',
  'TOKEN_TYPE' => 'md5',
  'TOKEN_RESET' => 'true',
  'DB_FIELDTYPE_CHECK' => 'true'
);

它应该被写成布尔假,我不知道哪个英雄反复地被写成一串假,那么判断当然是基于打开表单标记的逻辑,在工程,添加,编辑和显示都是相同的方法. 一旦验证错误,通用程序处理逻辑将返回原始界面,其格式与上次相同. 连续提交相同表格等同于重复提交,然后将报告“表格顺序”. 卡不良”.

更多与thinkPHP相关的内容感兴趣的读者可以查看此站点的主题: “ ThinkPHP入门教程”,“ ThinkPHP模板操作技能摘要”,“ ThinkPHP通用方法摘要”,“ Codeigniter入门教程”,“ CI(CodeIgniter) )“高级框架教程”,“ Zend FrameWork框架教程”和“ PHP模板技术摘要”.

我希望本文对基于ThinkPHP框架的PHP编程的所有人有所帮助.


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-243976-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...