有时候,你需要对加密的字符串加上时间限制。 比如一个小时后失效。类似这种需求, 利用开源算法authcode会很好用, 可是它会出现一些特殊字符串,并且出现解密失效的情况。
别人的算法看起来费劲,改起来更费劲, 不如自己写个简单的,直接上代码
- /**
- * 算法思路。
- * 0、遍历将$a的每位字符都先获取ascii码,再加上2,再返回该值对应的字符
- * 1、获取$a的长度 $b,再将$b转化为16进制。
- * 2、再求$b的长度 $c,再将$c转化为16进制。$c的长度将为1位。因为$a的长度不允许达到16的15次幕
- * 3、将用户传入的时间戳 加上当前时间戳得到$time.
- * 4、再将用户传入的密钥进行一定规则编码得到$d ,
- * 5、定义不重复的9位字符串$m, 再对$time进行从后到前循环循环。
- * 每次循环拿到 $m[$time[$i-1]] 再将其拼装起来得到 $times。 因为$time每位的值肯定不会超过9. 所以不会有超出长度的问题
- * 6、生成一个 位数(1-10)随机 的 随机字符串 $f
- * 7、$res = $c.$times.$b.$a.$f;
- * 8、再将$res 按照规则来打散及重新拼装。如字符串 12345678 ,最后一位,第一位。倒数第二位。第二位....最终得到81726354.
- *
- * 带时间戳算法加密(不限长度)
- * @param $a 待加密字符串
- * @param int $time 加密时长
- * @param $key 密钥
- */
- public static function auth_encode($a,$time=0,$key){
- $keya = md5 ( substr ( $key, 0, 16 ) );
- $keyb = md5 ( substr ( $key, 16, 16 ) );
- $key = md5($keya.$keyb.substr($key,0,10));
- for($i=0,$n=strlen($a);$i<$n;$i++){
- $a[$i] = chr(ord($a[$i])+2);
- }
- $time = $time ? ($time + time()): time();
- $time = (string) sprintf("%012d",$time);
- $strlen = dechex(strlen($a)); //代表字符串的长度
- $strlen1 = dechex(strlen($strlen)); //保证字符串长度的长度是一位。 因为此数最大15, 而字符串的长度可达到16的15次幕。所以绝对够用。
- $times = "";
- $str = "UsHlpba8nD";
- for($i=12;$i>0;$i--){
- $times .= $str[$time[$i-1]];
- }
- $res = $strlen1.$times.$strlen.$a.$key.self::rands(rand(1,10));
- $return = "";
- for($i=0,$n=strlen($res);$i<ceil($n/2);$i++){
- if($n-$i-1 == $i ){ //如果字符长度为
- $return .= $res[$i];
- }else{
- $return .= $res[$n-$i-1].$res[$i];
- }
- }
- return urlencode($return);
- }
- /**
- * 对于上面的方法去进行解密
- * 自定义带时间戳算法解密
- * @param $a
- * @param $key
- */
- public static function auth_decode($a,$key){
- $a = urldecode($a);
- $keya = md5 ( substr ( $key, 0, 16 ) );
- $keyb = md5 ( substr ( $key, 16, 16 ) );
- $key = md5($keya.$keyb.substr($key,0,10));
- $return = "";
- for($i=1,$n=strlen($a);$i<=floor($n/2);$i++){
- $return .= $a[2*$i-1];
- }
- for($i=ceil(strlen($a)/2);$i>0;$i--){
- $return .= $a[2*$i-2];
- }
- $strlen1 = hexdec(substr($return,0,1));
- $times = substr($return,1,12) ;
- $strlen = hexdec(substr($return,13,$strlen1)); //真正有用的字符串长度
- $code = substr($return,(13+$strlen1),$strlen);
- $time = "";
- for($i=strlen($times);$i>0;$i--){
- $time .= strpos("UsHlpba8nD",$times[$i-1]);
- }
- $time = (int) $time;
- if($time < time()){
- return 0;//代表过期
- }
- if(strpos(substr($return,(13+$strlen+$strlen1)),$key) ===0 ){
- for($i=0,$n=strlen($code);$i<$n;$i++){
- $code[$i] = chr(ord($code[$i])-2);
- }
- return $code;
- }else{
- return false; //密钥不等
- }
- }
- /**
- * 随机生成 $n位字符
- * @param $n
- * @return string
- */
- private static function rands($n){
- $randstirng ="abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRST";
- $returns = "";
- for($i=0;$i<$n;$i++){
- $rand = rand(0,strlen($randstirng)-1);
- $returns .= $randstirng[$rand];
- }
- return $returns;
- }
当然此算法并不够完美,还是会出现特殊字符,但保证能够完美解密