php实现简单的短链功能

124 阅读3分钟

技术栈:

  1. redis
  2. mysql
  3. laravel - 自行选择

转换方式

使用时间 + 序列号生成唯一值,然后使用10进制转62进制 我这里使用 Ymd + 序列号(0,1,2,3,4,5...)

// 获取日期 - 方便分表查询
$day = now()->format('Ymd'); // 20230919

// 获取序列号 - 使用redis - incr 原子性,防止序列号重复
$redisClient = Redis::connection()->client();
$serialNumber = $redisClient->incr('redis-key');

// 使用10进制转62进制 - 拼接十进制字符串:202309191
$shortLink = decimalToBase62($day . serialNumber);
echo $shortLink; 
// 转换结果: DgrrT

十进制转62进制

function decimalToBase62($decimal) {
    $base62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $base62_length = strlen($base62);
    $result = '';

    while ($decimal > 0) {
        $remainder = $decimal % $base62_length;
        $result .= $base62[$remainder];
        $decimal = intdiv($decimal, $base62_length);
    }

    return strrev($result);
}

二进制转62进制

public function base62ToDecimal($number) {
    $base62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $base62_length = strlen($base62);
    $number = strrev($number);
    $dec = 0;

    for ($i = 0; $i < strlen($number); $i++) {
        $digit = strpos($base62, $number[$i]);
        $dec += $digit * pow($base62_length, $i);
    }

    return $dec;
}

举例

用户使用:www.php.net/manual/zh/l… 进行转换短链,我们就可以使用上面得到的字符串进行绑定

   "DgrrT" => "https://www.php.net/manual/zh/language.basic-syntax.php"

可以根据自己业务逻辑进行分表存储,因为是按照日期获取到的随机串,我们可以很方便的进行分表操作。

用户访问我们的短链。

举个例子: www.baidu.com/DgrrT 我们要进行什么操作?

  1. 62进制转十进制,得到我们的分表表名称。
  2. 查询数据库,得到长连接。
  3. 301、302重定向

那么问题来了,所有的请求全部打到数据库,如果我们的功能是开放的,那么这样直接请求数据库肯定是灾难性的,我们可以在上面的基础上进行优化,添加各种判断

伪代码大法 - biubiubiu :1

// 1、62进制转10进制,判断日期
// 2、使用redis 布隆过滤器判断我们自己的库中是否存在这个key,不存在直接抛出异常或者其他操作
// 3、根据key获取到长连接
// 4、301、302重定向

现在这样我们把所有的数据全部存储到redis中,查询对应长连接,我们只需要查询redis就足够了、那么就有存在redis内存无限增大的问题。另外还有一些长期不使用长连接也存储到我们的redis,导致空间浪费。 继续优化: 我们可以根据我们的需求分配redis的内存大小,使用redis的内存淘汰策略(如何设置请自行百度),把不经常使用key淘汰掉即可(也就是冷数据),留下的全部都是经常使用的数据或者新增的数据(也就是热数据),热数据直接在redis中查询,冷数据因为不经常使用,直接去库中查询,查询到之后在写入到redis中

伪代码大法 - biubiubiu :2

// 1、62进制转10进制,判断日期
// 2、使用redis 布隆过滤器判断我们自己的库中是否存在这个key,不存在直接抛出异常或者其他操作
// 3、根据key获取到长连接,长连接存在,执行5
// 4、分表查询数据库
// 5、301、302重定向

这只是我自己的一点小见解,如果有其他的方案,请在评论区留言,我也去学习一下,哇咔咔