我们在实际项目运用中,难免会要求对ID进行加密,生成特定的字符串,比如生成用户邀请码,这样不用查数据库也可以反向解密到id
为什么使用32进制
因为数字加字母长度为36位,32位生成后不用区别用户输入不用区分大小写
1<?php 2class IDAES{ 3 $baseChar = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; 4}
加解密基础版,可以生成任意长度
不同的长度能容纳的位数不一样,可以容纳数字最大值为32的n次方,比如固定长度为6,那么最大值为1,073,741,824,如果长度为7,最大值为34,359,738,368
1<?php 2class IDAES{ 3 //32进制用来移位的字符串,顺序可以随机生成,提高强度 4 static $baseChar = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; 5 //id起始值,保证id比较小时的密钥强度 6 const CODESTART= 123456; 7 //密钥长度, 8 const CODELEN = 6; 9 10 //加密 11 static function idToString($id){ 12 $id += self::CODESTART; 13 $str = ''; 14 while ($id!=0){//进制转换 15 $tmp = $id % 32; 16 $str .= self::$baseChar[$tmp]; 17 $id = intval($id/32); 18 } 19 $str = strrev($str); 20 //位数如果不足用保留字母U填补,长度可以随意 21 return str_pad($str, self::CODELEN, 'U', STR_PAD_LEFT); 22 } 23 24 //解密 25 static function stringToId($str){ 26 $str = trim($str,'U'); 27 $charArr = array_flip(str_split(self::$baseChar)); 28 $num = 0; 29 $strlen = strlen($str); 30 for ($i=0;$i<=$strlen-1;$i++) 31 { 32 $_str = $str[$i]; 33 if(!isset($charArr[$_str])){ 34 return ''; 35 } 36 $num += $charArr[$_str]*pow(32,$strlen-$i-1); 37 } 38 39 return intval($num - self::CODESTART); 40 } 41}
进一步思考,我们可以对最终生成的字符串进行再次替换进一步混淆,防止反破解,我们这里可以将固定填充位改成随机生成混淆字符串
1<?php 2 3 //... 省略代码 4 //加密部位标识,这里根据生成自己的生成长度定,值任意排列 5 static $tagChar = ['A','B','C','D','E','F','G','H']; 6 7 //...继续省略,在加密的最后一段改成 8 $difflen = self::CODELEN-strlen($str); 9 $pre = self::$tagChar[$difflen]; 10 for ($i=0; $i<$difflen; $i++){ 11 $k = rand(0, 31); 12 $pre .= self::$baseChar[$k]; 13 } 14 $str = $pre.$str; 15 return $str; 16 17 //...日常省略,在解密的时先去掉混淆字符串 18 $pos = $str{0}; 19 $start = array_search($pos, self::$tagChar); 20 $str = substr($str, $start+1); 21 //获取32进制字符串后,继续解密...
当然还可以复杂化处理,进行再次加密
声明:最初的代码参考自https://blog.csdn.net/weixin_30443731/article/details/97862594