Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP force downloading .xlsx file corrupt

I am working on a site that allows teachers to upload documents and students download them. However, there is a problem. Microsoft Word (.docx) files download perfectly, but when downloading an excel (xlsx) file, excel gives a "This file is corrupt and cannot be opened" dialog. Any help with this would be greatly appreciated!

My download code is as follows:

case 'xlsx':

    header('Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Pragma: no-cache');
    readfile('./uploads/resources/courses/' . $filename);

break;
like image 656
cbenjafield Avatar asked Dec 18 '12 17:12

cbenjafield


2 Answers

I have this problem and was the BOM.

How to notice it

unzip: Checking the output file with unzip, I saw a warning at the second line.

$ unzip -l file.xlsx 
Archive:   file.xlsx
warning file:  3 extra bytes at beginning or within zipfile
...

xxd (hex viewer): I saw the first 5 bytes with the following command

head -c5 file.xlsx | xxd -g 1
0000000: ef bb bf 50 4b                             PK...

Notice the 3 first bytes ef bb bf that's BOM!

Why?

Maybe a php file with BOM or a previous output from a library.

You have to find where is the file or command with the BOM, In my case and right now, I don't have time to find it, but I solve this with output buffer.

<?php
ob_start();

// ... code, includes, etc

ob_get_clean();
// headers ...
readfile($file);
like image 162
Felipe Buccioni Avatar answered Sep 22 '22 17:09

Felipe Buccioni


this works fine on my local xampp setup regardless of extension so from my point of view no case statement is needed unless i'm missing something

i've tested with docx, accdb, xlsx, mp3, anything ...

$filename = "equiv1.xlsx";

header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Pragma: no-cache');
like image 32
cristi _b Avatar answered Sep 21 '22 17:09

cristi _b