基于PHP+MySQL实现文件临时有效链接的技术问询
PHP+MySQL实现文件临时链接系统方案
1. 数据库表设计
首先创建存储临时链接信息的表,关联用户、文件与有效期:
CREATE TABLE `temp_file_links` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `user_id` INT UNSIGNED NOT NULL, -- 关联你的用户表ID `file_path` VARCHAR(255) NOT NULL, -- 文件真实存储路径(建议放在web根目录外) `token` VARCHAR(64) NOT NULL UNIQUE, -- 临时链接唯一标识 `expire_at` DATETIME NOT NULL, -- 过期时间 `is_used` TINYINT(1) DEFAULT 0, -- 可选:标记是否已被访问 `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) -- 替换为你的用户表名 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 生成临时链接的逻辑
用户申请链接时,生成安全唯一的token,计算过期时间并存入数据库:
<?php // 假设已登录,获取当前用户ID $userId = $_SESSION['user_id']; $filePath = '/var/www/secure_files/report.pdf'; // 替换为实际文件路径(web根外) $expireMinutes = 120; // 用户指定的有效期,比如120分钟 // 生成64位安全随机token $token = bin2hex(random_bytes(32)); // 计算过期时间 $expireAt = date('Y-m-d H:i:s', time() + ($expireMinutes * 60)); // 插入数据库 $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'db_user', 'db_pass'); $stmt = $pdo->prepare("INSERT INTO temp_file_links (user_id, file_path, token, expire_at) VALUES (?, ?, ?, ?)"); $stmt->execute([$userId, $filePath, $token, $expireAt]); // 返回给用户的临时链接 $tempLink = "https://yourdomain.com/get_file.php?token=" . $token; echo "临时文件链接:" . $tempLink; ?>
3. 验证链接并返回文件的逻辑
创建get_file.php处理链接请求,验证有效性后返回文件:
<?php if (!isset($_GET['token'])) { http_response_code(404); exit("无效链接"); } $token = $_GET['token']; $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'db_user', 'db_pass'); // 查询有效链接(未过期、未被使用) $stmt = $pdo->prepare("SELECT * FROM temp_file_links WHERE token = ? AND expire_at > NOW() AND is_used = 0"); $stmt->execute([$token]); $linkInfo = $stmt->fetch(PDO::FETCH_ASSOC); if (!$linkInfo) { http_response_code(404); exit("链接已过期或无效"); } // 标记链接为已使用(可选,按需决定是否允许多次访问) $stmt = $pdo->prepare("UPDATE temp_file_links SET is_used = 1 WHERE token = ?"); $stmt->execute([$token]); // 返回文件 $filePath = $linkInfo['file_path']; if (!file_exists($filePath)) { http_response_code(404); exit("文件不存在"); } // 设置响应头 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($filePath) . '"'); header('Content-Length: ' . filesize($filePath)); // 输出文件内容 readfile($filePath); exit; ?>
4. 过期链接的清理
避免数据库冗余,定期清理过期记录:
Cron定时任务方案
编写清理脚本clean_expired.php:<?php $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'db_user', 'db_pass'); $stmt = $pdo->prepare("DELETE FROM temp_file_links WHERE expire_at < NOW()"); $stmt->execute(); ?>在服务器Cron中添加每日凌晨执行的任务:
0 0 * * * /usr/bin/php /var/www/scripts/clean_expired.phpMySQL事件调度器方案
开启调度后创建定时清理事件:SET GLOBAL event_scheduler = ON; CREATE EVENT clean_expired_links ON SCHEDULE EVERY 1 DAY STARTS CURRENT_DATE + INTERVAL 1 DAY DO DELETE FROM temp_file_links WHERE expire_at < NOW();
5. 安全与优化建议
- 文件务必存在于web根目录以外,禁止直接URL访问,必须通过PHP中转验证。
- 用
random_bytes()生成token,避免uniqid()这类可预测的字符串。 - 可限制单个用户生成的临时链接数量,或单链接的访问次数。
- 可选添加
accessed_at字段记录首次访问时间,便于排查问题。 - 生成链接前验证用户对目标文件的访问权限,防止越权操作。
内容的提问来源于stack exchange,提问作者JMcrafter26
相关产品推荐
相关产品推荐

