views:

52

answers:

3

I tried using a free script that I found on the Internet but it is giving me problems with Windows users (even though they are using IE 8, so it's not an option for me to ask them to upgrade their browsers.) Here's the requirements:

  • I have a bunch of Microsoft Word and pdf files that need to be protected so that only authorized users can download them. I have already created the login system and the current script I have works fine for non-IE browsers. However, I keep getting recurring problems with Windows users who keep complaining that their files download corrupt and yet everyone else either using Mac or Linux or any other browser gets on just fine.
  • The script must allow me to store files in a directory but force download of the file upon the function call.
  • Must work well with most major browsers, especially I.E.

If you have any practice suggestions or know of any great scripts (even if they are paid, I'm sick of this problem and would probably pay for a paid script) it would be greatly appreciated in advance.

Here is the code of the function I am currently using:

function output_file($file, $name, $mime_type=''){

    if(!is_readable($file)) die('File not found or inaccessible!');

    $size = filesize($file);
    $name = rawurldecode($name);

    /* Figure out the MIME type (if not specified) */
    $known_mime_types=array(
    "pdf" => "application/pdf",
    "txt" => "text/plain",
    "html" => "text/html",
    "htm" => "text/html",
    "exe" => "application/octet-stream",
    "zip" => "application/zip",
    "doc" => "application/msword",
    "xls" => "application/vnd.ms-excel",
    "ppt" => "application/vnd.ms-powerpoint",
    "gif" => "image/gif",
    "png" => "image/png",
    "jpeg"=> "image/jpg",
    "jpg" =>  "image/jpg",
    "php" => "text/plain",
    "rtf" => "application/rtf",
    "csv" => "text/csv"

    );

    if($mime_type==''){
        $file_extension = strtolower(substr(strrchr($file,"."),1));
        if(array_key_exists($file_extension, $known_mime_types)){
            $mime_type=$known_mime_types[$file_extension];
        }else {
            $mime_type="application/force-download";
        };
    };

    @ob_end_clean(); //turn off output buffering to decrease cpu usage

    // required for IE, otherwise Content-Disposition may be ignored
    if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');

    header('Content-Type: ' . $mime_type);
    header('Content-Disposition: attachment; filename="'.$name.'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    /* The three lines below basically make the 
    download non-cacheable */
    header("Cache-control: private");
    header('Pragma: private');
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");

    // multipart-download and download resuming support
    if(isset($_SERVER['HTTP_RANGE']))
    {
        list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
        list($range) = explode(",",$range,2);
        list($range, $range_end) = explode("-", $range);
        $range=intval($range);
        if(!$range_end) {
            $range_end=$size-1;
        }else {
            $range_end=intval($range_end);
        }

        $new_length = $range_end-$range+1;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range-$range_end/$size");
    }else {
        $new_length=$size;
        header("Content-Length: ".$size);
    }

    /* output the file itself */
    $chunksize = 1*(1024*1024); //you may want to change this
    $bytes_send = 0;
    if ($file = fopen($file, 'r'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

        while(!feof($file) && 
        (!connection_aborted()) && 
        ($bytes_send<$new_length)
        ){
            $buffer = fread($file, $chunksize);
            print($buffer); //echo($buffer); // is also possible
            flush();
            $bytes_send += strlen($buffer);
        }
        fclose($file);
    }else die('Error - can not open file.');

    die();
}
+1  A: 

Actually, this should be a pretty easy thing to do. It only consists of a few header calls and a readfile.

The PHP manual for readfile gives you most of the code on how to do it, just not the code to use a filename gotten from somewhere else.

R. Bemrose
A: 

Is it possible a PHP error is getting into the output and corrupting the file?

AbeVoelker
A: 

Maybe the time to download the file is longer than the time that is granted to php to execute the script. If your max_execution_time setting is lower than the time that it takes the client to download the file, it gets cut of. The script you use seems ok.

WesleyE