如何用PHP隐藏外部网站的原始下载链接?
解决方案:隐藏外部文件URL实现下载
原代码的问题
- 你把完整的外部URL作为下载文件名,会导致用户下载的文件名变成一串混乱的URL字符,完全不符合预期。
- 直接用
readfile()读取HTTPS URL依赖PHP的allow_url_fopen配置,很多服务器默认限制这个功能,导致无法正常读取文件。 - 缺少文件长度、缓存控制等必要HTTP头部,可能引发下载中断、进度显示异常等问题。
方案一:使用readfile(需开启allow_url_fopen)
这种方式简单直接,但需要服务器允许PHP读取外部URL:
<?php // 用白名单映射ID和文件URL,避免恶意请求 $fileMap = [ '1' => 'https://externalsite.com/20230113100300if_/https%3A%2F%2Fs38.123apps.com%2Fvconv%2Fd%2F63c12a662da0e_mkv_ymfVHPvq.mkv', // 可添加更多ID对应文件的条目 ]; $id = $_GET['id'] ?? ''; if (!isset($fileMap[$id])) { die('无效请求'); } $fileUrl = $fileMap[$id]; // 从URL中提取真实文件名,也可手动指定如$filename = "video.mkv" $parsedUrl = parse_url($fileUrl); $pathParts = explode('/', $parsedUrl['path']); $filename = end($pathParts); // 获取文件大小 $filesize = filesize($fileUrl); // 设置正确的HTTP头部 header('Content-Type: video/x-matroska'); // MKV文件的标准MIME类型 header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"'); header('Content-Length: ' . $filesize); header('Cache-Control: no-cache'); header('Pragma: no-cache'); // 输出文件内容 readfile($fileUrl); exit; ?>
方案二:使用cURL(更稳定,不依赖allow_url_fopen)
如果服务器禁用了allow_url_fopen,用cURL是更可靠的选择:
<?php // 同样使用白名单映射ID和文件URL $fileMap = [ '1' => 'https://externalsite.com/20230113100300if_/https%3A%2F%2Fs38.123apps.com%2Fvconv%2Fd%2F63c12a662da0e_mkv_ymfVHPvq.mkv', ]; $id = $_GET['id'] ?? ''; if (!isset($fileMap[$id])) { die('无效请求'); } $fileUrl = $fileMap[$id]; // 解析文件名 $parsedUrl = parse_url($fileUrl); $pathParts = explode('/', $parsedUrl['path']); $filename = end($pathParts); // 初始化cURL请求 $ch = curl_init($fileUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 自动处理重定向 $response = curl_exec($ch); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $body = substr($response, $headerSize); // 分离响应头和文件内容 $filesize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); // 获取文件大小 curl_close($ch); // 设置HTTP头部 header('Content-Type: video/x-matroska'); header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"'); header('Content-Length: ' . $filesize); header('Cache-Control: no-cache'); header('Pragma: no-cache'); // 输出文件内容 echo $body; exit; ?>
关键注意事项
- 必须使用白名单映射(如代码中的
$fileMap),绝对不能直接用$_GET['id']拼接URL,否则会被恶意利用来下载任意外部文件,造成安全风险。 - 确保服务器开启了对应功能:方案一需要
allow_url_fopen = On,方案二需要开启cURL扩展。 - 使用
video/x-matroska作为MIME类型,比通用的application/octet-stream更友好,浏览器能正确识别文件类型。
内容的提问来源于stack exchange,提问作者Zamani Vogue
相关产品推荐
相关产品推荐

