PHP生成短链接思路是啥

wen PHP项目 2

本文目录导读:

PHP生成短链接思路是啥

  1. 核心流程(一次完整请求)
  2. 短码生成算法(重点)
  3. 数据库设计
  4. PHP 完整实现
  5. 性能优化要点(进阶)
  6. 生产环境注意事项
  7. 完整项目结构建议

生成短链接的核心思路就是建立“短码”和“长链接”的映射关系,并进行重定向,下面从流程、算法、数据库设计和代码实现四个层面拆解。


核心流程(一次完整请求)

用户访问短链 http://a.cn/xYz9k
        ↓
PHP 解析 URL,取出短码 "xYz9k"
        ↓
查数据库/缓存:SELECT long_url FROM short_urls WHERE short_code = 'xYz9k'
        ↓
找到后,返回 301/302 重定向到长链接
        ↓
浏览器跳转到目标网站

短码生成算法(重点)

短码一般由 62个字符0-9a-zA-Z)组成,长度通常 6~8 位。

随机字符串(简单但需防冲突)

function generateShortCode($length = 6) {
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $code = '';
    for ($i = 0; $i < $length; $i++) {
        $code .= $chars[random_int(0, 61)];
    }
    return $code;
}

缺点:需要查重,并发高时可能冲突。


自增ID + 进制转换(推荐,无冲突)

  1. 数据库插入一条记录,获得自增ID(10001)
  2. 将这个ID转换为62进制字符串,作为短码
function idToShortCode($id) {
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $code = '';
    while ($id > 0) {
        $code = $chars[$id % 62] . $code;
        $id = intdiv($id, 62);
    }
    return str_pad($code, 6, '0', STR_PAD_LEFT); // 补位,保证长度
}

优点:绝对不冲突,还可以反向解码(由短码推出ID,便于统计)。


MD5/SHA1 截取(适合无需存储的短码)

$code = substr(md5($longUrl . time() . rand()), 0, 6);

缺点:碰撞概率高(6位62进制 = 568亿组合),需查重,且无法反向解码做统计。


数据库设计

CREATE TABLE short_urls (
    id         BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    short_code VARCHAR(10) NOT NULL UNIQUE,
    long_url   TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    visit_count INT DEFAULT 0,
    INDEX idx_code (short_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

PHP 完整实现

生成接口(接收长链接,返回短链接)

// generate.php
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$longUrl = $_POST['url'] ?? '';
if (!filter_var($longUrl, FILTER_VALIDATE_URL)) {
    die('Invalid URL');
}
// 首先检查是否已存在
$stmt = $pdo->prepare("SELECT short_code FROM short_urls WHERE long_url = ?");
$stmt->execute([$longUrl]);
$exists = $stmt->fetchColumn();
if ($exists) {
    echo "http://a.cn/{$exists}";
    exit;
}
// 插入获取自增ID
$pdo->prepare("INSERT INTO short_urls (long_url) VALUES (?)")->execute([$longUrl]);
$id = $pdo->lastInsertId();
// ID转短码
$code = idToShortCode($id);
$pdo->prepare("UPDATE short_urls SET short_code = ? WHERE id = ?")->execute([$code, $id]);
echo "http://a.cn/{$code}";

访问重定向入口

// index.php  (配合 .htaccess 将所有短链请求转发到这里)
<?php
$requestUri = $_SERVER['REQUEST_URI'];
$shortCode = ltrim($requestUri, '/');   // 取出短码
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare("SELECT long_url FROM short_urls WHERE short_code = ?");
$stmt->execute([$shortCode]);
$longUrl = $stmt->fetchColumn();
if ($longUrl) {
    // 302 临时重定向(方便后期修改长链接);301 永久重定向有SEO优势
    header("Location: " . $longUrl, true, 302);
    exit;
} else {
    http_response_code(404);
    echo "链接不存在";
}

性能优化要点(进阶)

使用 Redis 缓存热点短码

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$longUrl = $redis->get("short:{$shortCode}");
if (!$longUrl) {
    // 查数据库
    $longUrl = queryDB($shortCode);
    // 写入缓存,设置过期时间
    $redis->setex("short:{$shortCode}", 86400, $longUrl);
}
header("Location: " . $longUrl);

使用异步/队列写入数据

高并发场景下,可以先写Redis再异步同步到MySQL。

防恶意刷接口

限制同一IP每天生成次数,或使用验证码。


生产环境注意事项

事项 说明
短码长度 建议 6~8 位,越短越利于复制,但碰撞率越高
重定向状态码 302 便于后期修改;如果确定永久不改用 301
自定义短码 增加允许用户自定义(需检查唯一)
过期时间 非永久短链需加 expire_at 字段
安全过滤 防止 javascript: 等危险协议,需校验 http/https

完整项目结构建议

/your-project/
├── index.php          # 重定向入口
├── generate.php       # 短链生成接口
├── .htaccess          # 伪静态规则
├── config.php         # 数据库配置
└── lib/
    └── shortener.php  # 核心类(生成+解析)

就是PHP生成短链接的完整思路,核心是ID→62进制编码保证无冲突,配合Redis缓存 + 数据库持久化即可支撑高并发场景。

抱歉,评论功能暂时关闭!