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