转:短网址源码分享

见山 (UID:1) 站长 2025-11-3 167

代码

<?php
/**
 * 短网址生成器
 */

class ShortUrlDB {
    private $db;

    public function __construct($dbPath = 'shorturl.db') {
        $this->db = new PDO('sqlite:' . $dbPath);
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->initDatabase();
    }

    private function initDatabase() {
        $this->db->exec("CREATE TABLE IF NOT EXISTS short_urls (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            long_url TEXT NOT NULL,
            short_code VARCHAR(10) UNIQUE NOT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            clicks INTEGER DEFAULT 0
        )");
        $this->db->exec("CREATE INDEX IF NOT EXISTS idx_short_code ON short_urls(short_code)");
    }

    public function getDB() {
        return $this->db;
    }
}

class ShortUrlGenerator {
    private $db;
    private const CHARS = "0123456789abcdefghijklmnopqrstuvwxyz";

    public function __construct($db) {
        $this->db = $db;
    }

    public function generateShortCode($url) {
        $hash = crc32($url . microtime());
        $num = sprintf("%u", $hash);

        $code = '';
        while ($num > 0) {
            $code = self::CHARS[$num % 36] . $code;
            $num = intval($num / 36);
        }

        return str_pad(substr($code, 0, 6), 6, '0', STR_PAD_LEFT);
    }

    public function saveShortUrl($longUrl, $customCode = '') {
        // 规范化URL
        if (!preg_match("~^(?:f|ht)tps?://~i", $longUrl)) {
            $longUrl = "http://" . $longUrl;
        }

        // 检查是否已存在
        $stmt = $this->db->prepare("SELECT short_code FROM short_urls WHERE long_url = ?");
        $stmt->execute([$longUrl]);
        if ($result = $stmt->fetch()) {
            return $result['short_code'];
        }

        // 生成或验证短码
        if ($customCode) {
            if (!preg_match('/^[a-zA-Z0-9]{1,10}$/', $customCode)) {
                throw new Exception("短码格式错误");
            }
            if ($this->shortCodeExists($customCode)) {
                throw new Exception("短码已存在");
            }
            $shortCode = $customCode;
        } else {
            $shortCode = $this->generateShortCode($longUrl);
            $attempts = 0;
            while ($this->shortCodeExists($shortCode) && $attempts < 3) {
                $shortCode = $this->generateShortCode($longUrl . $attempts);
                $attempts++;
            }
        }

        // 插入数据
        $stmt = $this->db->prepare("INSERT INTO short_urls (long_url, short_code) VALUES (?, ?)");
        $stmt->execute([$longUrl, $shortCode]);

        return $shortCode;
    }

    public function shortCodeExists($shortCode) {
        $stmt = $this->db->prepare("SELECT 1 FROM short_urls WHERE short_code = ? LIMIT 1");
        $stmt->execute([$shortCode]);
        return (bool)$stmt->fetch();
    }

    public function getLongUrl($shortCode) {
        $stmt = $this->db->prepare("SELECT long_url FROM short_urls WHERE short_code = ?");
        $stmt->execute([$shortCode]);

        if ($result = $stmt->fetch()) {
            // 更新点击计数
            $this->db->prepare("UPDATE short_urls SET clicks = clicks + 1 WHERE short_code = ?")
                     ->execute([$shortCode]);
            return $result['long_url'];
        }

        return false;
    }
}

/**
 * 获取基础URL
 */
function getBaseUrl() {
    $is_https = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off');

    if (!$is_https && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
        $protos = explode(',', strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']));
        $is_https = in_array('https', $protos, true);
    }

    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '';

    // 获取当前目录路径
    $scriptDir = dirname($_SERVER['SCRIPT_NAME'] ?? '');
    if ($scriptDir === '/' || $scriptDir === '\\') {
        $scriptDir = '';
    }

    $baseUrl = ($is_https ? 'https://' : 'http://') . $host . $scriptDir;
    return rtrim($baseUrl, '/') . '/';
}

// 主程序逻辑
$db = new ShortUrlDB();
$shortUrlGen = new ShortUrlGenerator($db->getDB());
$baseUrl = getBaseUrl();

// 获取请求路径
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$shortCode = ltrim($path, '/');

// 如果是短码,进行重定向
if ($shortCode && !in_array($shortCode, ['', 'index.php'])) {
    if ($longUrl = $shortUrlGen->getLongUrl($shortCode)) {
        header('Location: ' . $longUrl, true, 301);
        exit;
    } else {
        // http_response_code(404);
        echo '<html><body><h2>404</h2><a href="' . $baseUrl . '">返回</a></body></html>';
        exit;
    }
}

// 处理表单提交
$message = '';
$shortUrl = '';
if ($_POST['url'] ?? false) {
    $longUrl = trim($_POST['url']);
    $customCode = trim($_POST['custom_code'] ?? '');

    if (filter_var($longUrl, FILTER_VALIDATE_URL)) {
        try {
            $code = $shortUrlGen->saveShortUrl($longUrl, $customCode);
            $shortUrl = $baseUrl . $code;
            $message = "生成成功!";
        } catch (Exception $e) {
            $message = "错误: " . $e->getMessage();
        }
    } else {
        $message = "URL格式错误";
    }
}

// 显示页面
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>短网址生成器</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; font-family: system-ui, sans-serif; }
        body { background: #f5f7fa; padding: 20px; min-height: 100vh; display: flex; justify-content: center; align-items: center; }
        .container { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); max-width: 480px; width: 100%; }
        h1 { text-align: center; margin-bottom: 20px; color: #2c3e50; }
        .message { padding: 10px; margin-bottom: 15px; border-radius: 4px; text-align: center; }
        .success { background: #d4edda; color: #155724; }
        .error { background: #f8d7da; color: #721c24; }
        .form-group { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: 500; }
        input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; }
        input:focus { outline: none; border-color: #3498db; }
        small { color: #666; font-size: 12px; margin-top: 3px; }
        button { width: 100%; background: #3498db; color: white; border: none; padding: 10px; border-radius: 4px; font-size: 14px; cursor: pointer; }
        button:hover { background: #2980b9; }
        .result { margin-top: 15px; padding: 15px; background: #f8f9fa; border-radius: 4px; }
        .copy-btn { background: #27ae60; margin-top: 8px; padding: 6px 10px; font-size: 12px; width: auto; }
    </style>
</head>
<body>
    <div class="container">
        <h1>短网址生成器</h1>

        <?php if ($message): ?>
            <div class="message <?php echo strpos($message, '成功') !== false ? 'success' : 'error'; ?>"><?php echo htmlspecialchars($message); ?></div>
        <?php endif; ?>

        <form method="POST">
            <div class="form-group">
                <label for="url">长网址</label>
                <input type="url" name="url" placeholder="https://example.com" value="<?php echo htmlspecialchars($_POST['url'] ?? ''); ?>" required>
            </div>

            <div class="form-group">
                <label for="custom_code">自定义短码(可选)</label>
                <input type="text" name="custom_code" placeholder="myurl" value="<?php echo htmlspecialchars($_POST['custom_code'] ?? ''); ?>" maxlength="10">
                <small>字母数字,1-10位</small>
            </div>

            <button type="submit">生成短网址</button>
        </form>

        <?php if ($shortUrl): ?>
            <div class="result">
                <strong>短网址</strong>
                <div style="word-break: break-all; margin: 5px 0; color: #3498db;"><?php echo htmlspecialchars($shortUrl); ?></div>
                <button class="copy-btn" onclick="copyText('<?php echo htmlspecialchars($shortUrl); ?>')">复制链接</button>
            </div>
        <?php endif; ?>
    </div>

    <script>
        function copyText(text) {
            navigator.clipboard.writeText(text.trim()).then(() => {
                const btn = event.target;
                btn.textContent = '已复制';
                setTimeout(() => btn.textContent = '复制链接', 1500);
            }).catch(() => {
                const textarea = document.createElement('textarea');
                textarea.value = text.trim();
                document.body.appendChild(textarea);
                textarea.select();
                document.execCommand('copy');
                document.body.removeChild(textarea);

                const btn = event.target;
                btn.textContent = '已复制';
                setTimeout(() => btn.textContent = '复制链接', 1500);
            });
        }
    </script>
</body>
</html>

 

伪静态规则

# .htaccess - Apache URL重写规则[1](@ref)
RewriteEngine On

# 如果请求的不是真实文件或目录
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]


# Nginx重写规则[1](@ref)
location / {
    try_files $uri $uri/ /index.php?$args;
}
 
转自:https://www.nodeloc.com/t/topic/65400
免责声明:

此内容由本站网友原创或转载自网络公开渠道,仅供学习测试使用,禁止商用,著作权归原作者所有;
本站不对此内容担负法律责任,请于下载后24小时内删除;
如发现内容侵权或违规,请联系本站,我们将在12小时内及时做删除或屏蔽处理!邮箱:[email protected]


最新回复 (2)

您可以在 登录 or 注册 后,对此帖发表评论!

返回
发新帖
自助推广 自助积分购买 我的推广
展示位加载中...
赞助商家我要入驻