本文目录导读:

在PHP中生成短地址(短链接)有多种算法,我来介绍几种常用的方案:
基于MD5的短地址算法(最常用)
<?php
class ShortUrlGenerator {
/**
* 生成短地址
* @param string $url 原始URL
* @param int $length 短地址长度
* @return array 返回多个短地址
*/
public static function generate($url, $length = 8) {
// 创建MD5哈希
$md5 = md5($url);
$shortUrls = [];
// 通常生成4个短地址供选择
for ($i = 0; $i < 4; $i++) {
// 从MD5中取一段,每8个字符一组
$segment = substr($md5, $i * 8, 8);
// 将16进制转为10进制
$hexdec = hexdec($segment);
// 使用62进制编码
$shortUrl = self::base62Encode($hexdec);
// 截取指定长度
$shortUrls[] = substr($shortUrl, 0, $length);
}
return $shortUrls;
}
/**
* 10进制转62进制
*/
private static function base62Encode($num) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$result = '';
while ($num > 0) {
$result = $chars[$num % 62] . $result;
$num = floor($num / 62);
}
return $result;
}
}
// 使用示例
$url = 'https://www.example.com/article/123456?ref=homepage';
$shortUrls = ShortUrlGenerator::generate($url);
print_r($shortUrls);
// 输出类似:Array ( [0] => b60e7qKb [1] => 0Qf9HqF6 [2] => 3MaF7sT8 [3] => 9vN4cDmX )
?>
自增ID + 字母数字编码算法
<?php
class ShortUrlService {
private $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
private $base = 62;
/**
* 将数字ID转换为短码
* @param int $id 自增ID
* @return string 短码
*/
public function encode($id) {
$shortUrl = '';
while ($id > 0) {
$shortUrl = $this->alphabet[$id % $this->base] . $shortUrl;
$id = floor($id / $this->base);
}
// 如果结果为空,返回第一个字符
if (empty($shortUrl)) {
$shortUrl = $this->alphabet[0];
}
return $shortUrl;
}
/**
* 将短码解码为数字ID
* @param string $code 短码
* @return int 原始ID
*/
public function decode($code) {
$id = 0;
$len = strlen($code);
for ($i = 0; $i < $len; $i++) {
$id = $id * $this->base + strpos($this->alphabet, $code[$i]);
}
return $id;
}
}
// 使用示例
$service = new ShortUrlService();
// 假设数据库中URL的自增ID
$id = 1000000;
$shortCode = $service->encode($id);
echo "短码: " . $shortCode . "\n"; // 输出类似: 4c92
// 解码验证
$decodedId = $service->decode($shortCode);
echo "解码后的ID: " . $decodedId . "\n";
?>
基于随机数的短地址算法
<?php
class RandomShortUrl {
private $length = 8;
/**
* 生成随机短码
* @param int $length
* @return string
*/
public function generateRandom($length = null) {
$length = $length ?: $this->length;
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
// 使用密码学安全的随机数生成器
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[random_int(0, $charactersLength - 1)];
}
return $randomString;
}
/**
* 检查短码是否已存在(需实现已使用短码的存储)
*/
public function generateUnique() {
do {
$code = $this->generateRandom();
// 这里需要检查数据库中是否已存在该短码
// $exists = $this->checkExistsInDB($code);
$exists = false; // 假设不存在
} while ($exists);
return $code;
}
}
// 使用示例
$generator = new RandomShortUrl();
$shortCode = $generator->generateRandom(6);
echo "随机短码: " . $shortCode . "\n";
?>
完整示例:包含数据库操作的短链接系统
<?php
class ShortLinkSystem {
private $db;
private $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
private $base = 62;
public function __construct($host, $user, $pass, $dbname) {
// 数据库连接示例(使用PDO)
$this->db = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/**
* 创建短链接
*/
public function createShortLink($originalUrl) {
// 1. 将URL插入数据库,获取自增ID
$stmt = $this->db->prepare("INSERT INTO urls (original_url, created_at) VALUES (?, NOW())");
$stmt->execute([$originalUrl]);
$id = $this->db->lastInsertId();
// 2. 生成短码
$shortCode = $this->encode($id);
// 3. 更新记录的短码
$stmt = $this->db->prepare("UPDATE urls SET short_code = ? WHERE id = ?");
$stmt->execute([$shortCode, $id]);
return $shortCode;
}
/**
* 解析短链接
*/
public function getOriginalUrl($shortCode) {
$stmt = $this->db->prepare("SELECT original_url FROM urls WHERE short_code = ?");
$stmt->execute([$shortCode]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
// 更新访问次数
$this->updateClickCount($shortCode);
return $result['original_url'];
}
return null;
}
/**
* 更新点击次数
*/
private function updateClickCount($shortCode) {
$stmt = $this->db->prepare("UPDATE urls SET clicks = clicks + 1 WHERE short_code = ?");
$stmt->execute([$shortCode]);
}
/**
* ID转短码
*/
private function encode($id) {
$shortCode = '';
while ($id > 0) {
$shortCode = $this->alphabet[$id % $this->base] . $shortCode;
$id = floor($id / $this->base);
}
return $shortCode;
}
/**
* 短码转ID
*/
private function decode($code) {
$id = 0;
$len = strlen($code);
for ($i = 0; $i < $len; $i++) {
$id = $id * $this->base + strpos($this->alphabet, $code[$i]);
}
return $id;
}
}
// 使用示例
// $system = new ShortLinkSystem('localhost', 'root', '', 'short_url');
// $shortCode = $system->createShortLink('https://www.example.com/very/long/url');
// $originalUrl = $system->getOriginalUrl($shortCode);
?>
使用现成库:Guzzle + RandomLib
<?php
// 使用 Composer 安装库
// composer require paragonie/random_compat
// 组合使用多种算法生成短码
function generateShortUrl($url, $length = 6) {
// 方法1:MD5 + base62
$md5 = md5($url . time() . rand(10000, 99999));
$hexdec = hexdec(substr($md5, 0, 8));
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$short = '';
while ($hexdec > 0) {
$short = $chars[$hexdec % 62] . $short;
$hexdec = floor($hexdec / 62);
}
// 截取指定长度
return substr($short, 0, $length);
}
?>
注意事项
- 冲突处理:确保生成的短码在数据库中唯一,需要检查重复
- 安全考虑:使用
random_int()而不是rand()生成随机数 - 性能优化:对热点短码进行缓存(Redis/Memcached)
- 数据库索引:短码字段应该建立唯一索引
- URL验证:生成前验证原始URL的格式
- 自定义短码:允许用户自定义短码,但需检查可用性
选择哪种算法取决于你的具体需求:
- 自增ID算法:短码长度固定,可预测,适合内部系统
- 随机算法:不可预测,安全性更高,适合公开服务
- MD5算法:基于原始URL生成,可重复生成相同短码