專案常需生成唯一標識 (訂單號、Token、檔案名、邀請碼)。本文分析常見方案優劣,提供一個兼顧唯一性、不可預測性、效能的最佳實踐函數。
| 方案 | 唯一性 | 不可預測性 | 效能 | 長度 |
|---|---|---|---|---|
uniqid() | 高 (微秒時間) | 低 (可推測時間) | 極快 | 13/23 字元 |
md5(uniqid()) | 高 | 中 | 快 | 32 字元 |
random_bytes(16) + bin2hex | 極高 (CSPRNG) | 極高 | 中 | 32 字元 |
| UUID v4 (ramsey/uuid) | 極高 | 極高 | 中 | 36 字元 |
| 本文方案 | 高 | 高 | 快 | 40 字元 (SHA1) |
<?php
/**
* 生成唯一、不可預測的 Hash ID
*
* @param int $randomBytes 隨機字節數 (建議 8-16)
* @param string $algo 雜湊算法 (sha1, sha256, md5)
* @return string 十六進位 Hash 字串
*/
function generateUniqueHash(int $randomBytes = 16, string $algo = 'sha1'): string {
// 1. 基礎唯一性:微秒時間 + 進程 ID
$base = uniqid('', true); // 更多熵值 (含微秒)
// 2. 加密安全隨機字節 (PHP 7+ random_bytes, 5.6+ openssl_random_pseudo_bytes)
try {
$random = random_bytes($randomBytes);
} catch (Exception $e) {
// 降級方案 (不推薦生產環境)
$random = openssl_random_pseudo_bytes($randomBytes, $strong);
if (!$strong) {
trigger_error('CSPRNG unavailable, fallback used', E_USER_WARNING);
}
}
// 3. 合併並雜湊
$data = $base . $random;
return hash($algo, $data, false); // false = 十六進位小寫
}
// 使用範例
echo generateUniqueHash(); // 40 字元 SHA1
echo generateUniqueHash(16, 'sha256'); // 64 字元 SHA256
echo generateUniqueHash(8, 'md5'); // 32 字元 MD5
?>
true 啟用「更多熵值」,輸出如 5f8c3a2b1d4e6.12345678,含微秒與 PID,比單純 uniqid() 難預測。/dev/urandom / CryptGenRandom),不可預測性最強。若需類 YouTube 短網址 (如 dQw4w9WgXcQ 11 字元),可將隨機字節 Base62 編碼:
<?php
function generateShortId(int $bytes = 8): string {
$random = random_bytes($bytes);
$alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$base = strlen($alphabet);
$num = gmp_init(bin2hex($random), 16); // 大整數
$result = '';
while (gmp_cmp($num, 0) > 0) {
[$num, $rem] = gmp_div_qr($num, $base);
$result = $alphabet[gmp_intval($rem)] . $result;
}
return str_pad($result, 11, $alphabet[0], STR_PAD_LEFT); // 固定長度
}
// 需啟用 gmp 擴充
?>
md5(time().rand()):rand() 非加密安全、時間可預測、極易碰撞。uniqid() 當 Token:可暴力枚舉時間窗口破解。UNIQUE INDEX,捕獲 Duplicate entry 重試。composer require ramsey/uuid use Ramsey\Uuid\Uuid; $uuid = Uuid::uuid4()->toString(); // 標準 UUID v4 (隨機) $uuid7 = Uuid::uuid7()->toString(); // UUID v7 (時間有序,適合資料庫主鍵)
生產專案強烈建議引入成熟庫,避免重複造輪子與安全隱患。
掌握唯一 ID 生成原理,根據業務場景 (長度、可讀性、有序性、安全性) 選擇合適方案,是後端工程師必備技能。