1. 程式人生 > >防止表單重複提交,PHP生成token並自動更新

防止表單重複提交,PHP生成token並自動更新

PHP生成token並自動更新。

在業務中,經常會遇到重複提交問題。token是一種解決表單重複提交的思路,token 原理大致為:
1:顯示錶單的那個 action 中使用 makeToken() 生成一個隨機的 token值,稱作 requestToken ,並存放在服務端(session或者cache中),並且傳遞一份到頁面中
2:表單頁面使用一個隱藏表單域獲取後端傳過來的 requestToken 值,該表單頁面提交時會將此 requestToken 值一同提交到後端
3:在表單頁面提交 actioin 後,服務端使用 checkToken(requestToken) 來比較服務端剛才下發的原 token 值,如果服務端存在 token 值並且與表單提交過來的值相等,證明是第一次提交。
4:每次校驗過後服務端的 token 值會立即被清除,所以當用戶重複提交時,後面的提交校驗都再也無法通過。從而實現了防止重複提交的功能,checkToken 是在 synchronized 塊中執行的保障了多執行緒下的安全性。

直接上程式碼:

WebToken.php:

<?php
/*
    提供基礎的token服務,儲存在session,校驗後自動更新。
    使用場景:
        提交表單前下發一個token,使用$this->makeToken();
        提交表單的時候,帶上這個token;提交後伺服器校驗此token,$this->checkToken($reqToken);並自動重新整理不會重複。

來源:http://blog.csdn.net/xuduorui/article/details/59108024
*/
class WebToken {
    const SIGN_KEY      = '-O=M<.`!';
    const SESSION_KEY   = 'ATOKEN';


    protected $token;
    
    function __construct() {
        session_start();
        $this->init();
    }
    
    public function init() {
    }
    
    public function makeToken($expire = 300) {
        $session_id = session_id();
        $time = microtime(true);
        $token = substr(md5($session_id.self::SIGN_KEY .$time), 3, 20);
        $this->saveToSession($token, $expire);
        return $token;
    }
    //驗證token並自動重新整理token
    public function checkToken($token, $renew=1) {
        // 取出token並作廢session
        $tokenInSession = $_SESSION[self::SESSION_KEY];
        unset($_SESSION[self::SESSION_KEY]);
        if ($renew) {
            $this->token = null;//$this->makeToken();
        }
        // 空則返回檢查失敗
        if (!$tokenInSession) {
            return false;
        }
        
        // 檢查session的token是否過期
        if ($tokenInSession['e'] < time()) {
            unset($_SESSION[self::SESSION_KEY]);
            return false;
        }
        // 檢查token值
        if (!empty($token) && $tokenInSession['t']==$token) {
            return true;
        }
        return false;
    }

    // 獲取token並不重新整理
    public function getToken() {
        if (!$this->token) {
            $this->token = $this->makeToken();
        }
        return $this->token;
    }
    protected function saveToSession($token, $expire=300) {
        $value = [
            't' => $token,  //token
            //'c' => time()+$expire, //create_time
            'e' => time()+(int)$expire,
        ];
        $_SESSION[self::SESSION_KEY] = $value;
        //$
        return $value;
    }
}