轻量级 PHP 短链接系统源码|单文件可部署、SQLite 存储、带管理后台(原创教学)

短链接系统源码封面

前言

很多站长需要把长网址缩短后分享,市面方案要么依赖第三方,要么功能臃肿。今天分享一套原创、开源教学用途的轻量级 PHP 短链接系统源码:单文件可运行,SQLite 存储,自带管理后台与访问统计,适合学习二次开发,也可直接用于自用小站。

声明:本文源码为原创教学示例,请勿用于违法违规用途;部署请遵守当地法律法规与目标服务条款。

功能特性

  • 短链生成、301/302 跳转可选
  • 自定义短码(4–8 位字母数字)
  • 点击量统计
  • SQLite 存储,无需 MySQL,部署简单
  • 基础管理列表(需登录,密码写在配置里)
  • 响应式单页 UI,深色模式友好

环境要求

  • PHP 8.0+(需启用 pdo_sqlite)
  • 任意可运行 PHP 的主机 / 宝塔 / Nginx+php-fpm

目录结构

short-url/
├── index.php      # 前台:生成与跳转
├── admin.php      # 简易管理
├── config.php     # 配置(站点名、管理员密码哈希)
└── data/          # SQLite 数据目录(需可写)
    └── links.db

完整源码

config.php

<?php
// 基础配置
return [
    'site_name' => '轻短链',
    'base_url'  => 'http://your-domain.com', // 不以 / 结尾
    'admin_user' => 'admin',
    // 密码哈希请用命令生成后粘贴:
    // php -r "echo password_hash('你的新密码', PASSWORD_DEFAULT);"
    'admin_pass_hash' => '$2y$10$REPLACE_ME_WITH_password_hash_OUTPUT',
    'default_redirect' => 302, // 301 或 302
    'code_min' => 4,
    'code_max' => 8,
];

index.php

<?php
$config = require __DIR__ . '/config.php';
$db = new PDO('sqlite:' . __DIR__ . '/data/links.db');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec("CREATE TABLE IF NOT EXISTS links (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  code TEXT UNIQUE NOT NULL,
  url TEXT NOT NULL,
  hits INTEGER DEFAULT 0,
  created_at TEXT DEFAULT CURRENT_TIMESTAMP
)");

// 跳转
if (isset($_GET['go'])) {
    $code = preg_replace('/[^a-zA-Z0-9]/', '', $_GET['go']);
    $st = $db->prepare('SELECT url, hits FROM links WHERE code = ?');
    $st->execute([$code]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) { http_response_code(404); exit('短链不存在'); }
    $db->prepare('UPDATE links SET hits = hits + 1 WHERE code = ?')->execute([$code]);
    $code_status = $config['default_redirect'] == 301 ? 301 : 302;
    header('Location: ' . $row['url'], true, $code_status);
    exit;
}

// 生成
$err = $ok = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $url = trim($_POST['url'] ?? '');
    $custom = trim($_POST['code'] ?? '');
    if (!filter_var($url, FILTER_VALIDATE_URL)) {
        $err = '请输入合法的 http(s) 链接';
    } else {
        if ($custom !== '') {
            if (!preg_match('/^[a-zA-Z0-9]{' . $config['code_min'] . ',' . $config['code_max'] . '}$/', $custom)) {
                $err = '自定义短码需为 ' . $config['code_min'] . '-' . $config['code_max'] . ' 位字母数字';
            } else {
                $code = $custom;
            }
        } else {
            $code = substr(bin2hex(random_bytes(6)), 0, 6);
        }
        if ($err === '') {
            try {
                $db->prepare('INSERT INTO links (code, url) VALUES (?, ?)')->execute([$code, $url]);
                $ok = $config['base_url'] . '/index.php?go=' . $code;
            } catch (PDOException $e) {
                $err = '短码已存在,请换一个';
            }
        }
    }
}
?>
<!doctype html><html lang="zh-CN"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title><?= htmlspecialchars($config['site_name']) ?></title>
<style>
body{font-family:system-ui,sans-serif;background:#0f1115;color:#e8eaed;display:flex;min-height:100vh;align-items:center;justify-content:center;margin:0}
.card{background:#1a1d24;padding:2rem;border-radius:16px;width:min(520px,92vw);box-shadow:0 10px 40px rgba(0,0,0,.35)}
h1{margin:0 0 1rem;font-size:1.4rem}
input,button{width:100%;box-sizing:border-box;padding:.75rem 1rem;border-radius:10px;border:1px solid #2a2f3a;background:#12151c;color:#e8eaed;font-size:1rem;margin:.35rem 0}
button{background:#f04494;border:0;cursor:pointer;font-weight:600}
.ok{background:#123d2a;color:#7dffa3;padding:.75rem 1rem;border-radius:10px;word-break:break-all}
.err{background:#3d1218;color:#ff8f9c;padding:.75rem 1rem;border-radius:10px}
.muted{opacity:.65;font-size:.85rem;margin-top:1rem}
</style></head><body>
<div class="card">
  <h1><?= htmlspecialchars($config['site_name']) ?></h1>
  <?php if ($ok): ?><div class="ok"><?= htmlspecialchars($ok) ?></div><?php endif; ?>
  <?php if ($err): ?><div class="err"><?= htmlspecialchars($err) ?></div><?php endif; ?>
  <form method="post">
    <input name="url" placeholder="粘贴长链接,https://..." required>
    <input name="code" placeholder="自定义短码(可选)">
    <button type="submit">生成短链</button>
  </form>
  <div class="muted">管理入口:<a href="admin.php" style="color:#f04494">admin.php</a></div>
</div></body></html>

admin.php

<?php
session_start();
$config = require __DIR__ . '/config.php';
$db = new PDO('sqlite:' . __DIR__ . '/data/links.db');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

if (isset($_GET['logout'])) { session_destroy(); header('Location: admin.php'); exit; }

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
    if (($_POST['user'] ?? '') === $config['admin_user']
        && password_verify($_POST['pass'] ?? '', $config['admin_pass_hash'])) {
        $_SESSION['admin'] = 1;
    } else {
        $login_err = '账号或密码错误';
    }
}

if (empty($_SESSION['admin'])) {
    ?><!doctype html><meta charset="utf-8"><title>登录</title>
    <form method="post" style="max-width:320px;margin:10vh auto;font-family:system-ui">
      <h2>短链管理登录</h2>
      <?php if (!empty($login_err)) echo '<p style="color:#c00">' . htmlspecialchars($login_err) . '</p>'; ?>
      <input name="user" placeholder="用户名" style="width:100%;padding:10px;margin:6px 0">
      <input name="pass" type="password" placeholder="密码" style="width:100%;padding:10px;margin:6px 0">
      <input type="hidden" name="login" value="1">
      <button style="padding:10px 16px">登录</button>
    </form><?php
    exit;
}

// 删除
if (isset($_GET['del'])) {
    $db->prepare('DELETE FROM links WHERE id = ?')->execute([intval($_GET['del'])]);
    header('Location: admin.php'); exit;
}

$rows = $db->query('SELECT * FROM links ORDER BY id DESC LIMIT 200')->fetchAll(PDO::FETCH_ASSOC);
?><!doctype html><meta charset="utf-8"><title>短链管理</title>
<div style="max-width:900px;margin:2rem auto;font-family:system-ui">
  <h2>短链列表 <a href="admin.php?logout=1" style="font-size:.9rem">退出</a></h2>
  <table border="1" cellpadding="8" cellspacing="0" width="100%">
    <tr><th>ID</th><th>短码</th><th>目标 URL</th><th>点击</th><th>操作</th></tr>
    <?php foreach ($rows as $r): ?>
    <tr>
      <td><?= (int)$r['id'] ?></td>
      <td><?= htmlspecialchars($r['code']) ?></td>
      <td><?= htmlspecialchars(mb_strimwidth($r['url'], 0, 60, '…')) ?></td>
      <td><?= (int)$r['hits'] ?></td>
      <td><a href="admin.php?del=<?= (int)$r['id'] ?>" onclick="return confirm('删除?')">删除</a></td>
    </tr>
    <?php endforeach; ?>
  </table>
</div>

? 源码下载

下载 short-url.zip(解压即用)

下载解压后按文中步骤部署即可。若正文代码与压缩包不一致,以压缩包为准。

部署步骤

  1. 新建站点(Nginx/Apache 均可),上传 index.php、admin.php、config.php,创建 data/ 目录并给 PHP 用户写权限。
  2. 修改 config.php:站点名、base_url、管理员密码哈希。
  3. 访问首页生成短链;访问 index.php?go=短码 跳转。
  4. 建议配置伪静态将 /s/短码 转到 index.php?go=短码。

安全与合规说明

  • 请修改默认管理员密码,不要把 data/ 目录暴露为公开下载。
  • 禁止用短链传播钓鱼、木马、侵权内容;站长应对跳转目标负责。
  • 本源码仅供学习交流,使用后果自负。

小结

这套短链系统代码量小、依赖少,适合二次开发:可扩展限流、黑名单域名、API 生成等。若你需要API 版 + 防滥用的增强版源码,可以在评论区留言,后续我会继续更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容