【问题标题】:Browser downloads the file with the PHP file's name who runs the download浏览器使用运行下载的 PHP 文件名下载文件
【发布时间】:2014-06-07 20:03:34
【问题描述】:

我使用 PHP 将下载发送到浏览器。我在名为 download.php 的文件上运行代码。

问题:有时不是下载文件,而是下载相同的文件(相同大小),但名称为download.php。

我还注意到,当我尝试使用Internet Download Manager 下载它时,我看到名称download.php 大约半秒钟,然后名称变为真实名称。

图片说明:

代码:

//First, see if the file exists
if (!is_file($file)) {
    header("HTTP/1.1 400 Invalid Request");
    die("<h3>File Not Found</h3>");
}

//Gather relevent info about file
$size = filesize($file);
$fileinfo = pathinfo($file);

//workaround for IE filename bug with multiple periods / multiple dots in filename
//that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe
$filename = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ?
              preg_replace('/\./', '%2e', $fileinfo['basename'], substr_count($fileinfo['basename'], '.') - 1) :
              $fileinfo['basename'];

$file_extension = strtolower($fileinfo['extension']);

//This will set the Content-Type to the appropriate setting for the file
switch($file_extension)
{
    case 'exe': $ctype='application/octet-stream'; break;
    case 'zip': $ctype='application/zip'; break;
    case 'mp3': $ctype='audio/mpeg'; break;
    case 'mpg': $ctype='video/mpeg'; break;
    case 'avi': $ctype='video/x-msvideo'; break;
    default:    $ctype='application/force-download';
}

//check if http_range is sent by browser (or download manager)
if($is_resume && isset($_SERVER['HTTP_RANGE']))
{
    $arr = explode('=', $_SERVER['HTTP_RANGE'], 2);
    if(isset($arr[1]))   
        list($size_unit, $range_orig) = $arr;
    else list($size_unit) = $arr;

    if ($size_unit == 'bytes')
    {
        //multiple ranges could be specified at the same time, but for simplicity only serve the first range
        //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
        $arr3 = explode(',', $range_orig, 2);
        if(isset($arr3[1]))
            list($range, $extra_ranges) = $arr3;
        else
            list($range) = $arr3;
    }
    else
    {
        $range = '';
    }
}
else
{
    $range = '';
}

//figure out download piece from range (if set)
$arr2 = explode('-', $range, 2);
if(isset($arr2[1]))
    list($seek_start, $seek_end) = $arr2;
else
    list($seek_start) = $arr2;

//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);

//add headers if resumable
if ($is_resume)
{
    //Only send partial content header if downloading a piece of the file (IE workaround)
    if ($seek_start > 0 || $seek_end < ($size - 1))
    {
        header('HTTP/1.1 206 Partial Content');
    }

    header('Accept-Ranges: bytes');
    header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size);
}

//headers for IE Bugs (is this necessary?)
//header("Cache-Control: cache, must-revalidate");   
//header("Pragma: public");

header('Content-Type: ' . $ctype);
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: '.($seek_end - $seek_start + 1));

//reset time limit for big files
set_time_limit(0);
ignore_user_abort(true);

//open the file
$fp = fopen($file, 'rb');

//seek to start of missing part
fseek($fp, $seek_start);

//start buffered download
while(!feof($fp))
{
    print(fread($fp, 1024*8));
    flush();
    ob_flush();        
}

fclose($fp);
exit;

【问题讨论】:

    标签: php download fread


    【解决方案1】:

    我找到了解决办法!

    我做了一个 htaccess RewriteRule。比如文件id是a1a2,文件名是foo.mp4,我把URL改成:download/a1a2/foo.mp4。

    ht访问代码:

    RewriteEngine on
    RewriteRule ^download/(.*)/(.*)?$ download.php?id=$1&fileName=$2 [QSA,NC,L]
    

    就这么简单!

    【讨论】:

      【解决方案2】:

      您可以按照the official PHP manual here 中的说明设置适当的标头来做到这一点:

      // We'll be outputting a PDF
      header('Content-type: application/pdf');
      
      // It will be called downloaded.pdf
      header('Content-Disposition: attachment; filename="downloaded.pdf"');
      

      也就是说,看看您的代码,您似乎已经在此处介绍了标头内容:

      header('Content-Type: ' . $ctype);
      header('Content-Disposition: attachment; filename="' . $filename . '"');
      header('Content-Length: '.($seek_end - $seek_start + 1));
      

      所以我认为唯一可能是问题与您的代码中的列表 mime 类型有关:

      //This will set the Content-Type to the appropriate setting for the file
      switch($file_extension)
      {
          case 'exe': $ctype='application/octet-stream'; break;
          case 'zip': $ctype='application/zip'; break;
          case 'mp3': $ctype='audio/mpeg'; break;
          case 'mpg': $ctype='video/mpeg'; break;
          case 'avi': $ctype='video/x-msvideo'; break;
          default:    $ctype='application/force-download';
      }
      

      可能是浏览器或您使用的 IDM 下载软件无法识别您设置的 mime 类型(在您的代码中为:$ctype)。所以它默认为application/force-download。

      我还强烈建议重构您的 switch,使其使用简单的关联数组逻辑像这样工作:

      // This will set the Content-Type to the appropriate setting for the file
      $ctype_array = array();
      $ctype_array['exe'] = 'application/octet-stream';
      $ctype_array['zip'] = 'application/zip';
      $ctype_array['mp3'] = 'audio/mpeg';
      $ctype_array['mpg'] = 'video/mpeg';
      $ctype_array['avi'] = 'video/x-msvideo';
      
      // Check if the file extension is in $ctype_array & return the value. If not, send default.
      $ctype = array_key_exists($file_extension, $ctype_array) ? $ctype_array[$file_extension] : 'application/force-download';
      

      这样您就可以轻松地向$ctype_array 添加更多项目,而无需处理switch/case 的逻辑。

      【讨论】:

      • 我试过了,我添加了文件的mine-type,但它仍然发生。
      • 奇数。可能是您的 PC 和服务器之间有一些您不知道的代理?
      • 感谢您的帮助,但我找到了解决方案。我刚刚对download.php 做了一个htaceess 重写规则,并将文件名放在了URL 的末尾。例如:将download.php?id=123 改为download/123/{File_Name}。
      • @ArielAharonson 这是一个很酷的解决方案!而且是有道理的。 download.php 始终是发送给客户端的第一件事,因此前一秒是 download.php,然后是实际文件是有道理的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-06-16
      • 1970-01-01
      • 1970-01-01
      • 2011-07-25
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      相关资源
      最近更新 更多