4

I have an excel file that i want a user to be able to download from my server. I have looked at a lot of questions on here but i cannot find a way to correctly download the file w/o corruption. I am assuming it is the headers but i haven't had a working combination of them yet. This is what i have right now and in the corrupt file that i receive i can see the column names of the spreadsheet i want but its all messed up.

$filename = '/var/www/web1/web/public/temporary/Spreadsheet.xls';        
header("Content-type: application/octet-stream");
header("Content-type: application/vnd-ms-excel");
header("Content-Disposition: attachment; filename=ExcelFile.xls;");
header("Pragma: no-cache");
header("Expires: 0");
readfile($filename);

edit: Solution I forgot to add that i was using Zend and it was corrupting the files when trying to use native php methods. My finsihed code was to place a link to another action in my controller and have the files download from there

public function downloadAction(){
        $file = '/var/www/web1/web/public/temporary/Spreadsheet.xls';
        header('Content-Type: application/vnd.ms-excel');
    header('Content-Disposition: attachment; filename="Spreadsheet.xls"');
    readfile($file);

    // disable the view ... and perhaps the layout
    $this->view->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender(true);


    }
rubio
  • 936
  • 5
  • 16
  • 36
  • by downloading I guess you mean displaying in the browser? Rather than a straight file download – Marc Costello Jan 31 '12 at 17:26
  • 1
    outputting 2 content headers is pointless - a file cannot be two things at once. it's like saying "I'm a giraffe and a whale!". – Marc B Jan 31 '12 at 17:26
  • 1
    By a long, long way the most common answer(s) to these kind of questions is down to either: a) you have leading/trailing whitespace/HTML before/after the `` tags in your script or a BOM in your file or b) you forgot to call `exit`/`die` after the `readfile()` and more content was output on the end of your file data. – DaveRandom Jan 31 '12 at 17:27
  • @MarcCostello I mean a straight download. – rubio Jan 31 '12 at 19:04
  • @DaveRandom i was missing an exit on my statement which would stop me from getting the file all together but the file still comes out corrupt. – rubio Jan 31 '12 at 19:19
  • @user915946 You should remove the `Content-Type` and `Content-Disposition` headers so you can view the file's raw data in a browser. You should then compare this with the output you get from downloading the file directly from the web server (bypassing PHP) and see what the difference/where the corruption is occurring. Do you have an example link you can provide us where we can download the corrupt data to inspect it? – DaveRandom Jan 31 '12 at 19:47
  • The corruption was because i was using zend and it wouldnt accept the php native method of downloading the file. Thank you for your help DaveRandom – rubio Jan 31 '12 at 20:07

3 Answers3

6

try doing it this way

 ob_get_clean();
 echo file_get_contents($filename);
 ob_end_flush();
mdprotacio
  • 842
  • 6
  • 18
  • yeah the php script was adding some whitespaces at the beginning and images files became corrupted on downloading, ob_get_clean() fixed it. thanks! – Alexandru Trandafir Catalin Sep 29 '14 at 07:45
  • i'm getting error message like ob_end_flush(): failed to delete and flush buffer. No buffer to delete or flush in file_path.Please suggest me what to do @Melvin Protacio – lalithkumar Apr 19 '17 at 13:16
1
$file_name = "file.xlsx";

// first, get MIME information from the file
$finfo = finfo_open(FILEINFO_MIME_TYPE); 
$mime =  finfo_file($finfo, $file_name);
finfo_close($finfo);

// send header information to browser
header('Content-Type: '.$mime);
header('Content-Disposition: attachment;  filename="download_file_name.xlsx"');
header('Content-Length: ' . filesize($file_name));
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');

//stream file
ob_get_clean();
echo file_get_contents($file_name);
ob_end_flush();
Bhavesh G
  • 3,000
  • 4
  • 39
  • 66
1

For one, only specify Content-Type once. You can use the excel-specific header but the generic application/octet-stream may be a safer bet just to get it working (the real difference will be what the browser shows the user with regards to "what would you like to open this file with", but basic browsers can rely on the extension as well)

Also, make sure you specify Content-Length and dump the size (in bytes) of the file you're outputting. The browser needs to know how big the file is and how much content it's expecting to receive (so it doesn't stop in the middle or a hiccup doesn't interrupt the file download).

So, the entire file should consist of:

<?php
  $filename = '/var/www/web1/web/public/temporary/Spreadsheet.xls';

  header("Content-Disposition: attachment; filename=ExcelFile.xls;");
  header('Content-Type: application/octet-stream');
  header('Content-Length: ' . filesize($filename));
  header("Pragma: no-cache");
  header("Expires: 0");

  @readfile($filename);
Community
  • 1
  • 1
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
  • I used both ocetet-stream and both return the same thing. I was missing and exit statement but the file still is corrupt. – rubio Jan 31 '12 at 19:20
  • @user: To confirm, the file (when downloaded using an FTP client) works fine? It's only when you're trying to pass it through PHP as a download that it corrupts? – Brad Christie Jan 31 '12 at 19:27
  • Yes, i downloaded it though ftp to check and it works fine. I am using zend as well if that is an issue. – rubio Jan 31 '12 at 19:39
  • I solved the problem. It was because of zend. But i needed to use vnd.-msexcel which you mentioned. Thanks – rubio Jan 31 '12 at 20:05