
在许多应用场景中,我们希望追踪用户的文件下载行为,例如统计下载量、记录下载者信息或在下载前进行权限校验。通常,这可以通过一个php脚本来实现,该脚本负责处理下载请求、记录相关数据,然后将文件流发送给用户。然而,如果用户可以直接通过文件的url(例如 https://exampledomain.com/files/file.pdf)访问文件,那么这个php脚本就会被绕过,导致无法记录下载信息。
为了解决这个问题,我们可以利用Apache服务器的mod_rewrite模块。mod_rewrite允许我们根据URL模式匹配规则,将用户请求的URL在服务器内部进行重写,使其指向我们预设的PHP处理脚本,同时将原始请求的文件路径作为参数传递给PHP脚本。这样,即使用户访问的是直链,请求也会被内部重定向到PHP脚本,从而实现下载日志记录的目的。
要实现URL重写,需要确保Apache服务器已启用mod_rewrite模块,并且允许在目录中使用.htaccess文件。
启用mod_rewrite模块 在大多数Linux发行版中,可以通过以下命令启用:
sudo a2enmod rewrite sudo systemctl restart apache2
对于Windows或其他系统,请检查Apache的httpd.conf文件,确保LoadModule rewrite_module modules/mod_rewrite.so这一行没有被注释掉。
允许.htaccess文件生效 在Apache的虚拟主机配置或主配置文件中,确保文件下载目录的<Directory>块中设置了AllowOverride All,例如:
<Directory /var/www/html/files>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>修改后同样需要重启Apache服务。
立即学习“PHP免费学习笔记(深入)”;
接下来,我们在需要进行下载日志记录的目录(例如,存储下载文件的/files/目录)中创建一个名为.htaccess的文件,并添加以下重写规则:
RewriteEngine On RewriteBase /files/ RewriteRule ^(.+(file|FILE))$ download.php?file=$1 [L]
下面详细解释这些指令的含义:
示例解析: 假设download.php文件位于/files/目录下。 当用户尝试访问 https://exampledomain.com/files/myfile.file 时:
原始答案中的正则表达式^(.+(file|FILE))$非常具体,可能不适用于所有类型的文件(例如file.pdf、image.jpg等)。为了使其更具通用性,我们可以根据实际需求调整RewriteRule的正则表达式。
以下是一些更通用的匹配模式:
匹配任何带有扩展名的文件:
RewriteRule ^([^/]+\.[a-zA-Z0-9]+)$ download.php?file=$1 [L]
匹配目录中所有文件(不包括子目录):
RewriteRule ^(.+)$ download.php?file=$1 [L]
建议: 根据您的文件命名约定和目录结构,选择最适合的正则表达式。如果您的文件目录中可能包含子目录,并且您不希望子目录也被重写到download.php,那么第一个通用模式会更安全。
您的download.php脚本需要执行以下核心任务:
示例PHP脚本骨架:
<?php
// download.php
$fileName = $_GET['file'] ?? '';
if (empty($fileName)) {
header("HTTP/1.0 400 Bad Request");
exit("文件名参数缺失。");
}
// 定义允许下载的根目录
$downloadDir = __DIR__ . DIRECTORY_SEPARATOR; // 假设download.php和文件在同一目录
// 重要的安全检查:防止目录遍历
$filePath = realpath($downloadDir . $fileName);
if ($filePath === false || strpos($filePath, $downloadDir) !== 0) {
header("HTTP/1.0 404 Not Found");
exit("文件不存在或无权访问。");
}
if (!file_exists($filePath) || !is_file($filePath)) {
header("HTTP/1.0 404 Not Found");
exit("文件不存在。");
}
// 记录下载日志(这里只是一个示例,您可以根据需要记录更多信息)
$logFile = __DIR__ . DIRECTORY_SEPARATOR . 'downloads.log';
$logEntry = date('Y-m-d H:i:s') . " - IP: " . $_SERVER['REMOTE_ADDR'] . " - Downloaded: " . $fileName . "\n";
file_put_contents($logFile, $logEntry, FILE_APPEND);
// 设置HTTP头,开始文件下载
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream'); // 适用于大多数文件类型
header('Content-Disposition: attachment; filename="' . basename($fileName) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filePath));
// 清除输出缓冲区,防止额外内容干扰文件下载
ob_clean();
flush();
// 读取文件并输出
readfile($filePath);
exit;
?>通过本文介绍的方法,您已经学会了如何利用Apache的mod_rewrite模块和.htaccess文件,将直接文件下载链接重定向至一个PHP脚本。这不仅解决了直链下载绕过日志系统的问题,还为实现更复杂的下载管理功能(如权限控制、带宽限制等)奠定了基础。在实施过程中,请务必注意正则表达式的精确性以及PHP脚本中的安全验证,以确保系统的稳定性和安全性。
以上就是Apache .htaccess 实现直链下载重定向至PHP日志脚本的教程的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号