短網址服務是將冗長 URL 轉換為短碼(如 https://short.ly/abc123)的經典應用。本文提供一個生產級可用的 PHP 類別,採用 Memcached 做高速儲存、Base62 編碼 產生短碼、自增 ID 保證唯一性,並支援編碼/解碼雙向操作,適合高併發場景。
increment() 原子操作產生唯一遞增數字 ID(初始值 10000 避免過短)。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";
}
encode() 允許使用者指定別名,需額外檢查衝突並儲存 alias → URL 映射。decode() 中記錄點擊數、Referrer、User-Agent、地理位置等,推送至分析系統(Kafka/ClickHouse)。| ID | Base62 | 長度 |
|---|---|---|
| 10000 | 2Bi | 3 |
| 100000 | q0U | 3 |
| 1000000 | 4c92 | 4 |
| 100000000 | 6LAze | 5 |
| 62^4-1 (14,776,335) | ZZZZ | 4 |
| 62^6-1 (56,800,235,583) | ZZZZZZ | 6 |
6 字元 Base62 可支援 568 億組合,足以應付絕大多數中小型服務數年增長。
此方案以 Memcached 高速讀寫特性、原子遞增 ID 保證唯一性、Base62 編碼縮短長度,構建出簡潔高效的短網址核心邏輯。實際部署時請務必補強持久化、監控、防濫用等生產級能力,並根據流量規模評估是否遷移至 Redis Cluster 或自建分散式 Key-Value 存儲。