今天弄了一个简单的数据添加程序,由于用到编辑器,可是又不需要太强大的,于是用了据说是淘宝的kissy_editor编辑器,看上去还不错,于是用了。可一用问题来了。


 


提交数据时提示:表单令牌错误。奶奶的,找了半天发现这个令牌是用来防止远程提交的。也不知道这编辑哪里和他冲突了。


 


在显示页面里 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__之类的变量,323if(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]));


 每次看到表单里有{__NOTOKEN__}就清session


       要关闭表单令牌验证,只要在配置里将TOKEN_ON’=false就行了。这样就关闭所有的验证了,感觉不是太好,不安全。我那个只是关闭某一个具体表单的验证。手册里有,见:5.3.13

Comments are closed.

Post Navigation