求助:如何用PHP实现音视频及URL文件的强制下载
PHP实现文件强制下载的两种方案
Got it, let's tackle your two PHP file download requirements step by step. Both rely on sending the right HTTP headers to tell the browser to trigger a download instead of trying to play media directly.
1. 本地音频/视频文件的强制下载
For local files, the core idea is to override the browser's default behavior (playing media) by setting Content-Disposition: attachment in the HTTP headers. Here's a robust implementation:
<?php // 替换为你的本地文件实际路径 $filePath = '/var/www/html/assets/sample.mp4'; // 验证文件是否存在且可读取 if (!file_exists($filePath) || !is_readable($filePath)) { http_response_code(404); echo "Error: 文件不存在或无法访问"; exit; } // 获取文件详情 $fileName = basename($filePath); $fileSize = filesize($filePath); // 设置强制下载的HTTP头 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"'); header('Content-Length: ' . $fileSize); header('Cache-Control: no-cache'); header('Pragma: no-cache'); // 高效输出文件内容(避免将整个文件加载到内存) readfile($filePath); exit; ?>
关键说明:
application/octet-stream: 通用二进制MIME类型,确保浏览器不会尝试内嵌播放媒体文件。rawurlencode($fileName): 处理特殊字符(比如中文文件名),防止下载时文件名乱码。readfile(): 比file_get_contents()更节省内存,因为它直接将文件流输出到浏览器,无需将文件全部存入RAM。
2. 从远程URL下载并触发强制下载
对于远程文件,我们需要先从目标URL获取内容,再向用户发送相同的下载头。推荐使用cURL来处理重定向和HTTP错误:
基础实现(中小型文件):
<?php // 替换为你的目标远程URL $remoteUrl = 'https://cf-media.sndcdn.com/WSIkwY864LX0.128.mp3?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLW1lZGlhLnNuZGNkbi5jb20vV1NJa3dZODY0TFgwLjEyOC5tcDMiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE1MTg4Njc5MjF9fX1dfQ__&Signature=D8mLMEF87phwsYauLxjeHVuPhYYyC~rVu901PnMNJzRX1WoYEQz3-t05OVfDJD5KQPN-mt2IXIW9SEjSy8ASWkD3esS4MQ9DoRRzLmlp84Irsj65LeyonJAj-3gvi~XVEoGkcwNQgWKNDlHpT8gJmjGwgiMsRwEfH5uBfLcKd2Vw...'; // 从远程URL中提取文件名 $fileName = basename(parse_url($remoteUrl, PHP_URL_PATH)); // 初始化cURL会话 $ch = curl_init($remoteUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向 curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'); // 模拟浏览器请求,避免被拦截 $fileContent = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 处理请求错误 if ($httpCode !== 200 || $fileContent === false) { http_response_code($httpCode ?: 500); echo "Error: 获取远程文件失败"; curl_close($ch); exit; } curl_close($ch); // 设置下载头 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"'); header('Content-Length: ' . strlen($fileContent)); header('Cache-Control: no-cache'); header('Pragma: no-cache'); // 输出文件内容 echo $fileContent; exit; ?>
针对大型远程文件(避免内存溢出):
如果处理大文件,将整个内容加载到内存会导致PHP触发内存限制。改用以下流式传输方案:
<?php $remoteUrl = 'your-remote-url-here'; $fileName = basename(parse_url($remoteUrl, PHP_URL_PATH)); // 先设置下载头 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"'); header('Cache-Control: no-cache'); header('Pragma: no-cache'); // 将远程文件直接流式传输到浏览器 $ch = curl_init($remoteUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'); curl_setopt($ch, CURLOPT_FILE, fopen('php://output', 'w')); // 直接输出到浏览器 curl_exec($ch); // 检查错误 if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) { http_response_code(404); echo "Error: 获取远程文件失败"; } curl_close($ch); exit; ?>
关键说明:
CURLOPT_FOLLOWLOCATION: 确保跟随远程服务器发送的重定向请求。CURLOPT_USERAGENT: 部分服务器会拦截无有效用户代理的请求,模拟浏览器可避免此类问题。- 用
php://output流式传输: 将远程文件内容直接管道到用户浏览器,无需存入PHP内存,适合处理大文件。
内容的提问来源于stack exchange,提问作者Muhammad
相关产品推荐
相关产品推荐

