根据用户量来生成最短的邀请码
面试提到的需求:根据用户的ID和字符串的组合来生成较短的邀请码,还有就是根据这个邀请码解析出邀请码对应的用户ID;生成这样的邀请码我们就不放在数据库里面了,在用户量很大的情况下,对于性能是一个很大的提升。
我错误的设计方案:
方案一:随机生成一个字符串在和用户ID做拼接,首先这样的想法就是错的,如果是在这样生成的,别人也会拿到用户的ID,这个时候我们的数据就不安全;还有一点不满足需求,需求说邀请码尽可能短。
方案二:我们将我们的用户id,按照一定的规则插入到随机字符串,比如隔一个字符或或者两个字符插入,这样可以解决方案一安全的问题,但是长度的问题是不能解决的,这个方案又死了;
后面我也没有想到什么方案去解决,面试就死了。
正确的方案:
因为当时面试时间短,没有考虑的很详细。后面我查了一些资料,看过之后我就想当时怎么这么菜,因为十进制的数据肯定长,但是我们的十六进制,相对十进制是很短的;这个时候看到一篇文章上面的思路是将用户的ID转换为10+26=36进制的数不就可以了嘛
1 function createCode($user_id) 2 { 3 static $source_string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 4 $num = $user_id; 5 $code = ''; 6 while($num) 7 { 8 $mod = $num % 36; 9 $num = ($num - $mod) / 36; 10 $code = $source_string[$mod].$code; 11 } 12 return $code; 13 }
邀请码保证了唯一性,并且长度不会太长,用户id也能够根据邀请码反推出来,但是有一点不好的是,别人也可以根据邀请码去反推出user_id,因此,我们需要做一些优化。
优化
把0剔除,当做补位符号,比如小于四位的邀请码在高位补0,这样36进制就变成了35进制,然后把字符串顺序打乱,这样,在不知道$source_string的情况下,是没办法解出正确的user_id的。
1 //生成邀请码 2 function createCode ($user_id) 3 { 4 static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ'; 5 $num = $user_id; 6 $code = ''; 7 while ($num > 0) { 8 $mod = $num % 35; 9 $num = ($num - $mod) / 35; 10 $code = $source_string[$mod].$code; 11 } 12 if(empty($code[3])){ 13 $code = str_pad($code, 4, '0', STR_PAD_LEFT); 14 } 15 return $code; 16 }
这样,对应user_id的唯一邀请码就生成了,再附一个解码函数:
1 //解析邀请码 2 function deCode ($code) 3 { 4 static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ'; 5 if (strrpos($code, '0') !== false){ 6 $code = substr($code, strrpos($code, '0')+1); 7 } 8 $len = strlen($code); 9 $code = strrev($code); 10 $num = 0; 11 for ($i=0; $i < $len; $i++){ 12 $num += strpos($source_string, $code[$i]) * pow(35, $i); 13 } 14 return $num; 15 }