面試提到的需求:根據用戶的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 }