Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I fix this PHP download script, which is corrupting files?

Tags:

php

download

I have a force-download script that produces good results with PDF and plain text, and is semi-OK with ZIP archives (they work in Windows, not in Linux). However, application files and images all fail. These make up the vast majority of the files I must handle. Zipping all downloads, as I've seen suggested on similar topics here, is not an option.

The failing files download to their full size, and are written to disk under the correct name. Attempts to open them result in a error message, which differs between types. Comparing downloaded files to their originals in hexdump, I can see that the script inserts the following characters at the start of each downloaded file:

ef bb bf

The downloaded file then reproduces the original until it stops at its specified size - so the original's last 6 characters are always missing.

Unfortunately I know nothing about how binary files are made up, what these characters might mean, or how/why the script is inserting them.

This is the script as-is:

$file = '94.ppt';
$path = $_SERVER['DOCUMENT_ROOT']."/relative/path/";
$full_path = $path.$file;
if ($fd = fopen ($full_path, "r")) {
    $fsize = filesize($full_path);
    $path_parts = pathinfo($full_path);
    $ext = strtolower($path_parts["extension"]);
    switch ($ext) {
        case "pdf":
            header("Content-type: application/pdf");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        case "txt":
            header("Content-type: text/plain");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        case "jpg":
            header("Content-type: image/jpeg");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        case "ppt":
            header("Content-Type: application/vnd.ms-powerpoint");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        default;
            header("Content-type: application/octet-stream");
            header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
    }
    header("Content-Transfer-Encoding: binary");
    header("Content-length: $fsize");
    header("Cache-control: private");
    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
}
fclose ($fd);
exit;

The development system is PHP 5.3.2-1 on Apache 2.2.14 (Ubuntu). The production host is PHP 5.2.9 on Apache 2.0.63 (some type of Linux).

like image 707
hnmcc Avatar asked Feb 24 '23 21:02

hnmcc


2 Answers

Your PHP script file seems to be encoded in UTF-8 with BOM that is right at the begin of the file before the opening <?php delimiter. These bytes are sent before your actual output and thus corrupting your data.

You just need to remove it and configure your editor not to use the BOM for UTF-8.

like image 86
Gumbo Avatar answered Apr 27 '23 03:04

Gumbo


EF BB BF is the standard UTF-8 byte order mark. Some people have reported that this happens when some of your PHP files that you include in the script are UTF-8 encoded; some versions of PHP react to this by sending out the UTF-8 byte order marker. The link above suggests calling ob_start() at the beginning of the script and ob_end_clean() before you start pushing out the contents of your file -- this way the byte order marker gets caught in the output buffer.

Also, you could simply use fpassthru to pipe your file to the output instead of reading and writing in a loop.

like image 44
Tamás Avatar answered Apr 27 '23 03:04

Tamás