[PHP] 產生碰撞(collision)機率低的短亂碼

這主題看似容易其實很有深度。從為甚麼要有這個「亂碼」開始,就是希望可以在做某件事的時候讓「重複」(碰撞)的機率減低,而最好的狀況就是不存在碰撞。

寫程式的人可能多少都用過「隨機」函數,但其實這方法並不是真的隨機,沒有想像中那般真的無法預測,也無法單靠它來避免碰撞。

不過有些變形的操作倒是能「盡量」避免,無法完全保證不碰撞。下面是研究的參考資料整理:

條件

  1. 短字串
  2. 碰撞機率低

不需資料關聯類型

這邊概念就是射後不理,產生出來就不理他了。可以透過使用多次隨機方法組合產生,至於碰撞機率這個問題就很不一定了。方法可以參考這篇Creating collision free “random” string 討論以及 PHP 7 的方法「random_bytes」!(其他像是單純使用 uniqid 方法反而要小心,可以參考文件討論串)

至於結果字串短不短還真是要看怎麼實作了,這邊只提到底層方法。

需要資料關聯

上個部分連結討論中都有一些解法,但如果需要有點規律跟甚至是做資料關聯呢?最好的案例就是縮網址系統

如何在確定有某種排序下將序號做重新編碼避免資料太容易曝光、可預測,以及縮短資料長度?

參考這篇文章:「Generating IDs like Youtube or Bit.ly using PHP」教學如何使用 PHP 產生出像 YouTube 或 Bitly 的亂碼字串。

原理即是透過改變進位法,把數字的 10 進位法去延伸更高進位的概念做字串替換。將原本數字 0~9 的變化強化到 0~9, a~z, A~Z 的 62 進位。

但 PHP 進位方法 base_convert 只支援 2~36 的處理,也就是要做到 62 進位處理就需要自己來了,感謝 Taylor Otwell 大大的支援得以產出這算法

好,到這邊還差一步,轉換前需要一個「不重複」數字序號來轉換,如果使用資料庫自動累加產生的主鍵編號,直接套入沒問題,那想要一樣先射後不理之後再說的呢?

保險起見,可以使用 microtime 方法來因應快速大量產生編碼的情況,避免單純以 timestamp 處理會有重複問題!(呼叫時間區間太短)

list($usec, $sec) = explode(" ", microtime());
Math::to_base($usec * 10000000 + time(), 62);

透過這個進位處理方法,將字串每一個位元的可能性拉大,自然是縮短又解決序號太容易猜測的好辦法!

Facebook 外掛整合


Share: