本文目录导读:

在 PHP 中生成临时下载链接有多种方法,我为您提供几种常用的实现方案:
方法1:使用 Token 验证(推荐)
生成临时链接
<?php
class TempDownload {
private $expireTime = 3600; // 默认1小时过期
private $secretKey = 'your-secret-key'; // 密钥
/**
* 生成临时下载链接
* @param string $filePath 文件路径
* @param int $expireTime 过期时间(秒)
* @return string 临时链接
*/
public function generateLink($filePath, $expireTime = null) {
if ($expireTime) {
$this->expireTime = $expireTime;
}
// 生成过期时间戳
$expire = time() + $this->expireTime;
// 生成token
$token = md5($filePath . $expire . $this->secretKey);
// 构建链接
$baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]";
return $baseUrl . '/download.php?file=' . urlencode($filePath) . '&expire=' . $expire . '&token=' . $token;
}
/**
* 验证并处理下载
*/
public function handleDownload() {
if (!isset($_GET['file']) || !isset($_GET['expire']) || !isset($_GET['token'])) {
die('无效的下载链接');
}
$file = urldecode($_GET['file']);
$expire = $_GET['expire'];
$token = $_GET['token'];
// 验证token
$expectedToken = md5($file . $expire . $this->secretKey);
if ($token !== $expectedToken) {
die('无效的下载令牌');
}
// 检查是否过期
if (time() > $expire) {
die('下载链接已过期');
}
// 验证文件存在
if (!file_exists($file) || !is_file($file)) {
die('文件不存在');
}
// 发送文件
$this->sendFile($file);
}
/**
* 发送文件下载
*/
private function sendFile($filePath) {
// 获取文件名
$fileName = basename($filePath);
// 设置请求头
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($filePath));
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Expires: 0');
// 清空输出缓冲
while (ob_get_level()) {
ob_end_clean();
}
// 读取并输出文件
readfile($filePath);
exit;
}
}
// 使用示例
$tempDownload = new TempDownload();
// 生成链接
$filePath = '/path/to/your/file.zip';
$link = $tempDownload->generateLink($filePath, 3600); // 1小时有效
echo "下载链接: " . $link;
?>
方法2:使用数据库存储 Token
<?php
class DatabaseTempDownload {
private $db;
private $expireTime = 3600;
public function __construct($pdo) {
$this->db = $pdo;
}
/**
* 生成链接并存储到数据库
*/
public function generateLink($filePath, $expireTime = null) {
if ($expireTime) {
$this->expireTime = $expireTime;
}
$token = bin2hex(random_bytes(32)); // 生成随机token
$expire = date('Y-m-d H:i:s', time() + $this->expireTime);
// 保存到数据库
$sql = "INSERT INTO download_links (token, file_path, expire_time, created_at) VALUES (?, ?, ?, NOW())";
$stmt = $this->db->prepare($sql);
$stmt->execute([$token, $filePath, $expire]);
$baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]";
return $baseUrl . "/download.php?token=" . $token;
}
/**
* 验证token并下载
*/
public function handleDownload() {
if (!isset($_GET['token'])) {
die('无效的下载链接');
}
$token = $_GET['token'];
// 查询数据库
$sql = "SELECT * FROM download_links WHERE token = ? AND expire_time > NOW() LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([$token]);
$record = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$record) {
die('下载链接无效或已过期');
}
// 可以使用后删除记录(一次性使用)
$sql = "DELETE FROM download_links WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$record['id']]);
// 发送文件
$this->sendFile($record['file_path']);
}
private function sendFile($filePath) {
if (!file_exists($filePath)) {
die('文件不存在');
}
$fileName = basename($filePath);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($filePath));
while (ob_get_level()) {
ob_end_clean();
}
readfile($filePath);
exit;
}
}
?>
方法3:简单签名链接
<?php
class SimpleSignedLink {
private $secretKey = 'your-secret-key';
private $expireTime = 600; // 10分钟
public function generateLink($filePath, $expireTime = null) {
if ($expireTime) {
$this->expireTime = $expireTime;
}
$expire = time() + $this->expireTime;
// 生成签名
$signature = hash_hmac('sha256', $filePath . $expire, $this->secretKey);
$baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]";
return $baseUrl . '/download.php?file=' . urlencode($filePath) . '&expire=' . $expire . '&signature=' . $signature;
}
public function validateAndDownload() {
if (!isset($_GET['file']) || !isset($_GET['expire']) || !isset($_GET['signature'])) {
die('无效请求');
}
$file = urldecode($_GET['file']);
$expire = $_GET['expire'];
$signature = $_GET['signature'];
// 验证签名
$expectedSignature = hash_hmac('sha256', $file . $expire, $this->secretKey);
if (!hash_equals($expectedSignature, $signature)) {
die('签名无效');
}
// 检查过期
if (time() > $expire) {
die('链接已过期');
}
// 验证文件路径(防止目录遍历攻击)
$allowedDir = '/var/www/files/';
$realPath = realpath($allowedDir . $file);
if ($realPath === false || strpos($realPath, $allowedDir) !== 0) {
die('无效的文件路径');
}
// 发送文件
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($realPath) . '"');
header('Content-Length: ' . filesize($realPath));
while (ob_get_level()) {
ob_end_clean();
}
readfile($realPath);
exit;
}
}
?>
download.php 文件(统一入口)
<?php // download.php - 处理所有临时下载请求 // 根据您的实现方法选择 $download = new TempDownload(); // 或 DatabaseTempDownload / SimpleSignedLink $download->handleDownload();
数据库表结构(如果使用数据库方法)
CREATE TABLE download_links (
id INT AUTO_INCREMENT PRIMARY KEY,
token VARCHAR(64) UNIQUE NOT NULL,
file_path VARCHAR(255) NOT NULL,
expire_time DATETIME NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
安全建议
- 路径安全:始终验证文件路径,防止目录遍历攻击
- 密钥安全:使用强随机密钥,不要硬编码
- HTTPS:生产环境务必使用HTTPS
- 过期时间:合理设置过期时间,避免过长
- 访问控制:可以结合IP限制、次数限制等
选择哪种方法取决于您的需求:
- 方法1:简单,无需数据库,适合临时使用
- 方法2:可追溯,支持一次性使用,推荐生产环境
- 方法3:无需数据库,安全可靠,性能好
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播