Why is my downloaded file is always damaged or corrupted?

22,943

Solution 1

That seems allot of code just to force-download, here is a nice function I use all the time. It will handle files over 2GB too.

<?php 
$file_id = (isset($_GET['id']) && (int)$_GET['id'] != 0) ? (int)$_GET['id'] : exit;

/*finding file info*/
$file = comon::get_all_by_condition('files', 'id', $file_id);
$path = $file['location'] . '/' . $file['file_name'];

if (!is_file($path)) {
    echo 'File not found.('.$path.')';
} elseif (is_dir($path)) {
    echo 'Cannot download folder.';
} else {
    send_download($path);
}

return;

//The function with example headers
function send_download($file) {
    $basename = basename($file);
    $length   = sprintf("%u", filesize($file));

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $basename . '"');
    header('Content-Transfer-Encoding: binary');
    header('Connection: Keep-Alive');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . $length);

    set_time_limit(0);
    readfile($file);
}
?>

Solution 2

    if (file_exists($file)) {
set_time_limit(0);
        header('Connection: Keep-Alive');
    header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="'.basename($file).'"');
            header('Content-Transfer-Encoding: binary');
            header('Expires: 0');
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header('Pragma: public');
            header('Content-Length: ' . filesize($file));
            ob_clean();
            flush();
            readfile($file);


}

Solution 3

Very nice, helpful also...

but there is a problem in your code -

header('Content-Disposition: attachment;
filename="'.basename($file).'"';

please change it with this following -

header('Content-Disposition: attachment;
filename="'.basename($file).'"');

you are forgot to close it.

Solution 4

Your script may contain NOTICE or WARNING, try disabling error reporting on top of your script:

error_reporting(0);
Share:
22,943
max
Author by

max

Updated on March 21, 2020

Comments

  • max
    max about 4 years

    I have a very weird problem with my download script

    it basically

    1.gets a file id with "GET" method

    2.gets the name and location of that file from database

    3.sends it to the client with the headers and readfile

    but strangely that file always comes out as corrupted or damaged

    like if it's a zip or rar file file size is right and it opens ok

    but i cant open compressed files inside of it and that's when i get the file damaged error

    which is weird cuz if the code had a problem i shouldn't even be able to open the zip file(or at least i think i shouldn't)

    another thing is i've printed out the file with it's path right before sending the headers just to be sure everything is ok

    I've put the file address on the url and download the file , file was ok with no errors

    so everything is fine before sending the headers

    here is my code

            $file_id = isset($_GET['id']) && (int)$_GET['id'] != 0 ? (int)$_GET['id'] : exit;
            
            
            //////// finging file info
            $file = comon::get_all_by_condition('files' , 'id' , $file_id );
            if(!$file) exit;
            foreach($file as $file){
            $location = $file['location'];
            $filename = $file['file_name'];
            }
            /////////////
    
    
            $site = comon::get_site_domian();
            
            $ext = trim(end(explode('.' , $filename )));
            $abslout_path = 'http://'.$site.'/'.$location.'/'.$filename;
            $relative = $location.'/'.$filename;
            
    
        
        ////////////////// content type 
                switch($ext) {
                case 'txt':
                    $cType = 'text/plain'; 
                break;              
                case 'pdf':
                    $cType = 'application/pdf'; 
                break;
        
                case 'zip':
                    $cType = 'application/zip';
                break;
                
                case 'doc':
                    $cType = 'application/msword';
                break;
                
                case 'xls':
                    $cType = 'application/vnd.ms-excel';
                break;
                
                case 'ppt':
                    $cType = 'application/vnd.ms-powerpoint';
                break;
                case 'gif':
                    $cType = 'image/gif';
                break;
                case 'png':
                    $cType = 'image/png';
                break;
                case 'jpeg':
                case 'jpg':
                    $cType = 'image/jpg';
                break;
        
                default:
                    $cType = 'application/force-download';
                break;
            }
       //////////////// just checking 
    
       if(!file_exists($relative)){
            echo $relative;
            echo '<br />';
            exit;
            }
        
        if( !is_readable( $relative ) )
        exit('its not redable');
        
    
    
        if( headers_sent() )
        exit('headers ? already sent !! ');
            
    
        
        header( 'Pragma: public' ); 
        header( 'Expires: 0' );
        header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
        header( 'Cache-Control: private', false ); // required for certain browsers 
        header( 'Content-Description:File Transfer' );
        header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
        header( 'Content-Type:'.$cType);
        header( 'Content-Disposition: attachment; filename="'. basename($filename) . '";' );
        header( 'Content-Transfer-Encoding: binary' );
        header( 'Content-Length: ' . filesize($relative) );
        readfile($abslout_path);
        exit;
    

    I've checked the headers couple times and they are fine(i think) , I've also add every headers known to man just to be sure !

    I'm starting to think maybe it's something other than script like char encoding or folder permission ! or something like that !!

    am i missing something ?

  • Lawrence Cherone
    Lawrence Cherone about 8 years
    @DanBray what a terrible edit, shame on community for approving
  • Dan Bray
    Dan Bray about 8 years
    @LawrenceCherone What is so terrible about making the code work? The code had a missing ). Do you think it's better to leave code with typos in? The missing ) could confuse people and waste a lot of their time.
  • Lawrence Cherone
    Lawrence Cherone about 8 years
    Nice spot on the (is_dir($path)) but the rest of the edit, was simply personal syntax preference.
  • Dan Bray
    Dan Bray about 8 years
    @LawrenceCherone It wouldn't let me just add the missing ) because there's a minimum amount of characters I have to edit. I guess I could have entered a short phrase at the bottom instead.
  • Sulung Nugroho
    Sulung Nugroho almost 7 years
    This is perfect for me. The downloaded file not corrupt. I use as Lawrence Cherone suggested php script but the downloaded file still corrupt. thanks to Altair CA. And thanks to all.