首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 短網址/短代碼生成演算法:SHA256 + 自定義字典 + 隨機長度

     編輯:PHP 綜合知識

演算法原理

將輸入字串(如長網址)經 SHA256 雜湊,再以自定義 64 字元字典編碼,並引入隨機步長切分雜湊值,產生 8-16 字元的短代碼。特點:

  • 確定性:相同輸入 + 相同步長 = 相同輸出
  • 隨機長度:增加逆向工程難度
  • URL 安全字元:無需額外編碼

完整實作

<?php
class ShortCodeGenerator {
    // 64 字元字典:URL 安全、無視覺混淆字元
    private const DICTIONARY = '1qaz2wsx3edc4rfv5t-gb6yhn7ujm8ik9ol0p_';
    private const DICT_LEN = 64; // strlen(self::DICTIONARY)
    
    /**
     * 產生短代碼
     * @param string $input 輸入字串(長網址、ID 等)
     * @param int $minLen 最小長度
     * @param int $maxLen 最大長度
     * @return string 短代碼
     */
    public static function generate(string $input, int $minLen = 8, int $maxLen = 16): string {
        // 1. SHA256 雜湊(64 hex 字元 = 256 bits)
        $hash = hash('sha256', $input);
        
        // 2. 隨機步長:決定如何切分雜湊
        $step = random_int($minLen, $maxLen);
        $count = (int)ceil(strlen($hash) / $step);
        
        $code = '';
        for ($i = 0; $i < $count; $i++) {
            $start = $i * $step;
            $chunk = substr($hash, $start, $step);
            
            // hex 轉整數,取低 30 位元
            $num = 0x3fffffff & (1 * '0x' . $chunk);
            
            // 模 64 映射到字典
            $index = $num % self::DICT_LEN;
            $code .= self::DICTIONARY[$index];
        }
        
        return $code;
    }
    
    /**
     * 批次產生(避免衝突重試)
     */
    public static function generateUnique(string $input, callable $existsCheck, int $maxRetries = 5): string {
        for ($i = 0; $i < $maxRetries; $i++) {
            $code = self::generate($input . $i); // 加入鹽值避免衝突
            if (!$existsCheck($code)) return $code;
        }
        throw new RuntimeException('無法產生唯一短代碼,請增加長度或字典');
    }
}

// 使用範例
$urls = [
    'https://example.com/very/long/url/with/many/parameters?foo=bar&baz=qux',
    'https://shop.example.com/product/12345?ref=affiliate&utm_source=newsletter',
    'https://api.example.com/v1/users/987654321/posts?limit=50&offset=100',
];

foreach ($urls as $url) {
    $code = ShortCodeGenerator::generate($url);
    echo "短代碼:$code (長度:" . strlen($code) . ")\n";
    echo "短網址:https://short.ly/$code\n\n";
}
?>

字典設計原則

原則說明本實作字典
長度 642^6,每字元承載 6 bits 資訊量✅ 64 字元
URL 安全無保留字元、無需編碼✅ 無 + / = ? & #
視覺可辨避免 0/O, 1/l/I, 2/Z, 5/S, 8/B 等混淆⚠️ 含 0/o, 1/l 等,建議移除
大小寫混合增加資訊熵、美觀❌ 僅小寫+數字+符號

改良版字典(推薦)

// 移除視覺混淆字元:0 O o, 1 I l, 2 Z, 5 S, 8 B, - _ 等
private const DICTIONARY_V2 = '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz';
// 共 64 字元:數字 2-9 (8) + 大寫除 I,O (24) + 小寫除 l,o (24) = 56... 需補齊
// 標準 Base64URL 字典即為最佳選擇
private const DICTIONARY_BASE64URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';

衝突機率分析

  • 8 字元:64^8 ≈ 2.8×10^14 組合,100 萬筆資料衝突機率 ~0.0002%
  • 10 字元:64^10 ≈ 1.1×10^18,1 億筆衝突機率 ~0.0005%
  • 建議:生產環境最少 8 字元,搭配資料庫 UNIQUE 索引 + 衝突重試

對比:Base62 / Base64URL / 自定義

方案字元數資訊熵/字元標準化適用場景
Base62 (0-9a-zA-Z)625.95 bits事實標準短網址、ID 混淆
Base64URL646 bitsRFC 4648JWT、Token、短網址
本文自定義646 bits無教學、特定需求

結語

短代碼生成核心是「雜湊 + 編碼 + 衝突處理」。生產環境建議:使用標準 Base64URL、資料庫 UNIQUE 索引保證唯一性、Redis 快取映射關係、考慮分散式系統下的雪花演算法 或 UUID 作為替代方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved