代码:
<?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;
}