如何用PHP检测用户下载行为?JS怎样访问数据库?
检测用户下载行为的实现方案
一、PHP 检测下载行为(推荐可靠方案)
最稳妥的方式是通过 PHP 脚本作为下载的中转处理程序,既能确保每次下载都被记录,又能提升文件安全性(避免文件被直接访问)。具体步骤如下:
1. 准备工作
- 将待下载的程序文件移至网站根目录以外的安全路径(比如
/var/www/private/),防止用户直接通过 URL 访问。 - 创建一个
downloads数据表用于存储下载记录(可根据需求调整字段):
CREATE TABLE downloads ( id INT AUTO_INCREMENT PRIMARY KEY, ip VARCHAR(45) NOT NULL, file_name VARCHAR(255) NOT NULL, download_time DATETIME NOT NULL, country VARCHAR(100), region VARCHAR(100), city VARCHAR(100) );
2. 编写下载处理脚本(download.php)
复用你现有的数据库操作类 $dbcls,实现记录下载日志+输出文件的逻辑:
<?php // 引入数据库类(替换为你的实际路径) require_once 'path/to/your/dbclass.php'; $dbcls = new YourDBClass(); // 校验允许下载的文件列表,防止恶意路径遍历 $allowed_files = ['my_program.exe', 'tool.zip']; $target_file = isset($_GET['file']) ? $_GET['file'] : ''; if (!in_array($target_file, $allowed_files)) { die('无效的下载请求'); } // 文件实际存储路径 $file_path = '/var/www/private/' . $target_file; if (!file_exists($file_path)) { die('文件不存在'); } // 记录下载行为到数据库 $user_ip = $_SERVER['REMOTE_ADDR']; // 复用你的地理位置获取函数 $location_data = get_location2($user_ip); $country = $location_data ? $dbcls->escape_string($location_data->country) : ''; $region = $location_data ? $dbcls->escape_string($location_data->subdivision) : ''; $city = $location_data ? $dbcls->escape_string($location_data->city) : ''; $insert_qry = "INSERT INTO downloads (ip, file_name, download_time, country, region, city) VALUES ('" . $dbcls->escape_string($user_ip) . "', '" . $dbcls->escape_string($target_file) . "', NOW(), '" . $country . "', '" . $region . "', '" . $city . "')"; $dbcls->query_command($insert_qry); // 发送文件给用户 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($file_path) . '"'); header('Content-Length: ' . filesize($file_path)); // 大文件推荐用分块读取代替 readfile,避免内存溢出 readfile($file_path); exit; ?>
3. 前端下载链接
将原文件链接替换为指向 PHP 脚本的链接:
<a href="download.php?file=my_program.exe">下载我的程序</a>
二、JavaScript 辅助方案(无法直接操作数据库)
JavaScript 本身不能直接连接数据库,必须通过调用后端 PHP 接口实现日志记录。这种方式适合辅助场景,但无法保证 100% 可靠(比如用户点击后立即关闭页面可能导致请求中断)。
1. 前端 JS 代码
为下载链接添加点击事件,通过 AJAX 发送日志请求:
document.querySelectorAll('.download-link').forEach(link => { link.addEventListener('click', async (e) => { try { // 异步发送日志请求,不阻塞下载 await fetch('log_download.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: 'file=' + encodeURIComponent(link.dataset.file) }); } catch (err) { // 日志失败不影响下载,仅在控制台输出错误 console.error('下载日志记录失败:', err); } }); });
对应的 HTML 链接:
<a href="my_program.exe" class="download-link" data-file="my_program.exe">下载程序</a>
2. 后端日志接口(log_download.php)
接收 JS 请求并写入数据库:
<?php require_once 'path/to/your/dbclass.php'; $dbcls = new YourDBClass(); if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['file'])) { $file_name = $dbcls->escape_string($_POST['file']); $user_ip = $_SERVER['REMOTE_ADDR']; $location_data = get_location2($user_ip); $country = $location_data ? $dbcls->escape_string($location_data->country) : ''; $region = $location_data ? $dbcls->escape_string($location_data->subdivision) : ''; $city = $location_data ? $dbcls->escape_string($location_data->city) : ''; $insert_qry = "INSERT INTO downloads (ip, file_name, download_time, country, region, city) VALUES ('" . $dbcls->escape_string($user_ip) . "', '" . $file_name . "', NOW(), '" . $country . "', '" . $region . "', '" . $city . "')"; $dbcls->query_command($insert_qry); } ?>
注意事项
- 优先选择 PHP 中转方案:能确保每一次成功的下载都被记录,安全性和可靠性更高。
- 安全校验:永远不要直接使用用户输入的文件名构造文件路径,必须通过白名单校验防止目录遍历攻击。
- 大文件优化:对于超大文件,建议使用服务器的 X-Sendfile(Apache)或 X-Accel-Redirect(Nginx)特性,提升下载效率。
内容的提问来源于stack exchange,提问作者San Pei
相关产品推荐
相关产品推荐

