文件下载的 HTTP 标头

2022-01-02 00:00:00 http-headers download content-type php

我编写了一个 PHP 脚本来处理文件下载,确定正在请求哪个文件并设置正确的 HTTP 标头以触发浏览器实际下载文件(而不是在浏览器中显示它).

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).

我现在遇到一个问题,一些用户报告某些文件被错误识别(因此无论扩展名如何,浏览器都会将其视为 GIF 图像).我猜这是因为我没有设置内容类型"在响应头中.这是最有可能的情况吗?如果是这样,是否有一种可以用于所有文件的相当通用的类型,而不是试图解释每种可能的文件类型?

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). 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?

目前我只设置值Content-disposition:attachment;文件名=arandomf.ile"

Currently I'm only setting the value "Content-disposition: attachment; filename=arandomf.ile"

更新:我在这里按照本指南构建了一个更强大的文件下载流程(http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/),但在脚本执行和浏览器的下载对话框出现之间存在明显的延迟.任何人都可以确定导致这种情况的瓶颈吗?

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. Can anyone identify the bottleneck that is causing this?

这是我的实现:

/**
 * 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);
        }
    }
}

推荐答案

根据 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

所以我会选择那个.

相关文章