V1GG3N
V1GG3N

Reputation: 309

force file download of msword failing

I currently have the following:

if (headers_sent()) {

    echo 'HTTP header already sent';
} else {
    if (!is_file($path)) {
        header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
        echo 'File not found';
    } else if (!is_readable($path)) {
        header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
        echo 'File not readable';
    } else {
        ob_start();
        header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
        header('Content-Description: File Transfer');
        header("Content-Type: octet-stream");
        header("Content-Transfer-Encoding: binary");
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header("Content-Length: ".filesize($path));
        header("Content-Disposition: attachment; filename=\"".basename($path)."\"");
        ob_clean();
        ob_flush();
        readfile($path);

        exit;

The above code produces a file download of the correct file name, but with a twist.

The downloaded file has some html from the download page (headers being sent incorrectly?) then later in the downloaded document there is gibberish text (ex. OJQJ^J.??. WW8Num2z0) taking up several pages. Finally at the end of the .doc I can read some English which appears to be the correct text of the .doc, but with no formatting.

These issues persist in Chrome and Mozilla.

Any help would be greatly appreciated. Thanks in advance.

EDIT:

I began testing with a .doc that has only one line of text: "test"

The file can be opened manually from the directory in which it is uploaded to, and verified that it is not corrupt. However, downloading this file using any of the methods recommended thus far yields several pages of gibberish text (the real file is only 1 line). The actual text of the file, which is "test", is found on the very last of the 66 pages of gibberish, and it is found in this haystack: ?test ?"ᄚ? ᄚ?!ᄚn"ᄚn#ミn$ミn3P(20???՜.モラ+,??՜.モラ+,???Root Entry???????? ?F@CompObj????jOle ????????1Table????????????ᆬSummaryInformation(?????WordDocument????????????"$DocumentSummaryInformation8????????????[t????????????????

Upvotes: 0

Views: 776

Answers (2)

Kartik
Kartik

Reputation: 9853

Try this excerpt for the last else that is without any flushing functions

header("HTTP/1.1 200 OK");
header("Pragma: public"); 
header("Expires: 0"); 
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 
header("Content-Type: application/force-download"); 
header("Content-Disposition: attachment; filename=".basename($path));
header("Content-Description: File Transfer"); 
@readfile($path); 

Upvotes: 1

CodeCaster
CodeCaster

Reputation: 151594

What are these?

    header("Content-Type: octet-stream");
    header("Content-Transfer-Encoding: binary");

Trim down your code to a working example and extend it from there. You do not need to set the status code, PHP does this for you. You do not need to set the Content-length either. Sending only this should just work:

$path = 'foo.dat';

if (headers_sent()) {
    echo 'HTTP header already sent';
} else {
    if (!is_file($path)) {
        header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
        echo 'File not found';
    } else if (!is_readable($path)) {
        header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
        echo 'File not readable';
    } else {
        header("Content-Disposition: attachment; filename=\"".basename($path)."\"");
        readfile($path);
    }
}

Upvotes: 1

Related Questions