需求描述:根據(jù)用戶id生成與之對(duì)應(yīng)的唯一邀請(qǐng)碼寞忿,范圍為‘0-9A-Z’。
這個(gè)需求的重點(diǎn)在于加粗的部分比被,也就是要能夠根據(jù)邀請(qǐng)碼反推出用戶ID胯究,這樣邀請(qǐng)碼就不用入庫了稍计,在用戶量很大的情況下,性能可以得到不小的提升裕循。
錯(cuò)誤思路
隨機(jī)生成一個(gè)字符串臣嚣,再將用戶id拼接到字符串后面,但是這樣id就太明顯了剥哑,容易暴露硅则,而且如果id很長的話,會(huì)導(dǎo)致邀請(qǐng)碼很長星持,不利于用戶使用抢埋。
所以可以將用戶id插入到生成的字符串中弹灭,隔一個(gè)字符插入一個(gè)id的數(shù)字督暂,這樣id混合在字符串中,不容易暴露穷吮,但是長度問題并沒有得到優(yōu)化逻翁,于是把隔一個(gè)字符插入一個(gè)id的數(shù)字改為隔一個(gè)字符插入兩個(gè)id的數(shù)字。然而長度好像并沒有受到太大的影響捡鱼。
正解
思考:一個(gè)10進(jìn)制的數(shù)字短還是一個(gè)16進(jìn)制的數(shù)字短八回?
肯定是16進(jìn)制相對(duì)短一些,所以我們可以直接把用戶id轉(zhuǎn)成10+26=36進(jìn)制的不就可以了嗎?具體代碼如下:
function createCode($user_id)
{
static $source_string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$num = $user_id;
$code = '';
while($num)
{
$mod = $num % 36;
$num = ($num - $mod) / 36;
$code = $source_string[$mod].$code;
}
return $code;
}
邀請(qǐng)碼保證了唯一性缠诅,并且長度不會(huì)太長溶浴,用戶id也能夠根據(jù)邀請(qǐng)碼反推出來,但是有一點(diǎn)不好的是管引,別人也可以根據(jù)邀請(qǐng)碼去反推出user_id士败,因此,我們需要做一些優(yōu)化褥伴。
優(yōu)化
把0剔除谅将,當(dāng)做補(bǔ)位符號(hào),比如小于四位的邀請(qǐng)碼在高位補(bǔ)0重慢,這樣36進(jìn)制就變成了35進(jìn)制饥臂,然后把字符串順序打亂,這樣似踱,在不知道$source_string
的情況下隅熙,是沒辦法解出正確的user_id的。
代碼如下:
function createCode($user_id) {
static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
$num = $user_id;
$code = '';
while ( $num > 0) {
$mod = $num % 35;
$num = ($num - $mod) / 35;
$code = $source_string[$mod].$code;
}
if(empty($code[3]))
$code = str_pad($code,4,'0',STR_PAD_LEFT);
return $code;
}
這樣核芽,對(duì)應(yīng)user_id的唯一邀請(qǐng)碼就生成了猛们,再附一個(gè)解碼函數(shù):
function decode($code) {
static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
if (strrpos($code, '0') !== false)
$code = substr($code, strrpos($code, '0')+1);
$len = strlen($code);
$code = strrev($code);
$num = 0;
for ($i=0; $i < $len; $i++) {
$num += strpos($source_string, $code[$i]) * pow(35, $i);
}
return $num;
}
我的博客:根據(jù)用戶id生成一個(gè)唯一邀請(qǐng)碼,歡迎各位大神一起交流狞洋。