建立「短代碼 ⟺ 原網址」映射關係,用戶訪問短網址 → 伺服器查找映射 → 301/302 重導向至原網址。
<?php
function code62($x) {
$show = '';
while ($x > 0) {
$s = $x % 62;
if ($s > 35) $s = chr($s + 61); // a-z
elseif ($s > 9) $s = chr($s + 55); // A-Z
else $s = chr($s + 48); // 0-9
$show .= $s;
$x = floor($x / 62);
}
return strrev($show); // 低位在前需反轉
}
function shorturl($url) {
$crc = crc32($url); // 32 位雜湊
$unsigned = sprintf("%u", $crc); // 無號整數
return code62($unsigned); // 6 位短碼
}
echo shorturl('https://www.jb51.net/'); // 輸出類似: 1EeIv2
?>
CREATE TABLE `short_url` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`code` VARCHAR(10) NOT NULL UNIQUE, -- 短代碼
`url` TEXT NOT NULL, -- 原網址
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`hits` INT UNSIGNED DEFAULT 0, -- 訪問計數
INDEX `idx_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
<?php
include_once('db.php');
$code = $_GET['url'] ?? '';
if ($code) {
$stmt = $pdo->prepare("SELECT url FROM short_url WHERE code = ?");
$stmt->execute([$code]);
if ($row = $stmt->fetch()) {
header('Location: ' . $row['url'], true, 301);
$pdo->exec("UPDATE short_url SET hits = hits + 1 WHERE code = '$code'");
exit;
}
}
header('HTTP/1.0 404 Not Found');
echo 'Unknown link.';
?>
# Apache .htaccess
RewriteEngine On
RewriteRule ^([a-zA-Z0-9]+)$ /link.php?url=$1 [L]
# Nginx
location / {
rewrite ^/([a-zA-Z0-9]+)$ /link.php?url=$1 last;
}
baidu = https://www.baidu.com/ qq = https://www.qq.com/ hw = https://www.hw.com/ dm = https://www.dm.com/view-blog-362.html
<?php
$links = parse_ini_file('links.ini');
$key = $_GET['l'] ?? '';
if ($key && isset($links[$key])) {
header('Location: ' . $links[$key], true, 301);
exit;
}
header('HTTP/1.0 404 Not Found');
echo 'Unknown link.';
?>
# Apache RewriteRule ^([a-z]+)$ /index.php?l=$1 [L] # Nginx rewrite ^/([a-z]+)$ /index.php?l=$1 last;
<?php
function shorturl($input) {
$base32 = array_merge(range('a','z'), range('0','5')); // 32 字元
$hex = md5($input); // 32 字元十六進位
$output = [];
for ($i = 0; $i < 4; $i++) { // 產生 4 組 6 字元短碼
$subHex = substr($hex, $i * 8, 8); // 取 8 字元 (32 bits)
$int = 0x3FFFFFFF & hexdec($subHex); // 與 30 位 1 進行 AND
$out = '';
for ($j = 0; $j < 6; $j++) {
$val = 0x1F & $int; // 取低 5 位 (0-31)
$out .= $base32[$val];
$int >>= 5;
}
$output[] = $out;
}
return $output; // 陣列含 4 個備選短碼
}
print_r(shorturl('https://www.jb51.net/'));
/* 輸出範例:
Array (
[0] => a3z8f2
[1] => k9m1p4
[2] => q7w5e8
[3] => r6t2y9
)
*/
?>
| 維度 | MySQL | INI 配置 | Base32 演算法 |
|---|---|---|---|
| 儲存方式 | 資料庫表 | 檔案配置 | 純演算法 (無儲存) |
| 動態新增 | ✅ 支援 | ✅ 需重寫檔案 | ❌ 不可控 (單向) |
| 查詢效能 | 索引 O(1) | 記憶體 O(1) | 運算 O(1) |
| 適用場景 | 大量動態短網址 | 少量固定映射 | 短網址服務核心生成 |
| 維護成本 | 中 (備份/監控) | 低 | 極低 |
| 衝突處理 | 唯一索引重試 | 手動避免 | 多組備選碼 |