防止表單重複提交,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;
}
}