如何从WordPress站点B获取X-Sendfile传输的远程文件?
解决WordPress站点代理X-Sendfile远程下载的思路
先分析你之前两种方法失败的原因:
- 方法1(download_url):WordPress的
download_url函数主要用于将文件下载到本地服务器存储,它的URL校验逻辑会检查目标是否返回可识别的文件内容,而站点A返回的是X-Sendfile头(而非直接文件内容),导致函数判定URL无效。 - 方法2(PhpXsendfile直接传远程URL):X-Sendfile机制的核心是让Web服务器读取本地文件并发送给客户端,它不支持远程URL,因此直接传入远程地址会导致服务器找不到对应本地文件,触发错误。
下面是三种可行的解决思路:
方案1:PHP反向代理(WordPress环境兼容)
使用WordPress内置的WP_Http类请求站点A的下载链接,获取响应头和文件内容后转发给客户端,相当于站点B做一层中转。这种方式无需服务器配置,代码层面即可实现:
if (!empty($_GET['download'])) { $remote_download_url = 'https://a.com/?download=' . urlencode($_GET['download']); $http_client = new WP_Http(); // 配置流式下载到临时文件,避免大文件占用过多内存 $response = $http_client->get($remote_download_url, [ 'timeout' => 300, // 根据文件大小调整超时时间 'stream' => true, 'filename' => tempnam(sys_get_temp_dir(), 'wp_proxy_download_'), ]); if (is_wp_error($response)) { status_header(404); exit('下载失败:' . $response->get_error_message()); } // 转发站点A返回的下载相关响应头 $remote_headers = $response['headers']; if (isset($remote_headers['Content-Disposition'])) { header('Content-Disposition: ' . $remote_headers['Content-Disposition']); } if (isset($remote_headers['Content-Type'])) { header('Content-Type: ' . $remote_headers['Content-Type']); } if (isset($remote_headers['Content-Length'])) { header('Content-Length: ' . $remote_headers['Content-Length']); } // 输出文件内容并清理临时文件 readfile($response['filename']); unlink($response['filename']); exit; }
注意:如果是超大文件,建议进一步优化临时文件处理逻辑,避免磁盘占用过高。
方案2:Web服务器反向代理(性能最优)
如果拥有站点B的服务器配置权限,直接在Web服务器(Nginx/Apache)层面配置反向代理,让请求直接转发到站点A,这种方式完全绕过PHP,性能最佳,适合大文件场景。
Nginx配置示例
location ~ ^/\?download= { proxy_pass https://a.com$request_uri; proxy_set_header Host a.com; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 若站点A使用Nginx的X-Accel-Redirect(替代X-Sendfile),需转发对应头 # proxy_pass_header X-Accel-Redirect; }
Apache配置示例
RewriteEngine On RewriteCond %{QUERY_STRING} ^download=(.*)$ RewriteRule ^(.*)$ https://a.com/$1?download=%1 [P,L] # 确保已启用mod_proxy、mod_proxy_http和mod_rewrite模块
方案3:302重定向(最简单但暴露源站)
如果不介意访客跳转到站点A的URL,可以直接在站点B做302重定向,代码最简单:
if (!empty($_GET['download'])) { $remote_url = 'https://a.com/?download=' . urlencode($_GET['download']); wp_redirect($remote_url); exit; }
方案对比
- Web服务器代理:性能最优,无PHP开销,适合大文件,但需要服务器配置权限。
- PHP代理:无需服务器配置,兼容性强,但大文件可能存在内存/超时问题,需优化。
- 302重定向:实现最简单,但访客会跳转到站点A的URL,暴露源站地址。
内容的提问来源于stack exchange,提问作者cloudinstone
相关产品推荐
相关产品推荐

