title: Browser downloads the file with the PHP file's name who runs the download
body: <p>I use PHP to send download to the browser. I run the code on a file named <code>download.php</code>.</p>
  
  <p>The problem: sometimes instead of download the file, it's downloads the same file (same size), but with the name <code>download.php</code>.</p>
  
  <p>I also noticed that when I try to download it with <a href="http://www.internetdownloadmanager.com" rel="nofollow noreferrer">Internet Download Manager</a>, I see the name <code>download.php</code> for about half second, and then the name changes to the real name.</p>
  
  <p>Pictures to explain:
  <img src="https://i.stack.imgur.com/ZwxI8.png" alt="I see it for about half second">
  <img src="https://i.stack.imgur.com/ckeSx.png" alt="Then I see the correct file name"></p>
  
  <p>The code:</p>
  
  <pre><code>//First, see if the file exists
  if (!is_file($file)) {
      header("HTTP/1.1 400 Invalid Request");
      die("&lt;h3&gt;File Not Found&lt;/h3&gt;");
  }
  
  //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']) &amp;&amp; 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 &amp;&amp; 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 &lt; 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 &gt; 0 || $seek_end &lt; ($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;
  </code></pre>