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

PHP 生成短網址(Short URL)原理與實現代碼

     編輯:PHP 相關知識

短網址服務(如 bit.ly、t.cn)的核心是將長 URL 映射為短代碼。本文介紹一種基於 CRC32 哈希 + 62 進制編碼 的無數據庫生成算法,適合無需持久化映射、容許極低碰撞率的場景。

算法原理

  1. CRC32 校驗: 對原 URL 計算 CRC32,得到 32 位無符號整數(範圍 0 ~ 4,294,967,295)。
  2. 無符號化: PHP crc32() 返回有符號整數,用 sprintf('%u') 轉為無符號字符串。
  3. 62 進制轉換: 字符集 0-9a-zA-Z 共 62 個字符,對數值反覆取模 62、除以 62,將餘數映射為字符,直到商為 0。
  4. 拼接結果: 反轉字符順序(或正序拼接),得到短代碼。

字符映射表

餘數範圍映射字符ASCII 計算
0 ~ 9'0' ~ '9'chr($mod + 48)
10 ~ 35'A' ~ 'Z'chr($mod + 55) (10+55=65='A')
36 ~ 61'a' ~ 'z'chr($mod + 61) (36+61=97='a')

完整實現代碼

<?php
/**
 * 生成短網址代碼
 * @param string $url 原始長網址
 * @return string 短代碼(如 "a3f9K")
 */
function dwz($url) {
    // 1. CRC32 哈希並轉為無符號數字字符串
    $code = sprintf('%u', crc32($url));
    $surl = '';

    // 2. 循環轉 62 進制
    while ($code > 0) {
        $mod = $code % 62;
        if ($mod > 9 && $mod <= 35) {
            $mod = chr($mod + 55); // A-Z
        } elseif ($mod > 35) {
            $mod = chr($mod + 61); // a-z
        }
        // 0-9 直接作為字符
        $surl .= $mod;
        $code = floor($code / 62);
    }

    // 3. 反轉字符串(因為是從低位到高位產生)
    return strrev($surl);
}

// 測試
$urls = [
    'https://www.example.com/very/long/url/with/parameters?foo=bar&baz=qux',
    'https://github.com/user/repo/issues/12345',
    'https://localhost:8080/api/v1/users?page=1&size=20'
];

foreach ($urls as $url) {
    echo "原網址: $url\n";
    echo "短代碼: " . dwz($url) . "\n";
    echo "短網址: https://short.ly/" . dwz($url) . "\n\n";
}
?>

特點與局限性分析

維度評價說明
是否需數據庫不需要純算法生成,無狀態,極簡部署
碰撞概率極低但存在CRC32 32位空間約 42 億,生日悖論下 ~7.7 萬條數據有 50% 碰撞概率
可逆性不可逆無法從短代碼反推原 URL,需數據庫存儲映射才能跳轉
短碼長度1 ~ 6 位最大 62^6 ≈ 568 億組合,足夠大多數場景
適用場景內部臨時分享、無狀態服務、日誌標記不適用於公開短鏈服務(需持久化、防掃描、統計分析)

生產級短鏈服務架構建議

若需構建正式短鏈服務,建議採用 「隨機字符串 + 數據庫映射」 模式:

  1. 生成 6-8 位隨機字符(random_bytes + Base62),檢查數據庫唯一性。
  2. 存儲映射:short_code -> long_url,建立索引。
  3. 訪問時查詢數據庫,301/302 重定向,並記錄點擊統計。
  4. 緩存熱門鏈接至 Redis,減輕 DB 壓力。
  5. 提供 API、過期時間、密碼保護、自定義後綴等功能。

進階:Base62 編碼通用函數

<?php
const BASE62_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

function base62_encode($num) {
    if ($num === 0) return '0';
    $result = '';
    while ($num > 0) {
        $result = BASE62_CHARS[$num % 62] . $result;
        $num = intdiv($num, 62);
    }
    return $result;
}

function base62_decode($str) {
    $num = 0;
    $len = strlen($str);
    for ($i = 0; $i < $len; $i++) {
        $num = $num * 62 + strpos(BASE62_CHARS, $str[$i]);
    }
    return $num;
}

// 通用短碼生成:隨機數 + 編碼
function generate_short_code($length = 6) {
    $bytes = random_bytes($length);
    $num = 0;
    foreach ($bytes as $byte) {
        $num = ($num << 8) | $byte;
    }
    return base62_encode($num);
}
?>

CRC32+Base62 算法代碼簡潔、無依賴,適合快速原型、內部工具、日誌標記等輕量場景。構建對外服務時,請採用數據庫映射架構,確保唯一性、可管理性與擴展性。

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