提交数据时提示:表单令牌错误。奶奶的,找了半天发现这个令牌是用来防止远程提交的。也不知道这编辑哪里和他冲突了。
在显示页面里 View类会替换一些公共的,特殊的变量,在View.clss.php 第311行定义了:
protected function templateContentReplace($content) {
// 系统默认的特殊变量替换
$replace = array(
‘../Public’ => APP_PUBLIC_PATH,// 项目公共目录
‘__PUBLIC__’ => WEB_PUBLIC_PATH,// 站点公共目录
‘__TMPL__’ => APP_TMPL_PATH, // 项目模板目录
‘__ROOT__’ => __ROOT__, // 当前网站地址
‘__APP__’ => __APP__, // 当前项目地址
‘__URL__’ => __URL__, // 当前模块地址
‘__ACTION__’ => __ACTION__, // 当前操作地址
‘__SELF__’ => __SELF__, // 当前页面地址
);
if(C(‘TOKEN_ON’)) {
if(strpos($content,'{__TOKEN__}’)) {
// 指定表单令牌隐藏域位置
$replace[‘{__TOKEN__}’] = $this->buildFormToken();
}elseif(strpos($content,'{__NOTOKEN__}’)){
// 标记为不需要令牌验证
$replace[‘{__NOTOKEN__}’] = ”;
}elseif(preg_match(‘/</form(s*)>/is’,$content,$match)) {
// 智能生成表单令牌隐藏域
$replace[$match[0]] = $this->buildFormToken().$match[0];
}
}
// 允许用户自定义模板的字符串替换
if(is_array(C(‘TMPL_PARSE_STRING’)) )
$replace = array_merge($replace,C(‘TMPL_PARSE_STRING’));
$content = str_replace(array_keys($replace),array_values($replace),$content);
return $content;
}
就是替换__PUBLIC__之类的变量,323行 if(C(‘TOKEN_ON’)) 这里就是如果开启了令牌验证,则进行相应的操作。需要验证的话就调用 buildFormToken()方法,357行 $_SESSION[$tokenName] = $tokenValue; 其实就是给$_SESSION[__hash__] 赋值。
如果要解决这问题,只要在页面的</from>之前加入 {__NOTOKEN__}就行了,从上面代码也可看出,如果有这个变量,则把它替换成了空。我在页面上也加了这个,可是仍然出现表单令牌错误。顺便提一下display这个函数:
public function display($templateFile=”,$charset=”,$contentType=’text/html’)
{
$this->fetch($templateFile,$charset,$contentType,true);
}
调用了fetch(),fetch()里又调用了templateContentReplace()就是上面那个函数。
问题没解决,继续找,于是找到了 create()在数据添加时都会调用这个函数,这个函数在Model类里的,有如下内容:
if(C(‘TOKEN_ON’) && !$this->autoCheckToken($data)) {
$this->error = L(‘_TOKEN_ERROR_’);
return false;
}
调用了:
// 自动表单令牌验证
public function autoCheckToken($data) {
$name = C(‘TOKEN_NAME’);
if(isset($_SESSION[$name])) {
// 当前需要令牌验证
if(empty($data[$name]) || $_SESSION[$name] != $data[$name]) {
// 非法提交
return false;
}
// 验证完成销毁session
unset($_SESSION[$name]);
}
return true;
}
这里面有句:if(isset($_SESSION[$name])) 就是前面开启令牌验证后,有一个session 赋值。
$_SESSION[$tokenName] = $tokenValue;
我在if(isset($_SESSION[$name]))前面把$_SESSION[$name])的值赋为空也不行。后来发现必须要在前面 unset($_SESSION[$name]))一下,才有效果。我之前所做的什么赋空格,清缓存都没用。必须把这变量清掉。由于这是session变量,所以在第一次出错后,$_SESSION[$name])有值了。后面怎么做都出错。因为一起没有执行到unset()。所以随便在哪里加一下,运行一下就没问题了。如果实在不行,就在 $replace[‘{__NOTOKEN__}’] = ”;后面加 unset($_SESSION[C(‘TOKEN_NAME]));
要关闭表单令牌验证,只要在配置里将TOKEN_ON’=false就行了。这样就关闭所有的验证了,感觉不是太好,不安全。我那个只是关闭某一个具体表单的验证。手册里有,见:5.3.13