1.我们可以对原始 URL 进行哈希得到一个数字,然后将这个数字进一步转换为包含字母和数字的 8 位字符串,作为短链接中的唯一标识符。这样,即使原始 URL 非常长,我们也能够生成一个较短且易于记忆的短链接。
//简易版
class ShortLinkGenerator {
// 计算字符串的哈希值
private static function hashString($str) {
$hash = 0x811c9dc5;
for ($i = 0; $i < strlen($str); $i++) {
$hash ^= ord($str[$i]);
$hash *= 0x1000193;
$hash &= 0xffffffff;
}
return $hash;
}
// 数字转换为短链接字符串
private static function numberToShortLink($num) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
$maxIndex = strlen($characters) - 1;
for ($i = 0; $i < 8; $i++) {
$string .= $characters[$num % ($maxIndex + 1)];
$num = intval($num / ($maxIndex + 1));
}
return $string;
}
// 根据原始 URL 生成短链接
public static function generate($url) {
$hash = self::hashString($url);
$shortKey = self::numberToShortLink($hash);
return "https://example.com/{$shortKey}";
}
}
// 示例用法
$originalUrl = 'https://www.example.com/article/123';
$shortLink = ShortLinkGenerator::generate($originalUrl);
echo "原始 URL: {$originalUrl}\n";
echo "短链接: {$shortLink}\n";
在这里,我们对 generate 函数进行了修改。
- 现在生成的短链接只包含域名后的 8 位字符串。我们将计算出的哈希值传递给 numberToShortLink 函数,该函数会将哈希值转换为一个 8 位的字符串。
- 最后,我们将该字符串插入到域名后面,得到一个完整的短链接。需要注意的是,由于使用了较短的字符串作为短链接标识符,因此可能存在冲突的风险。在实际应用中,最好采取一些措施来避免重复的短链接,比如增加长度或者使用更强的哈希算法等。
- 在这里,我们对 generate 函数进行了修改。现在生成的短链接只包含域名后的 8 位字符串。我们将计算出的哈希值传递给 numberToShortLink 函数,该函数会将哈希值转换为一个 8 位的字符串。
- 最后,我们将该字符串插入到域名后面,得到一个完整的短链接。需要注意的是,由于使用了较短的字符串作为短链接标识符,因此可能存在冲突的风险。
- 在实际应用中,最好采取一些措施来避免重复的短链接,比如增加长度或者使用更强的哈希算法等。
2.对短链接添加生命周期、重复检查等功能
针对短链接的生命周期、重复检查等功能,我们可以考虑以下实现方式:
- 短链接的生命周期:短链接可以设置一个有效期,超过这个时间后就会失效。可以在数据库中添加一个字段来存储链接的创建时间,并根据需要进行查询和更新。当用户使用失效的短链接时,系统会返回一个提示页面,告知用户该链接已经过期。
- 短链接的重复检查:为了避免生成重复的短链接,可以在数据库中添加一个唯一索引,用于存储短链接的标识符。在生成新的短链接时,先查询数据库是否已经存在相同的标识符,如果存在,则重新生成。可以在生成短链接的 generate 函数中添加一个循环,不断尝试新的标识符,直到找到一个未被占用的标识符为止。如果重复检查的逻辑比较复杂,也可以专门编写一个函数来完成检查。
- 数据库设计:为了存储短链接的信息,我们需要设计一个数据库表。可以考虑包含以下字段:
id: 主键,自增长。
original_url: 原始链接。
short_key: 短链接的标识符。
create_time: 链接的创建时间。
expire_time: 链接的过期时间。- 这些字段可以根据具体业务需求进行调整。为了提高查询效率,可以在 short_key 字段上添加一个唯一索引。 这些字段可以根据具体业务需求进行调整。为了提高查询效率,可以在 short_key 字段上添加一个唯一索引。
class ShortLinkGenerator { // 计算字符串的哈希值 private static function hashString($str) { $hash = 0x811c9dc5; for ($i = 0; $i < strlen($str); $i++) { $hash ^= ord($str[$i]); $hash *= 0x1000193; $hash &= 0xffffffff; } return $hash; }
// 数字转换为短链接字符串
private static function numberToShortLink($num) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
$maxIndex = strlen($characters) - 1;
for ($i = 0; $i < 8; $i++) {
$string .= $characters[$num % ($maxIndex + 1)];
$num = intval($num / ($maxIndex + 1));
}
return $string;
}
// 生成唯一的短链接标识符
private static function generateUniqueShortKey($db) {
$isUnique = false;
while (!$isUnique) {
// 生成新的标识符
$hash = mt_rand();
$shortKey = self::numberToShortLink($hash);
// 检查是否已经存在相同的标识符
$stmt = $db->prepare('SELECT COUNT(*) FROM short_links WHERE short_key = ?');
$stmt->bindParam(1, $shortKey);
$stmt->execute();
$count = $stmt->fetchColumn();
if ($count == 0) {
$isUnique = true;
}
}
return $shortKey;
}
// 根据原始 URL 生成短链接
public static function generate($db, $url) {
// 生成唯一的短链接标识符
$shortKey = self::generateUniqueShortKey($db);
// 添加短链接到数据库
$stmt = $db->prepare('INSERT INTO short_links (original_url, short_key, create_time, expire_time) VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 DAY))');
$stmt->bindParam(1, $url);
$stmt->bindParam(2, $shortKey);
$stmt->execute();
// 返回完整的短链接
return "https://example.com/{$shortKey}";
}
// 根据短链接查询原始 URL
public static function getOriginalUrl($db, $shortKey) {
$stmt = $db->prepare('SELECT original_url FROM short_links WHERE short_key = ? AND expire_time > NOW()');
$stmt->bindParam(1, $shortKey);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
return $row['original_url'];
} else {
return null;
}
}
}
// 示例用法
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
// 生成新的短链接
$originalUrl = 'https://www.example.com/article/123';
$shortLink = ShortLinkGenerator::generate($db, $originalUrl);
echo "原始 URL: {$originalUrl}\n";
echo "短链接: {$shortLink}\n";
// 根据短链接查找原始 URL
$shortKey = substr($shortLink, strlen('https://example.com/'));
$originalUrl = ShortLinkGenerator::getOriginalUrl($db, $shortKey);
if ($originalUrl) {
echo "原始 URL: {$originalUrl}\n";
} else {
echo "短链接无效\n";
}
>在这里,我们添加了一个名为 short_links 的表来存储短链接的信息。在生成新的短链接时,先调用 generateUniqueShortKey 函数生成一个唯一的标识符,然后将其和原始 URL 一起添加到数据库中。在查询原始 URL 时,需要检查短链接是否已经过期,如果已经过期则返回空。以上仅作为示例,实际应用中还需要考虑一些其他因素,比如并发访问、安全性、错误处理等。
****3.对以上代码添加并发访问、安全性、错误处理
> 以下是对之前代码进行并发访问、安全性、错误处理等方面的改进:
>- 并发访问处理:为了避免并发访问导致的数据库写入冲突,可以添加一个写锁来保护 short_links 表。在添加新的短链接时获取锁,释放锁后才能进行下一个添加操作。可以使用 MySQL 的 GET_LOCK() 和 RELEASE_LOCK() 函数实现锁机制。
>- 安全性处理:需要对原始 URL 进行校验,防止恶意用户利用生成的短链接访问危险网站或执行跨站脚本攻击。可以使用 PHP 的 filter_var() 函数来检验 URL 是否合法、是否为 HTTP 或 HTTPS 协议,以及是否包含非法字符等。
>- 错误处理:需要在代码中添加错误处理机制,确保程序在出现异常情况时能够正常运行并给出有意义的错误提示。可以使用 PHP 的 try...catch 语句来捕获和处理异常。
```php
class ShortLinkGenerator {
// 计算字符串的哈希值
private static function hashString($str) {
$hash = 0x811c9dc5;
for ($i = 0; $i < strlen($str); $i++) {
$hash ^= ord($str[$i]);
$hash *= 0x1000193;
$hash &= 0xffffffff;
}
return $hash;
}
// 数字转换为短链接字符串
private static function numberToShortLink($num) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
$maxIndex = strlen($characters) - 1;
for ($i = 0; $i < 8; $i++) {
$string .= $characters[$num % ($maxIndex + 1)];
$num = intval($num / ($maxIndex + 1));
}
return $string;
}
// 获取短链接锁
private static function getShortLinkLock($db) {
$stmt = $db->prepare('SELECT GET_LOCK("short_link_lock", 10)');
$stmt->execute();
$isLocked = $stmt->fetchColumn();
if (!$isLocked) {
throw new Exception("获取短链接锁失败");
}
}
// 释放短链接锁
private static function releaseShortLinkLock($db) {
$stmt = $db->prepare('SELECT RELEASE_LOCK("short_link_lock")');
$stmt->execute();
}
// 生成唯一的短链接标识符
private static function generateUniqueShortKey($db) {
$isUnique = false;
while (!$isUnique) {
// 生成新的标识符
$hash = mt_rand();
$shortKey = self::numberToShortLink($hash);
// 检查是否已经存在相同的标识符
$stmt = $db->prepare('SELECT COUNT(*) FROM short_links WHERE short_key = ?');
$stmt->bindParam(1, $shortKey);
$stmt->execute();
$count = $stmt->fetchColumn();
if ($count == 0) {
$isUnique = true;
}
}
return $shortKey;
}
// 根据原始 URL 生成短链接
public static function generate($db, $url) {
try {
// 检查 URL 是否合法
$url = filter_var($url, FILTER_SANITIZE_URL);
if (!$url || !preg_match('/^https?:\/\//', $url)) {
throw new Exception("非法的 URL");
}
// 获取短链接锁
self::getShortLinkLock($db);
// 生成唯一的短链接标识符
$shortKey = self::generateUniqueShortKey($db);
// 添加短链接到数据库
$stmt = $db->prepare('INSERT INTO short_links (original_url, short_key, create_time, expire_time) VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 DAY))');
$stmt->bindParam(1, $url);
$stmt->bindParam(2, $shortKey);
$stmt->execute();
// 释放短链接锁
self::releaseShortLinkLock($db);
// 返回完整的短链接
return "https://example.com/{$shortKey}";
} catch (Exception $e) {
// 处理异常情况
self::releaseShortLinkLock($db);
throw new Exception($e->getMessage());
}
}
// 根据短链接查询原始 URL
public static function getOriginalUrl($db, $shortKey) {
try {
// 检查短链接是否合法
if (!preg_match('/^[0-9a-zA-Z]{8}$/', $shortKey)) {
throw new Exception("非法的短链接");
}
$stmt = $db->prepare('SELECT original_url FROM short_links WHERE short_key = ? AND expire_time > NOW()');
$stmt->bindParam(1, $shortKey);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
return $row['original_url'];
} else {
throw new Exception("短链接无效");
}
} catch (Exception $e) {
// 处理异常情况
throw new Exception($e->getMessage());
}
}
}
// 示例用法
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
// 生成新的短链接
$originalUrl = 'https://www.example.com/article/123';
try {
$shortLink = ShortLinkGenerator::generate($db, $originalUrl);
echo "原始 URL: {$originalUrl}\n";
echo "短链接: {$shortLink}\n";
} catch (Exception $e) {
echo "生成短链接失败: {$e->getMessage()}\n";
}
// 根据短链接查找原始 URL
$shortKey = substr($shortLink, strlen('https://example.com/'));
try {
$originalUrl = ShortLinkGenerator::getOriginalUrl($db, $shortKey);
echo "原始 URL: {$originalUrl}\n";
} catch (Exception $e) {
echo "获取原始 URL 失败: {$e->getMessage()}\n";
}
在这里,我们添加了获取和释放锁的方法,并在 generate 函数中调用。在异常情况下,需要使用 try...catch 语句来正确处理异常并释放锁。同时,我们也对输入的 URL 和短链接进行了校验,在非法情况下抛出异常
发表评论: