gpt4 book ai didi

ThinkPHP下表单令牌错误与解决方法分析

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 26 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章ThinkPHP下表单令牌错误与解决方法分析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

本文实例讲述了ThinkPHP下表单令牌错误与解决方法。分享给大家供大家参考,具体如下:

在项目的开发过程中,添加、编辑数据时偶尔会遇到系统提示的“表单令牌错误”,一开始没怎么在意,直到今天下午QA把此问题提到bug系统了,正好时间也有空余,就追着TP3.13的源码看了下去,几分钟后,便知道原委了.

在项目中开启表单令牌,通常要在配置文件中做如下配置 。

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

以编辑数据为例,通常在服务端有个Model写上字段过滤规则,Action写上数据检测的代码,如 。

?
1
2
3
4
$table = D( 'table' );
if (! $table ->create()){
   exit ( $this ->error( $table ->getError()));
}

这时在IDE上双击create()定位到TP框架中Model.class.php中的create方法 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 创建数据对象 但不保存到数据库
* @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;
   }
   ……省略……
}

看到代码会理解当autoCheckToken方法检测失败时会报错,那么就接着跟踪此方法 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 自动表单令牌验证
// 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],那么这个seesion变量时从哪里过来的呢,这还得从生成令牌时说起,定位TokenBuildBehavior.class.php文件 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建表单令牌
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 ;
}

此段代码主要是在TP开启表单验证的情况下,以TOKEN_NAME和当前URI的md5为健生成令牌值,再在用户提交表单时,先验证下是否存在该session,没有则返回false,有则紧接着和表单字段TOKEN_NAME验证下,如果一致先删除此session(作用时避免下次提交出先表单令牌错误),返回ture,否则返回false.

ok,回到主题,TP下表单提交之所以会出现令牌错误,那么就只有两种可能 。

1. 在令牌开启的状态下,提交的表单中,没有TOKEN_NAME字段或是没有相应session(当前提交表单环境下,没有生成相应session,这个主要是在用户提交后报错用户紧接着又刷新当前页面,同时编辑页面和展示页面是在同一个方法里) 。

2. 有session变量,但前后值不一样 。

我们项目之所以出现此错误,可以看看下面配置 。

?
1
2
3
4
5
6
7
return array (
   'TOKEN_ON' => 'false' ,
   'TOKEN_NAME' => '__hash__' ,
   'TOKEN_TYPE' => 'md5' ,
   'TOKEN_RESET' => 'true' ,
   'DB_FIELDTYPE_CHECK' => 'true'
);

本来应该写成布尔值的false,不知道哪位大侠任性的写成字符串的false了,那么判断时当然会按开启表单令牌的逻辑来,而且项目中,添加、编辑和展示都是同一个方法,一旦验证出错,一般程序处理逻辑会返回原有的界面,那么就和上次是同一个表单了,连续提交同一个表单也就相当于重复提交,那么便会报“表单令牌错误”.

希望本文所述对大家基于ThinkPHP框架的PHP程序设计有所帮助.

最后此篇关于ThinkPHP下表单令牌错误与解决方法分析的文章就讲到这里了,如果你想了解更多关于ThinkPHP下表单令牌错误与解决方法分析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com