Welcome Guest, Not a member yet? Register   Sign In
Large File Downloads Issue Solved
#1

[eluser]Unknown[/eluser]
In developing a file download application for my client, I ran into the issue of not being able to download files over 80 megabytes. I could easily upload them via the Upload helper, but the Download helper was no help.

I tried all the PHP settings tricks and did not want to start messing with Apache.

After looking through the Download helper code and comparing other general PHP download solutions.

The difference I found was that the Download helper has you read the file contents first then they modify the headers to send the file to the browser. The general PHP download techniques show that you modify the headers first, then use "readfile()" to get the file.

So, I added an IF... ELSE statement to the Download helper basically saying - IF FILE TYPE IS 'SMALL' USE THE DEFAULT METHOD, ELSE USE THE READFILE() METHOD.

In the Controller I get the size of the file being downloaded and then set a variable to pass in whether or not the file is "SMALL".

This has been the solution to my problem without going through a ton server config hoops.

Let me know if this helps you at all.

There are most likely ways to refine this to optimize it.

CODE BELOW

CONTROLLER
Code:
//  DOWNLOAD FILE
    function download() {
        // LOAD FILE SIZE PLUGIN
        $this->load->plugin('filesize');
        // GRAB FILE NAME
        $file_name =  $this->uri->segment(3);
        // SET DIRECT PATH TO FILE
        $file_path = "securefiles/".$file_namee;
        // GRAB THE FILE SIZE
        $file_size = get_filesize($file_path);
        // CHOOSE WHICH DOWNLOAD METHOD BASED FILE SIZE
        if ($file_size >= 45) {
            // BEGIN DOWNLOAD
            force_download($file_name, $file_path, 'large');
        } else {
            // READ FILE CONTENTS
            $file_data = file_get_contents("securefiles/".$file_name);
            // BEGIN DOWNLOAD
            force_download($file_name, $file_data, 'small');
        }
    }

DOWNLOAD HELPER PORTION MODIFIED
Added Parameter: $type - Line 44
Code:
function force_download($filename = '', $data = '', $type = '')

Added IF / ELSE statement - Line 75
Code:
// Generate the server headers
        if ($type == 'small')
        {
            if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
            {
                header('Content-Type: "'.$mime.'"');
                header('Content-Disposition: attachment; filename="'.$filename.'"');
                header('Expires: 0');
                header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
                header("Content-Transfer-Encoding: binary");
                header('Pragma: public');
                header("Content-Length: ".strlen($data));
            }
            else
            {
                header('Content-Type: "'.$mime.'"');
                header('Content-Disposition: attachment; filename="'.$filename.'"');
                header("Content-Transfer-Encoding: binary");
                header('Expires: 0');
                header('Pragma: no-cache');
                header("Content-Length: ".strlen($data));
            }
        } else {
            if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
            {
                header('Content-Type: "'.$mime.'"');
                header('Content-Disposition: attachment; filename="'.$filename.'"');
                header('Expires: 0');
                header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
                header("Content-Transfer-Encoding: binary");
                header('Pragma: public');
                //header("Content-Length: ".strlen($data));
                readfile($data);
            }
            else
            {
                header('Content-Type: "'.$mime.'"');
                header('Content-Disposition: attachment; filename="'.$filename.'"');
                header("Content-Transfer-Encoding: binary");
                header('Expires: 0');
                header('Pragma: no-cache');
                //header("Content-Length: ".strlen($data));
                readfile($data);
                
            }
        }
#2

[eluser]helmutbjorg[/eluser]
Great work... Perhaps instead of passing in the 'small' variable you could put the filesize detection into the helper? Then you would never have to worry about it again and use the helper just like normal.
#3

[eluser]xwero[/eluser]
I wonder why the function doesn't check if the file exists? this will save you the fetching of the data for the second parameter.

You can reduce the code by moving all headers that every browsers uses above the if/else structure.
And why not use readfile for all forced downloads and remove $data as the exit parameter.
#4

[eluser]helmutbjorg[/eluser]
even better...
#5

[eluser]Unknown[/eluser]
Great suggestions. A couple of responses to some of the questions.

File Exists
I'm not sure the Download helper doesn't include a file exists check. I guess that is up to the developer to write into their own controller. Good idea though.

Use readfile for all forced downloads
After I had done research, the file_get_contents() function (used in examples for use with the default Download helper) is supposedly the better function use, but it didn't work for large files. I think I may test only using the readfile() function.

Add File Size to Download Helper
If go with the only using readfile() - I don't think I'll have to use it. But if I kept the dual function method, that would be a good idea.

Remove $data as exit parameter
I'm not sure I understand this one. The $data parameter either holds the file contents or with the readfile() function, holds the path to the file.

Thanks again for the ideas and suggestions.
#6

[eluser]xwero[/eluser]
Now the data is passed because it's the first parameter of the exit function but if you use the readfile function the data doesn't need to be displayed by the exit function.




Theme © iAndrew 2016 - Forum software by © MyBB