Home  >  Article  >  Backend Development  >  Analysis of form token errors and solutions under ThinkPHP

Analysis of form token errors and solutions under ThinkPHP

不言
不言Original
2018-06-07 10:31:401918browse

This article mainly introduces the form token errors and solutions under ThinkPHP. It analyzes the principle, configuration, error causes and corresponding solutions of thinkPHP form token in more detail. Friends in need can refer to it

The examples in this article describe the form token errors and solutions under ThinkPHP. Share it with everyone for your reference, the details are as follows:

During the development process of the project, I occasionally encountered the "Form Token Error" prompted by the system when adding and editing data. I didn't pay much attention to it at first, until today. In the afternoon, QA mentioned this issue to the bug system. I happened to have some free time, so I followed the source code of TP3.13 and read it. After a few minutes, I knew the whole story.

To enable form tokens in the project, you usually need to make the following configuration in the configuration file

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

Take editing data as an example, usually in There is a Model on the server with field filtering rules, and the Action with data detection code, such as

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

At this time, double-click create() on the IDE to locate The create method in Model.class.php in the TP framework

/**
* 创建数据对象 但不保存到数据库
* @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;
  }
  ……省略……
}

When you see the code, you will understand that an error will be reported when the autoCheckToken method fails to detect, so continue to track this Method

// 自动表单令牌验证
// 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;
}

After reading this code, you will find that there is $_SESSION[$name] in the first judgment, so where does this seesion variable come from? Well, this has to start when generating the token, locating the TokenBuildBehavior.class.php file

// 创建表单令牌
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   = &#39;<input type="hidden" name="&#39;.$tokenName.&#39;" value="&#39;.$tokenKey.&#39;_&#39;.$tokenValue.&#39;" />&#39;;
  return $token;
}

This code is mainly used to enable form verification in TP In this case, the token value is generated based on TOKEN_NAME and the md5 of the current URI. When the user submits the form, first verify whether the session exists. If not, return false. If yes, then verify with the form field TOKEN_NAME. If it is consistent Delete this session first (when used to avoid form token errors when submitting next time), return true, otherwise return false.

ok, back to the topic, the reason why a token error occurs when submitting a form under TP, there are only two possibilities

1. When the token is turned on, in the submitted form , there is no TOKEN_NAME field or no corresponding session (in the current submission form environment, no corresponding session is generated. This is mainly because an error is reported after the user submits and the user then refreshes the current page. At the same time, the editing page and the display page are in the same method)

2. There is a session variable, but the before and after values ​​are different

The reason why this error occurs in our project can be seen in the following configuration

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

It should have been written as false as a Boolean value. I don’t know which hero wrote it as false as a string. Then of course the judgment will be based on the logic of opening the form token, and in the project, add, edit and The display method is the same. Once there is an error in verification, the general program processing logic will return to the original interface, then it will be the same form as last time. Continuous submission of the same form is equivalent to repeated submission, then " Form token error".

Related recommendations:

thinkPHP’s method of implementing the check-in function

thinkPHP’s method of implementing excel data Import and export (with complete case)

The above is the detailed content of Analysis of form token errors and solutions under ThinkPHP. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn