![]()
本文中的示例描述了ThinkPHP下表单令牌的错误和解决方案. 与您分享以供参考,如下:
在项目的开发过程中,我偶尔会在添加和编辑数据时遇到系统提示的“表单令牌错误”. 我一开始并不在意. 直到今天下午,质量检查人员将此问题提交给了错误系统,我也有空. 我按照TP3.13的源代码进行阅读. 几分钟后,我了解了整个故事.
在项目中打开表单令牌,通常在配置文件中进行以下配置
// 是否开启令牌验证 'TOKEN_ON' => true, // 令牌验证的表单隐藏字段名称 'TOKEN_NAME' => '__hash__', //令牌哈希验证规则 默认为MD5 'TOKEN_TYPE' => 'md5', //令牌验证出错后是否重置令牌 默认为true 'TOKEN_RESET' => true

以编辑后的数据为例表单令牌验证,服务器上通常有一个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;
}
……省略……
}

看到代码将了解,当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;
}

此代码主要是在TP启用表单验证时,以TOKEN_NAME和当前URI的md5作为键来生成令牌值,然后在用户提交表单时表单令牌验证,首先验证会话是否存在,如果不存在,返回false,如果存在,则使用表单字段TOKEN_NAME进行验证. 如果会话是一致的,请首先删除该会话(以避免下次提交时提交第一个表单令牌的错误),返回true,否则返回false.
好,回到主题,在TP下提交表单时会出现令牌错误的原因,那么只有两种可能性
1. 启用令牌后,提交的表单中没有TOKEN_NAME字段或相应的会话(在当前表单提交环境中,不会生成相应的会话,这主要是在用户提交错误并随后报告刷新当前消息之后)页,然后编辑页面并同时显示该页面)
2. 有会话变量,但是前后的值不一样

我们的项目出现此错误的原因,您可以查看下面的配置
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
妈的