简体   繁体   English

文件下载的 HTTP 标头

[英]HTTP Headers for File Downloads

I've written a PHP script that handles file downloads, determining which file is being requested and setting the proper HTTP headers to trigger the browser to actually download the file (rather than displaying it in the browser).我编写了一个处理文件下载的 PHP 脚本,确定正在请求哪个文件并设置正确的 HTTP 标头以触发浏览器实际下载文件(而不是在浏览器中显示它)。

I now have a problem where some users have reported certain files being identified incorrectly (so regardless of extension, the browser will consider it a GIF image).我现在遇到一个问题,一些用户报告某些文件被错误识别(因此无论扩展名如何,浏览器都会将其视为 GIF 图像)。 I'm guessing this is because I haven't set the "Content-type" in the response header.我猜这是因为我没有在响应头中设置“内容类型”。 Is this most likely the case?这是最有可能的情况吗? If so, is there a fairly generic type that could be used for all files, rather than trying to account for every possible file type?如果是这样,是否有一种可用于所有文件的相当通用的类型,而不是试图考虑每种可能的文件类型?

Currently I'm only setting the value "Content-disposition: attachment; filename=arandomf.ile"目前我只设置值“内容处置:附件;文件名=arandomf.ile”

Update: I followed this guide here to build a more robust process for file downloads ( http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/ ), but there is a significant delay between when the script is executed and when the browser's download dialog appears.更新:我在这里按照本指南构建了一个更强大的文件下载过程( http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/ ) ,但在执行脚本和出现浏览器的下载对话框之间存在明显的延迟。 Can anyone identify the bottleneck that is causing this?任何人都可以确定导致这种情况的瓶颈吗?

Here's my implementation:这是我的实现:

/**
 * Outputs the specified file to the browser.
 *
 * @param string $filePath the path to the file to output
 * @param string $fileName the name of the file
 * @param string $mimeType the type of file
 */
function outputFile($filePath, $fileName, $mimeType = '') {
    // Setup
    $mimeTypes = array(
        'pdf' => 'application/pdf',
        'txt' => 'text/plain',
        'html' => 'text/html',
        'exe' => 'application/octet-stream',
        'zip' => 'application/zip',
        'doc' => 'application/msword',
        'xls' => 'application/vnd.ms-excel',
        'ppt' => 'application/vnd.ms-powerpoint',
        'gif' => 'image/gif',
        'png' => 'image/png',
        'jpeg' => 'image/jpg',
        'jpg' => 'image/jpg',
        'php' => 'text/plain'
    );
    
    $fileSize = filesize($filePath);
    $fileName = rawurldecode($fileName);
    $fileExt = '';
    
    // Determine MIME Type
    if($mimeType == '') {
        $fileExt = strtolower(substr(strrchr($filePath, '.'), 1));
        
        if(array_key_exists($fileExt, $mimeTypes)) {
            $mimeType = $mimeTypes[$fileExt];
        }
        else {
            $mimeType = 'application/force-download';
        }
    }
    
    // Disable Output Buffering
    @ob_end_clean();
    
    // IE Required
    if(ini_get('zlib.output_compression')) {
        ini_set('zlib.output_compression', 'Off');
    }
    
    // Send Headers
    header('Content-Type: ' . $mimeType);
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Content-Transfer-Encoding: binary');
    header('Accept-Ranges: bytes');
    
    // Send Headers: Prevent Caching of File
    header('Cache-Control: private');
    header('Pragma: private');
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    
    // Multipart-Download and Download Resuming Support
    if(isset($_SERVER['HTTP_RANGE'])) {
        list($a, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
        list($range) = explode(',', $range, 2);
        list($range, $rangeEnd) = explode('-', $range);
        
        $range = intval($range);
        
        if(!$rangeEnd) {
            $rangeEnd = $fileSize - 1;
        }
        else {
            $rangeEnd = intval($rangeEnd);
        }
        
        $newLength = $rangeEnd - $range + 1;
        
        // Send Headers
        header('HTTP/1.1 206 Partial Content');
        header('Content-Length: ' . $newLength);
        header('Content-Range: bytes ' . $range - $rangeEnd / $fileSize);
    }
    else {
        $newLength = $fileSize;
        header('Content-Length: ' . $fileSize);
    }
    
    // Output File
    $chunkSize = 1 * (1024*1024);
    $bytesSend = 0;
    
    if($file = fopen($filePath, 'r')) {
        if(isset($_SERVER['HTTP_RANGE'])) {
            fseek($file, $range);
            
            while(!feof($file) && !connection_aborted() && $bytesSend < $newLength) {
                $buffer = fread($file, $chunkSize);
                echo $buffer;
                flush();
                $bytesSend += strlen($buffer);
            }
            
            fclose($file);
        }
    }
}

As explained by Alex's link you're probably missing the header Content-Disposition on top of Content-Type .正如 Alex 的链接所解释的那样,您可能缺少Content-Type顶部的标题Content-Disposition

So something like this:所以像这样:

Content-Disposition: attachment; filename="MyFileName.ext"

Acoording to RFC 2046 (Multipurpose Internet Mail Extensions) :根据RFC 2046(多用途 Internet 邮件扩展)

The recommended action for an implementation that receives an收到一个实施的推荐操作
"application/octet-stream" entity is to simply offer to put the data in a file “应用程序/八位字节流”实体只是提供将数据放入文件中

So I'd go for that one.所以我会去那个。

You can try this force-download script .你可以试试这个强制下载脚本 Even if you don't use it, it'll probably point you in the right direction:即使您不使用它,它也可能会为您指明正确的方向:

<?php

$filename = $_GET['file'];

// required for IE, otherwise Content-disposition is ignored
if(ini_get('zlib.output_compression'))
  ini_set('zlib.output_compression', 'Off');

// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));

if( $filename == "" ) 
{
  echo "<html><title>eLouai's Download Script</title><body>ERROR: download file NOT SPECIFIED. USE force-download.php?file=filepath</body></html>";
  exit;
} elseif ( ! file_exists( $filename ) ) 
{
  echo "<html><title>eLouai's Download Script</title><body>ERROR: File not found. USE force-download.php?file=filepath</body></html>";
  exit;
};
switch( $file_extension )
{
  case "pdf": $ctype="application/pdf"; break;
  case "exe": $ctype="application/octet-stream"; break;
  case "zip": $ctype="application/zip"; break;
  case "doc": $ctype="application/msword"; break;
  case "xls": $ctype="application/vnd.ms-excel"; break;
  case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
  case "gif": $ctype="image/gif"; break;
  case "png": $ctype="image/png"; break;
  case "jpeg":
  case "jpg": $ctype="image/jpg"; break;
  default: $ctype="application/octet-stream";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers 
header("Content-Type: $ctype");
// change, added quotes to allow spaces in filenames, by Rajkumar Singh
header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
exit();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM