通过加密计算出短信验证码,无需缓存验证码
<?php
class XixiOtp {
private $iKeeptime; // 验证码有效期
private $sKey; // 加密用的密钥
private $p1Len = 1; // 验证码前缀长度(建议1~2)
private $p2Len = 5; // 验证码后缀长度(建议3~7)
public function __construct($sKey, $iKeeptime = 600) {
$this->sKey = $sKey;
$this->iKeeptime = $iKeeptime;
}
public function setAccount($sAccount) {
// 设置要生成的账号
$this->sAccount = $sAccount;
}
private function numPad($n, $len) {
return str_pad($n, $len, '0', STR_PAD_LEFT);
}
private function getCrc32($str) {
return sprintf('%u', crc32($str));
}
private function getP2($iT1, $iP1) {
// 通过时间和验证码前缀来计算验证码的后缀
$iT2 = intval(($iT1 - $iP1 * $this->iKeeptime / pow(10, $this->p1Len)) / $this->iKeeptime);
$sP1 = $this->numPad($iP1, $this->p1Len);
$arr = array($this->sAccount, $iT2, $sP1, $this->sKey);
$crc = $this->getCrc32(implode(',', $arr));
$iP2 = $crc % pow(10, $this->p2Len);
return $this->numPad($iP2, $this->p2Len);
}
public function getCode() {
// 取得Otp验证码
$iT1 = time();
$m = $iT1 % $this->iKeeptime;
$iP1 = intval($m * pow(10, $this->p1Len) / $this->iKeeptime);
$iP2 = $this->getP2($iT1, $iP1);
return $this->numPad($iP1, $this->p1Len) . $iP2;
}
public function verify($code) {
// 校验Otp验证码是否有效
$iT1 = time();
$sP1 = substr($code, 0, $this->p1Len);
$sP2 = substr($code, $this->p1Len);
return $sP2 === $this->getP2($iT1, intval($sP1));
}
public static function test() {
// 测试代码
$iKeeptime = 600;
$otp = new XixiOtp('feieryun.cn', $iKeeptime);
$otp->setAccount('309385018@qq.com');
$sCode = $otp->getCode();
echo($sCode . "\r\n");
for ($i = 0; $i <= $iKeeptime; $i++) {
echo $i . ':';
var_dump($otp->verify($sCode));
sleep(1);
}
}
}
XixiOtp::test();
可用于发邮件或短信验证码,无需创建表存储验证码