在 URL 短鏈接、訂單號混淆、文件分佈存儲等場景,常需將數字 ID(如自增主鍵)轉為短字母串,且支持反向還原。alphaID 是經典實現,基於進制轉換 + 字符集打亂,支持自定義長度、密鑰加密。本文深度解析原理、代碼、使用場景與注意事項。
<?php
// 數字 → 字母
echo alphaID(12354); // PpQXn7COf
echo alphaID(12354, false, 6); // 指定長度 6
// 字母 → 數字
echo alphaID('PpQXn7COf', true); // 12354
// 帶密鑰(更難破解)
echo alphaID(12354, false, 0, 'my_secret_key'); // 輸出不同字符串
echo alphaID($encoded, true, 0, 'my_secret_key'); // 還原需同密鑰
?>
<?php
/**
* 數字 ID 與短字母 ID 雙向轉換
*
* @param mixed $in 輸入:數字(轉字母) 或 字符串(轉數字)
* @param bool $toNum true=字母轉數字, false=數字轉字母
* @param mixed $padUp 數字/長度:最小長度補位
* @param string $passKey 密鑰:打亂字符集,增加破解難度
* @return mixed 轉換結果
*/
function alphaID($in, $toNum = false, $padUp = false, $passKey = null) {
// 基礎字符集:62 位 (a-z, 0-9, A-Z)
$index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// 密鑰打亂字符集(可選)
if ($passKey !== null) {
$i = str_split($index);
$passHash = hash('sha256', $passKey);
$passHash = (strlen($passHash) < strlen($index)) ? hash('sha512', $passKey) : $passHash;
$p = str_split($passHash);
array_multisort($p, SORT_DESC, $i); // 以密鑰哈希排序字符集
$index = implode($i);
}
$base = strlen($index); // 62
if ($toNum) {
// === 字母 → 數字 ===
$in = strrev($in); // 反轉
$out = 0;
$len = strlen($in) - 1;
for ($t = 0; $t <= $len; $t++) {
$bcp = bcpow($base, $len - $t); // 大數冪運算
$out += strpos($index, $in[$t]) * $bcp;
}
// 補位還原
if (is_numeric($padUp)) {
$padUp--;
if ($padUp > 0) $out -= pow($base, $padUp);
}
$out = sprintf('%F', $out); // 避免科學計數法
$out = substr($out, 0, strpos($out, '.'));
} else {
// === 數字 → 字母 ===
// 補位
if (is_numeric($padUp)) {
$padUp--;
if ($padUp > 0) $in += pow($base, $padUp);
}
$out = '';
for ($t = floor(log($in, $base)); $t >= 0; $t--) {
$bcp = bcpow($base, $t);
$a = floor($in / $bcp) % $base;
$out .= $index[$a];
$in -= $a * $bcp;
}
$out = strrev($out); // 反轉輸出
}
return $out;
}
?>
字符集長度 62,相當於 **62 進制**。數字轉字母本質是「10 進制 → 62 進制」,字母轉數字是「62 進制 → 10 進制」。
例子: 12354 (10進制) → 62進制表示
12354 = 3×62² + 17×62¹ + 8×62⁰
索引: 3 17 8
字符: d r i → "dri" (未打亂時)
使用 `hash('sha256', $passKey)` 生成 64 位十六進制字符串,按字符值降序排序,帶動原字符集同步重排。這相當於**替換密碼**,無密鑰無法還原映射關係。
轉換後 `strrev()` 反轉,使高位在前、低位在後,符合人類閱讀習慣,且使目錄分佈更均勻(見下文)。
指定最小長度,避免 ID 過短(如 `1` → `b`)。原理:轉換前給數字加上 `base^padUp`,轉換後減去。確保輸出長度 ≥ `padUp`。
<?php
// 數據庫自增 ID → 短碼
$shortCode = alphaID($autoIncrementId); // 如 123456789 → "aB3fG"
// 存儲映射: short_codes 表 (code, target_url)
// 訪問 /aB3fG → 解碼得 ID → 查詢目標 URL → 302 跳轉
?>
<?php
// 避免暴露業務量(連續數字)
$publicOrderNo = alphaID($internalOrderId, false, 8, 'order_salt_2024');
// 內部系統解碼還原真實 ID 處理
$realId = alphaID($publicOrderNo, true, 8, 'order_salt_2024');
?>
<?php
// 利用反轉特性:前兩位字符決定目錄層級
$alphaId = alphaID($fileId); // 如 "PpQXn7COf"
$dir1 = $alphaId[0]; // 'P'
$dir2 = $alphaId[1]; // 'p'
$dir3 = substr($alphaId, 2); // 'QXn7COf'
$path = "/storage/$dir1/$dir2/$dir3";
// 好處:62×62=3844 個二級目錄,文件均勻分佈,避免單目錄文件過多
?>
| 限制 | 說明 | 應對 |
|---|---|---|
| 最大支持數字 | ~9007199254740992 (2^53, JS/ PHP float 安全整數上限) | 超大數字用 BCMath/GMP 或分段編碼 |
| 非加密安全 | 僅為混淆,非加密算法,已知算法+樣本可逆推密鑰 | 敏感數據請用 AES/openssl_encrypt |
| 大小寫敏感 | 字符集含大小寫,URL 中區分大小寫 | Web 服務器配置忽略大小寫或統一轉小寫 |
| PHP 版本要求 | 需 BCMath 擴展 (`bcpow`, `bcadd` 等) | 安裝 php-bcmath / php7.x-bcmath |
tuupola/base62,純編碼無加密,極快。alphaID 是一個經典、輕量的數字-短字母雙向轉換函數,通過 62 進制轉換 + 字符集打亂 + 反轉輸出 實現。適用於短鏈接、訂單號混淆、文件分佈等**非安全敏感**場景。生產環境建議使用成熟庫 Hashids,獲得更好可維護性與功能豐富度。