PHP 代理下载文件
PHP proxy to download files
我认为这很容易。
我有一个简单的网站,其中有一个保留区域和一些要从中下载的文件。
我禁用了使用 .htaccess 的直接文件下载,我通过这个简单的 proxy.php 文件管理文件下载:
// ....
if ($filename === null || !file_exists($proxiedDirectory.$filename)) {
http_response_code(404);
exit;
}
if (!$site->is_logged_in()) {
http_response_code(403);
exit;
}
$fp = fopen($proxiedDirectory.$filename, 'rb');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
fpassthru($fp);
exit;
此代码完美运行,但不幸的是我有一个 1.2Gb 的文件可供用户下载,而且此脚本太慢,并且不允许下载完整文件。
如有任何帮助,我们将不胜感激,
提前致谢!
米。
使用分块下载,如下:
$chunkSize = 1024 * 1024;
while (!feof($fp))
{
$buffer = fread($fp, $chunkSize);
echo $buffer;
ob_flush();
flush();
}
使用nginx作为代理可能更合适。
原因很简单:
当你用php下载的时候,在php-fpm中请求会超时,所以文件很可能下载不完整。
location /proxy.lua {
proxy_pass http://proxy.com/link/;
}
如果需要检查用户是否登录,可以使用lua + nginx(OpenResty)
但是有一种简单的方法可以检查:
1. proxy.php 使用两个参数将请求重定向到 nginx 位置 proxy.lua:ts 和代码。
ts is timestamp of server
code is md5sum(ts+"complexstring")
header("Location: /proxy.lua?ts=122&code=xxx&filename=xxxx", 302);
exit(0);
在 lua 时:
parse the parameter ts and code, validate the code and ts value
proxy the file
您可以组合使用 header()
、set_time_limit()
、fgets()
、ob_flush()
、flush()
。这是我的示例,最好在 OS 64 位上使用 Php 64 位,因为 filesize()
在此体系结构中没有限制。
// Set force download headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file . '"');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . sprintf("%u", filesize($downloads_folder . $file)));
// Open and output file contents
set_time_limit(0);
$fh = fopen($downloads_folder . $file, "rb");
while (!feof($fh)) {
echo fgets($fh);
ob_flush();
flush();
}
fclose($fh);
exit;
希望对您有所帮助。
在fpassthru($fp)
之前使用ob_end_clean()
例如
ob_end_clean();
fpassthru($fp);
这可能适用于大文件
我认为这很容易。
我有一个简单的网站,其中有一个保留区域和一些要从中下载的文件。
我禁用了使用 .htaccess 的直接文件下载,我通过这个简单的 proxy.php 文件管理文件下载:
// ....
if ($filename === null || !file_exists($proxiedDirectory.$filename)) {
http_response_code(404);
exit;
}
if (!$site->is_logged_in()) {
http_response_code(403);
exit;
}
$fp = fopen($proxiedDirectory.$filename, 'rb');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
fpassthru($fp);
exit;
此代码完美运行,但不幸的是我有一个 1.2Gb 的文件可供用户下载,而且此脚本太慢,并且不允许下载完整文件。
如有任何帮助,我们将不胜感激,
提前致谢!
米。
使用分块下载,如下:
$chunkSize = 1024 * 1024;
while (!feof($fp))
{
$buffer = fread($fp, $chunkSize);
echo $buffer;
ob_flush();
flush();
}
使用nginx作为代理可能更合适。 原因很简单: 当你用php下载的时候,在php-fpm中请求会超时,所以文件很可能下载不完整。
location /proxy.lua {
proxy_pass http://proxy.com/link/;
}
如果需要检查用户是否登录,可以使用lua + nginx(OpenResty)
但是有一种简单的方法可以检查: 1. proxy.php 使用两个参数将请求重定向到 nginx 位置 proxy.lua:ts 和代码。
ts is timestamp of server
code is md5sum(ts+"complexstring")
header("Location: /proxy.lua?ts=122&code=xxx&filename=xxxx", 302);
exit(0);
在 lua 时:
parse the parameter ts and code, validate the code and ts value
proxy the file
您可以组合使用 header()
、set_time_limit()
、fgets()
、ob_flush()
、flush()
。这是我的示例,最好在 OS 64 位上使用 Php 64 位,因为 filesize()
在此体系结构中没有限制。
// Set force download headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file . '"');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . sprintf("%u", filesize($downloads_folder . $file)));
// Open and output file contents
set_time_limit(0);
$fh = fopen($downloads_folder . $file, "rb");
while (!feof($fh)) {
echo fgets($fh);
ob_flush();
flush();
}
fclose($fh);
exit;
希望对您有所帮助。
在fpassthru($fp)
之前使用ob_end_clean()
例如
ob_end_clean();
fpassthru($fp);
这可能适用于大文件