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

PHP 實作短網址服務:基於 Memcached 與 Base62 編碼的完整方案

     編輯:PHP 相關知識

短網址服務是將冗長 URL 轉換為短碼(如 https://short.ly/abc123)的經典應用。本文提供一個生產級可用的 PHP 類別,採用 Memcached 做高速儲存、Base62 編碼 產生短碼、自增 ID 保證唯一性,並支援編碼/解碼雙向操作,適合高併發場景。

核心設計原理

  1. 去重機制:對原始 URL 計算 MD5,以 MD5 為 Key 查詢 Memcached,已存在則直接回傳現有短碼。
  2. ID 生成:使用 Memcached increment() 原子操作產生唯一遞增數字 ID(初始值 10000 避免過短)。
  3. Base62 編碼:將數字 ID 轉為 0-9、a-z、A-Z 組成的短字串,長度隨 ID 增長自動增加。
  4. 雙向映射:儲存 MD5 → ID、短碼 → 原始 URL 兩組映射,實現 O(1) 查詢。

完整類別實作

<?php
class ShortUrlService
{
    private $memcached;
    private $baseUrl;

    public function __construct(array $memcachedServers, string $baseUrl = 'https://short.ly/')
    {
        $this->baseUrl = rtrim($baseUrl, '/') . '/';
        $this->memcached = new Memcached();
        foreach ($memcachedServers as $server) {
            $this->memcached->addServer($server['host'], $server['port']);
        }
        // 初始化自增計數器(僅首次執行需設定)
        if ($this->memcached->get('auto_increment_id') === false) {
            $this->memcached->set('auto_increment_id', 10000);
        }
    }

    /**
     * 編碼:長網址 → 短網址
     * @param string $url 原始長網址
     * @return string|false 短網址或失敗回傳 false
     */
    public function encode(string $url)
    {
        $url = trim($url);
        // 基本 URL 格式驗證
        if (!preg_match('#^https?://#i', $url)) {
            return false;
        }

        $md5 = md5($url);
        $id = $this->memcached->get($md5);

        if ($id === false) {
            // 取得下一個可用 ID(原子遞增)
            $id = $this->memcached->increment('auto_increment_id');
            if ($id === false) {
                // 理論上不會發生,但保底重置
                $this->memcached->set('auto_increment_id', 10000);
                $id = $this->memcached->increment('auto_increment_id');
            }

            // 建立雙向映射
            $this->memcached->set($md5, $id);
            $key = $this->dec2any($id);
            $this->memcached->set($key, $url);
        } else {
            $key = $this->dec2any($id);
        }

        return $this->baseUrl . $key;
    }

    /**
     * 解碼:短網址 → 原始長網址
     * @param string $shortUrl 完整短網址或僅短碼
     * @return string|false 原始網址或找不到回傳 false
     */
    public function decode(string $shortUrl)
    {
        $key = str_replace($this->baseUrl, '', trim($shortUrl));
        $url = $this->memcached->get($key);
        return $url ?: false;
    }

    /**
     * 十進位轉 Base62 (0-9, a-z, A-Z)
     * @param int $num
     * @param int $base 預設 62
     * @return string
     */
    private function dec2any(int $num, int $base = 62): string
    {
        $index = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        if ($num === 0) {
            return '0';
        }
        $out = '';
        while ($num > 0) {
            $out = $index[$num % $base] . $out;
            $num = (int)($num / $base);
        }
        return $out;
    }
}

使用範例

<?php
require_once 'ShortUrlService.php';

// 設定 Memcached 叢集
$servers = [
    ['host' => '10.0.0.1', 'port' => 11211],
    ['host' => '10.0.0.2', 'port' => 11211],
];

$service = new ShortUrlService($servers, 'https://s.example.com/');

$urls = [
    'https://www.google.com/search?q=php+short+url',
    'https://github.com/user/repo/blob/main/src/very/long/path/file.php',
    'https://example.com/api/v1/users/12345/posts/67890/comments?sort=desc&limit=20',
];

foreach ($urls as $url) {
    $short = $service->encode($url);
    echo "Original: $url\n";
    echo "Short:    $short\n";

    $decoded = $service->decode($short);
    echo "Decoded:  $decoded\n";
    echo str_repeat('-', 60) . "\n";
}

效能與擴展考量

  • Memcached 叢集:建議部署多節點並啟用 Ketama 一致性雜湊分佈,避免單點故障與熱點 Key 問題。
  • 持久化備份:Memcached 重啟資料遺失,生產環境需搭配 MySQL/Redis 持久化備份,或直接改用 Redis(支援持久化、原子操作、更豐富資料結構)。
  • 自訂短碼:可擴充 encode() 允許使用者指定別名,需額外檢查衝突並儲存 alias → URL 映射。
  • 存活期控制:為映射 Key 設定 TTL(如 30 天),或建立定期清理任務移除長期未訪問的短連結。
  • 統計分析:在 decode() 中記錄點擊數、Referrer、User-Agent、地理位置等,推送至分析系統(Kafka/ClickHouse)。
  • 防濫用:加入頻率限制、驗證碼、域名白名單,防止惡意刷短網址。

Base62 編碼對照表

IDBase62長度
100002Bi3
100000q0U3
10000004c924
1000000006LAze5
62^4-1 (14,776,335)ZZZZ4
62^6-1 (56,800,235,583)ZZZZZZ6

6 字元 Base62 可支援 568 億組合,足以應付絕大多數中小型服務數年增長。

結語

此方案以 Memcached 高速讀寫特性、原子遞增 ID 保證唯一性、Base62 編碼縮短長度,構建出簡潔高效的短網址核心邏輯。實際部署時請務必補強持久化、監控、防濫用等生產級能力,並根據流量規模評估是否遷移至 Redis Cluster 或自建分散式 Key-Value 存儲。

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