php,文件下载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5595485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
php, file download
提问by jsonx
I am using the simple file downloading script:
我正在使用简单的文件下载脚本:
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
It is working on my localserver upto 200mb.
它在我的本地服务器上工作高达 200mb。
When i try this code in my website it downloads 173KB instead of 200MB file.
当我在我的网站上尝试此代码时,它会下载 173KB 而不是 200MB 的文件。
I checked everything, wrote some custom code (using ob functions and fread instead of readfile) but can't download big files.
我检查了所有内容,编写了一些自定义代码(使用 ob 函数和 fread 而不是 readfile),但无法下载大文件。
Thank you for your answers.
谢谢您的回答。
- I am using Apache 2.2, PHP 5.3
- All PHP settings to deal with big files are ok. (execution times, memory limits, ...
- 我使用的是 Apache 2.2、PHP 5.3
- 所有处理大文件的 PHP 设置都可以。(执行时间,内存限制,...
回答by RobertPitt
One issue I have with the following code is you have no control over the output stream, your letting PHP handle it without knowing exactly what is going on within the background:
我在以下代码中遇到的一个问题是您无法控制输出流,您让 PHP 处理它而不确切知道后台发生了什么:
What you should do is set up an output system that you can control and replicated accros servers.
您应该做的是设置一个可以控制和复制 accros 服务器的输出系统。
For example:
例如:
if (file_exists($file))
{
if (FALSE!== ($handler = fopen($file, 'r')))
{
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: chunked'); //changed to chunked
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
//header('Content-Length: ' . filesize($file)); //Remove
//Send the content in chunks
while(false !== ($chunk = fread($handler,4096)))
{
echo $chunk;
}
}
exit;
}
echo "<h1>Content error</h1><p>The file does not exist!</p>";
This is only basic but give it a go!
这只是基本的,但试一试!
Also read my reply here: file_get_contents => PHP Fatal error: Allowed memory exhausted
还可以在这里阅读我的回复:file_get_contents => PHP 致命错误:允许内存耗尽
回答by Paul DelRe
It seems readfile can have issues with long files. As @Khez asked, it could be that the script is running for too long. A quick Googling resulted in a couple examples of chunking the file.
似乎 readfile 可能对长文件有问题。正如@Khez 所问,可能是脚本运行时间过长。一个快速的谷歌搜索导致了几个分块文件的例子。
http://teddy.fr/blog/how-serve-big-files-through-phphttp://www.php.net/manual/en/function.readfile.php#99406
http://teddy.fr/blog/how-serve-big-files-through-php http://www.php.net/manual/en/function.readfile.php#99406
回答by Polarlight
One solution to certain scenarios is that you can use PHP-script to intelligently decide what file from where to download, but instead of sending the file directly from PHP, you could return a redirection to the client which then contains the direct link which is processed by the web server alone.
某些场景的一种解决方案是,您可以使用 PHP 脚本智能地决定从何处下载哪个文件,但不是直接从 PHP 发送文件,您可以将重定向返回给客户端,然后包含处理的直接链接仅通过 Web 服务器。
This could be done at least in two ways: either PHP-script copies the file into a "download zone" which for example might be cleaned from "old" files regularly by some other background/service script or you expose the real permanent location to the clients.
这至少可以通过两种方式完成:要么 PHP 脚本将文件复制到“下载区”,例如可能会被其他一些后台/服务脚本定期从“旧”文件中清除,或者您将真正的永久位置公开给客户。
There are of course drawbacks as is the case with each solution. In this one is that depending on the clients (curl, wget, GUI browser) requesting the file they may not support redirection you make and in the other one, the files are very exposed to the outer world and can be at all times read without the (access) control of the PHP script.
当然,每种解决方案都有缺点。在这种情况下,根据请求文件的客户端(curl、wget、GUI 浏览器),他们可能不支持您所做的重定向,而在另一种情况下,文件非常暴露于外部世界,并且可以随时读取而无需PHP 脚本的(访问)控制。
回答by Khez
Have you made sure your script can run longenough and has enough memory?
Do you really need output buffering ?
你真的需要输出缓冲吗?
回答by ZoFreX
The real solution is to avoid using a PHP script for just sending a file to the client, it's overkill and your webserver is better suited for the task.
真正的解决方案是避免使用 PHP 脚本仅将文件发送到客户端,这是矫枉过正,而您的网络服务器更适合该任务。
Presumably you have a reason for sending the files through PHP, perhaps users must authenticate first? If that is the case then you should use X-Accel-Redirect(if you're using nginx) or X-Sendfile(previously X-LIGHTTPD-send-file) on lighttpd.
想必您有通过 PHP 发送文件的原因,也许用户必须先进行身份验证?如果是这种情况,那么您应该在 lighttpd 上使用X-Accel-Redirect(如果您使用的是 nginx)或X-Sendfile(以前是 X-LIGHTTPD-send-file)。
If you're using Apache I've found a few references to mod_xsendfilebut I've never used it personally, and I doubt it's installed for you if you have managed hosting.
如果您使用的是 Apache,我发现了一些对mod_xsendfile 的引用,但我从未亲自使用过它,如果您有托管主机,我怀疑是否为您安装了它。
If these solutions are untenable I apologise, but I really need more information on the actual problem: Why are you sending these files through PHP in the first place?
如果这些解决方案站不住脚,我深表歉意,但我真的需要更多关于实际问题的信息:你为什么首先通过 PHP 发送这些文件?