【问题标题】:Force-downloading, from php file强制下载,从 php 文件
【发布时间】:2013-06-26 18:07:39
【问题描述】:

我正在尝试下载 .mp4 文件。 (大约 1.3GB 大小)。 我正在使用以下内容:

<?php 
$path = "video.mp4";
header('Accept-Ranges: bytes');  // For download resume
header('Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header('Content-Description: File Transfer' );
header('Content-Disposition: attachment; filename="'.basename( $path ).'"' );
header('Content-Length: ' . filesize($path));  // File size
header('Content-Transfer-Encoding: binary');  // For Gecko browsers mainly
header('Content-Type: application/octet-stream' );
header('Expires: 0' );
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT');
header('Pragma: no-cache' );
ob_clean();
flush();
readfile($path);

我打开我的 php 文件,然后 firefox 弹出“要保存”菜单。尺寸看起来合适。 我按另存为,到我的桌面。最终下载的文件以随机大小列出,大约 400MB(330、463 和 440)。

响应标头是:

Connection: Keep-Alive
Content-Disposition:    attachment; filename="//www.frederikspang.dk/elevgallavideo.mp4"
Content-Length: 1422778850
Content-Type:   video/mp4
Date:   Sun, 30 Jun 2013 22:12:30 GMT
Keep-Alive: timeout=10, max=50
Pragma: public
Server: Apache
content-transfer-encoding:  binary

【问题讨论】:

  • 您可能遇到了执行时间限制。下载是否总是在相同的时间段后停止?
  • 可恢复文件下载需要更多的代码;所以你应该删除Accept-Ranges。见:stackoverflow.com/questions/157318/…
  • 你真的在使用输出缓冲吗?如果不是,您可能不需要 ob_clean() 和 flush(),因为 readfile 命令会将数据直接输出到客户端。
  • 我还没计时-@MikeW |它不可恢复,可以一次下载为一个文件。
  • @dethtron5000 即使我没有使用输出缓冲,我也很难让下载可靠地工作,除非我先清除缓冲区。这是一种一直对我有用的技术。

标签: php http-headers force-download


【解决方案1】:

这很难 - 大多数 php 配置将在 30 秒后失败。如果您拥有 php.ini,则可以将其更改为更长的限制。但是——这还值得吗?我的意思是 - 文件可能会变大或网络变慢 - 你会再次遇到超时。

这就是制作下载器的原因 - 以较小的块下载大文件 Half Crazed 向您展示了我 THIS 答案的代码(它不仅仅是一个 - 这仅考虑了客户协商传输的方式之一 -但仍然是一个好的开始)。

例如,Mega.co.nz 使用新的 html5 功能。使用块在浏览器中下载文件,在用户上加入文件,然后从浏览器磁盘空间下载文件。它可以恢复文件,暂停文件等。 (抱歉 - 没有代码,因为它会很大并且包含不止一种语言(php、js))。

PS:把你的readfile($path);改成:

$handle=fopen($path, 'rb');
while (!feof($handle))
{
    echo fread($handle, 8192);
    flush();
}
fclose($handle);

这不会将整个文件加载到内存中,只是一次加载 8KiB 的一部分,然后将它们发送给用户。

【讨论】:

  • 虽然这是非常真实的 - 这是 Apache2 的 Keep-Alive,但还不够高。 (刚刚又看到这个问题,以为我会给你一个答案)
  • 对不起,回答迟了,但keep-alive是出于其他原因使用...大多数服务器会在 60 秒后杀死 php - 即使它仍在发送文件(将被杀死)。并且通常不明智地解除这个限制
【解决方案2】:
   <?php
$filename = "theDownloadedFileIsCalledThis.mp4";
$myFile = "/absolute/path/to/my/file.mp4";

// Add bellow code for mime type
$ext=strtolower(substr($fl,strrpos($myFile,".")));
$mime_types = array(
            '.txt' => 'text/plain',
            '.htm' => 'text/html',
            '.html' => 'text/html',
            '.php' => 'text/html',
            '.css' => 'text/css',
            '.js' => 'application/javascript',
            '.json' => 'application/json',
            '.xml' => 'application/xml',
            '.swf' => 'application/x-shockwave-flash',
            '.flv' => 'video/x-flv',

            // images
            '.png' => 'image/png',
            '.jpe' => 'image/jpeg',
            '.jpeg' => 'image/jpeg',
            '.jpg' => 'image/jpeg',
            '.gif' => 'image/gif',
            '.bmp' => 'image/bmp',
            '.ico' => 'image/vnd.microsoft.icon',
            '.tiff' => 'image/tiff',
            '.tif' => 'image/tiff',
            '.svg' => 'image/svg+xml',
            '.svgz' => 'image/svg+xml',

            // video
            '.3gp' => 'video/3gpp',
            '.3g2' => 'video/3g2',
            '.avi' => 'video/avi',
            '.mp4' => 'video/mp4',
            '.asf' => 'video/asf',
            '.mov' => 'video/quicktime',
        );

if (array_key_exists($ext, $mime_types)){
   $mm_type=$mime_types[$ext];
}else{
   $mm_type="application/octet-stream";
}
$mm_type="application/octet-stream";

header("Cache-Control: public, must-revalidate"); // Avoid this line
header("Pragma: public"); // Add this line
header("Pragma: hack"); // Avoid this line
header("Content-Type: " . $mm_type);
header("Content-Length: " .(string)(filesize($myFile)) ); // Avoid this line
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-Length: ' . filesize($myFile)); // Add this line
header("Content-Transfer-Encoding: binary\n");
ob_clean(); // Add this line

readfile($myFile);

?>

【讨论】:

  • 答案很不清楚。它没有很好的记录。请详细说明“避免”和“添加”,以及为什么。
  • mime 类型的引用很有用,并且标头声明很有意义......“避免”显然意味着“不使用”,“添加”意味着“添加”。他本可以做的就是更好地解释为什么
  • 如果你还是要设置$mm_type="application/octet-stream",所有mime类型的垃圾是怎么回事?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
  • 2010-11-03
相关资源
最近更新 更多