Discuz! 經典隨機數函數 random($length, $numeric) 採用獨特的種子構造方式,結合 microtime() 與 $_SERVER['DOCUMENT_ROOT'] 生成偽隨機字串。本文深度解析其演算法流程與特性。
function random($length, $numeric = 0) {
// 1. 種子材料:微秒時間 + 文檔根目錄
$seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
// 2. 字元池構建
if ($numeric) {
// 純數字模式:移除 0 並補充 012340567890
$seed = str_replace('0', '', $seed) . '012340567890';
} else {
// 混合模式:原種子 + zZ + 大寫版
$seed = $seed . 'zZ' . strtoupper($seed);
}
// 3. 隨機抽取
$hash = '';
$max = strlen($seed) - 1;
for ($i = 0; $i < $length; $i++) {
$hash .= $seed{mt_rand(0, $max)};
}
return $hash;
}
// 測試
echo random(15, 1) . "<br>"; // 純數字
echo random(15); // 混合字母數字
228283270677112 SjqffsU76994qfS
| 步驟 | 代碼 | 目的 |
|---|---|---|
| 種子材料 | microtime() . $_SERVER['DOCUMENT_ROOT'] | 引入高熵時間 + 固定環境變量,增加不可預測性 |
| MD5 雜湊 | md5(...) | 將任意長度輸入壓縮為 32 字元十六進位 |
| 進制轉換 | base_convert(..., 16, 35/10) | 數字模式轉 10 進制(0-9);混合模式轉 35 進制(0-9, a-z) |
| 字元池擴充 | str_replace('0','') . '012340567890 / . 'zZ' . strtoupper() | 確保字元池包含足夠多樣性,避免 base_convert 輸出字元集過窄 |
| 隨機抽樣 | $seed{mt_rand(0,$max)} | 從字元池有放回抽樣 |
mt_rand() 為梅森旋轉演算法,可預測;種子含 DOCUMENT_ROOT 固定值,熵來源有限。// PHP 7+ 加密安全隨機字串
function random_secure($length, $numeric = false) {
$bytes = random_bytes(ceil($length / 2));
$pool = $numeric ? '0123456789' : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$result = '';
for ($i=0; $i<$length; $i++) {
$result .= $pool[random_int(0, strlen($pool)-1)];
}
return $result;
}
// 或使用 bin2hex(random_bytes($n)) 獲取十六進位隨機串
Discuz! random() 是「工程妥協」的典型產物:在 PHP 早期缺乏 random_bytes() 時,以可用性換取開發效率。理解其局限,才能在正確場景做正確選擇。