轉自: https://www.cnblogs.com/aksir/p/6852544.html
1
|
需求描述:根據用戶id生成與之對應的唯一邀請碼,範圍爲‘0-9A-Z’。
|
這個需求的重點在於加粗的部分,也就是要能夠根據邀請碼反推出用戶ID,這樣邀請碼就不用入庫了,在用戶量很大的情況下,性能可以得到不小的提升。
錯誤思路
隨機生成一個字符串,再將用戶id拼接到字符串後面,但是這樣id就太明顯了,容易暴露,而且如果id很長的話,會導致邀請碼很長,不利於用戶使用。
所以可以將用戶id插入到生成的字符串中,隔一個字符插入一個id的數字,這樣id混合在字符串中,不容易暴露,但是長度問題並沒有得到優化,於是把隔一個字符插入一個id的數字改爲隔一個字符插入兩個id的數字。然而長度好像並沒有受到太大的影響。
正解
思考:一個10進制的數字短還是一個16進制的數字短?
肯定是16進制相對短一些,所以我們可以直接把用戶id轉成10+26=36進制的不就可以了嗎?具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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 ;
}
|
邀請碼保證了唯一性,並且長度不會太長,用戶id也能夠根據邀請碼反推出來,但是有一點不好的是,別人也可以根據邀請碼去反推出user_id,因此,我們需要做一些優化。
優化
把0剔除,當做補位符號,比如小於四位的邀請碼在高位補0,這樣36進制就變成了35進制,然後把字符串順序打亂,這樣,在不知道$source_string
的情況下,是沒辦法解出正確的user_id的。
代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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 ;
}
|
這樣,對應user_id的唯一邀請碼就生成了,再附一個解碼函數:
1
2
3
4
5
6
7
8
9
10
11
12
|
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 ;
}
|