带时间戳算法-----类似authcode开源算法

       

      有时候,你需要对加密的字符串加上时间限制。 比如一个小时后失效。类似这种需求, 利用开源算法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;
    }

     当然此算法并不够完美,还是会出现特殊字符,但保证能够完美解密

点赞