字符集:0-9a-zA-Z (62 字符),將數字 ID 轉為短字串,反之解碼。
class ShortUrl {
private $mem;
private $baseUrl = 'https://xxx.com/';
private $charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
public function __construct() {
$this->mem = new Memcached();
$this->mem->addServer('192.168.10.90', 11116);
$this->mem->addServer('192.168.10.90', 11117);
}
// 編碼:長網址 -> 短碼
public function encode($url) {
// 過濾協議頭
$url = preg_replace('#^[https://|https://|ftp://]#iS', '', $url);
// 查快取
$key = 'url:' . md5($url);
if (($code = $this->mem->get($key)) !== false) {
return $this->baseUrl . $code;
}
// 獲取/生成自動遞增 ID
if (($id = $this->mem->increment('auto_increment_id')) === false) {
$this->mem->set('auto_increment_id', 10000);
$id = $this->mem->increment('auto_increment_id');
}
// Base62 編碼
$code = $this->dec2any($id);
// 雙向快取
$this->mem->set($key, $code);
$this->mem->set('code:' . $code, $url);
return $this->baseUrl . $code;
}
// 解碼:短碼 -> 原網址
public function decode($shortUrl) {
$code = str_replace($this->baseUrl, '', $shortUrl);
$key = 'code:' . $code;
return $this->mem->get($key) ?: 'Not Found';
}
// 10進制轉62進制
private function dec2any($num, $base = 62) {
if ($num == 0) return '0';
$result = '';
while ($num > 0) {
$result = $this->charset[$num % $base] . $result;
$num = floor($num / $base);
}
return $result;
}
// 62進制轉10進制
private function any2dec($str, $base = 62) {
$len = strlen($str);
$result = 0;
for ($i = 0; $i < $len; $i++) {
$result = $result * $base + strpos($this->charset, $str[$i]);
}
return $result;
}
}
// 測試
$su = new ShortUrl();
$urls = ['https://www.baidu.com', 'https://www.google.com', 'https://www.jbxue.com'];
foreach ($urls as $url) {
$short = $su->encode($url);
echo "Short: $short\n";
echo "Original: " . $su->decode($short) . "\n\n";
}
increment 原子操作保證唯一性