Sates
Sates

Reputation: 408

The file can not be opened, downloaded or is corrupted when forcing its download

This is how my webhosting scheme looks like:

enter image description here

This is the code I'm having problems with, trying to force a file to be downloaded:

$fetch_file = $set_query->fetch_assoc();
$file = "../library/".$fetch_file["file_name"];
if (file_exists($file) && is_file($file)) {
if(ini_get('zlib.output_compression')) {       
    ini_set('zlib.output_compression', 'Off'); 
}
header('Content-Length: ' . filesize($file));
header('Pragma: public');
header('Expires: 0');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=\"'.basename($file).'\"');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Connection: close');
ob_end_flush();
ob_end_clean();
readfile($file);
exit;

The download dialog actually pops up but I get an error from my browser saying that it was unable to read, and as a result, unable to open or download.

I tried to put ob_end_flush() and ob_end_clean() before the headers but it didn't work out. I don't know why the download dialog properly shows the file to download but says it can't be read nor opened.

I managed to fix that by using:

// digital_lub/JKAJSD831.pdf
$file = UPLOAD_PATH.$fetch_file["file_name"];

The dialog opens and downloads the file now but it won't open locally, saying it's corrupted. When I open it as text, it contains the HTML of my page.

My download page is requested by being included in index.php via an .htaccess url rewrite. This is index.php:

<?
require_once("constructor.php");
$smarty->display("page_index");
if (isset($_GET["page"])) {

    $page = htmlspecialchars($_GET["page"]);
    $setPageFile = "module/".$page.".php";

    if (file_exists($setPageFile)) {
        include($setPageFile);
    } else {
        $smarty->assign("alert", array(1, "Żądany moduł nie jest obsługiwany."));
    }
} else {
    Header("Location: login");
}
$smarty->display("page_footer");
?>

Upvotes: 0

Views: 1991

Answers (3)

spenibus
spenibus

Reputation: 4409

Essentially your problem is that you send more data than just your file. Since your page is actually included in another page, which displays some header before reaching any kind of download logic, that extra HTML becomes part of your downloaded file, corrupting it.

There are two steps to avoid this:

  1. Remove ob_end_flush(), as it would still flush the buffer to the client and you clearly don't want that, and leave only ob_end_clean(), which will destroy whatever is in the buffer.

  2. In your top most document index.php, which includes the subpages (such as your download page), put ob_start() at the very beginning to capture absolutely all output and add ob_end_flush() at the very end to output your content.

This creates 2 execution paths:

  • Save output, generate page, flush output thus displaying the page.
  • Save output, trigger download, destroy output, send file data, exit early.

This ensures that only your file's data is sent to the client.

This is a basic example of this logic:

  • index.php:

    <?php
    ob_start();
    echo '__HEADER__';
    require('page.php');
    echo '__FOOTER__';
    ob_end_flush();
    ?>
    
  • page.php:

    <?php
    ob_end_clean();
    readfile('test.txt');
    exit();
    ?>
    
  • test.txt:

    __TEST__
    

This should only output __TEST__.

Upvotes: 2

Halayem Anis
Halayem Anis

Reputation: 7805

You must specify the file extension/type, browser will not guess it :)
Here, a PHP script that you can customize if your server can handle more type of files.

<?php
    //---------------------------------------------------------
    //----------------- MIME TYPE DEFINITION ------------------
    //---------------------------------------------------------
    $mimeType = array() ;

    #[text]
    $mimeType["txt"]    = "text/plain" ;
    $mimeType["sql"]    = "text/plain" ;
    $mimeType["htm"]    = "text/html" ;
    $mimeType["html"]   = "text/html" ;
    $mimeType["css"]    = "text/css" ;

    #[image]
    $mimeType["png"]    = "image/png" ;
    $mimeType["gif"]    = "image/gif" ;
    $mimeType["jpg"]    = "image/jpeg" ;
    $mimeType["jpeg"]   = "image/jpeg" ;
    $mimeType["bmp"]    = "image/bmp" ;
    $mimeType["tif"]    = "image/tiff" ;

    #[archives]
    $mimeType["bz2"]    = "application/x-bzip" ;
    $mimeType["gz"]     = "application/x-gzip" ;
    $mimeType["tar"]    = "application/x-tar";
    $mimeType["zip"]    = "application/zip";

    #[audio]
    $mimeType["aif"]    = "audio/aiff";
    $mimeType["aiff"]   = "audio/aiff";
    $mimeType["mid"]    = "audio/mid" ;
    $mimeType["midi"]   = "audio/mid";
    $mimeType["mp3"]    = "audio/mpeg" ;
    $mimeType["ogg"]    = "audio/ogg" ;
    $mimeType["wav"]    = "audio/wav" ;
    $mimeType["wma"]    = "audio/x-ms-wma" ;

    #[video]
    $mimeType["asf"]    = "video/x-ms-asf" ;
    $mimeType["asx"]    = "video/x-ms-asf" ;
    $mimeType["avi"]    = "video/avi" ;
    $mimeType["mpg"]    = "video/mpeg" ;
    $mimeType["mpeg"]   = "video/mpeg" ;
    $mimeType["wmv"]    = "video/x-ms-wmv" ;
    $mimeType["wmx"]    = "video/x-ms-wmx" ;

    #[xml]
    $mimeType["xml"]    = "text/xml" ;
    $mimeType["xsl"]    = "text/xsl" ;

    #[microsoft]
    $mimeType["doc"]    = "application/msword" ;
    $mimeType["docx"]   = "application/msword" ;
    $mimeType["rtf"]    = "application/msword" ;
    $mimeType["xls"]    = "application/excel" ;
    $mimeType["xlsm"]   = "application/excel" ;
    $mimeType["xlt"]    = "application/excel" ;
    $mimeType["xlsx"]   = "application/excel" ;
    $mimeType["pps"]    = "application/vnd.ms-powerpoint" ;
    $mimeType["ppt"]    = "application/vnd.ms-powerpoint" ;

    #[adobe]
    $mimeType["pdf"]    = "application/pdf" ;
    $mimeType["ai"]     = "application/postscript" ;
    $mimeType["eps"]    = "application/postscript" ;
    $mimeType["psd"]    = "image/psd" ;

    #[macromedia]
    $mimeType["swf"]    = "application/x-shockwave-flash" ;

    #[real]
    $mimeType["ra"]     = "audio/vnd.rn-realaudio" ;
    $mimeType["ram"]    = "audio/x-pn-realaudio" ;
    $mimeType["rm"]     = "application/vnd.rn-realmedia" ;
    $mimeType["rv"]     = "video/vnd.rn-realvideo" ;

    #[other]
    $mimeType["exe"]    = "application/x-msdownload" ;
    $mimeType["pls"]    = "audio/scpls" ;
    $mimeType["m3u"]    = "audio/x-mpegurl" ;
    // <--

    //---------------------------------------------------------
    //----------- INITIALIZING DOWNLOAD PROCESS ---------------
    //---------------------------------------------------------
    $fileToUpload; // TODO! $_REQUEST['PATH/TO/FILE/FILENAME.FILEEXTENSION'] ??
    if (strlen(trim($file_to_upload_s)) == 0) {
        print '[ERROR] file name is empty' ;
        return ;
    }
    $fileExtension = pathinfo($fileToUpload, PATHINFO_EXTENSION );
    $fileExtension = strtolower($fileExtension);
    if (strlen(trim($fileExtension)) == 0) {
        print '[ERROR] file extension is not mentioned' ;
        return ;
    }

    if(array_key_exists($fileExtension, $mimeType ) === FALSE ) {
        print '[ERROR] server does not support this file extension [' . $fileExtension . '], configuration is missing' ;
        return;
    } 

    //---------------------------------------------------------
    //------------- STARTING DOWNLOAD PROCESS -----------------
    //---------------------------------------------------------
    header('Content-Type: ' . $mimeType[$fileExtension]);
    header('Content-Disposition: attachment; filename="' . $fileToUpload . '"');
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . filesize($fileToUpload));
    header('Accept-Ranges: bytes');
    header('Cache-Control: private');
    header('Pragma: private');
    header('Expires: Mon, 1 Jan 1970 00:00:00 GMT');
    readfile($fileToUpload);
?>

Upvotes: 0

Nikhil Malik
Nikhil Malik

Reputation: 478

I tried it and you didn't closed your if bracket ;), i am sure it is not the reason, you missed it here but when i tried it, i am able to download file.
File was png, you can manually try for a file with php script, if it's not then it can be your server permission issue.

Upvotes: 0

Related Questions