Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my downloaded file is always damaged or corrupted?

Tags:

file

php

download

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 ?

like image 733
max Avatar asked Dec 05 '22 16:12

max


2 Answers

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);
}
?>
like image 90
Lawrence Cherone Avatar answered Dec 10 '22 09:12

Lawrence Cherone


    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);


}
like image 24
Altair CA Avatar answered Dec 10 '22 09:12

Altair CA