Hướng dẫn php readfile large file

When using readfile() -- using PHP on Apache -- is the file immediately read into Apache's output buffer and the PHP script execution completed, or does the PHP script execution wait until the client finishes downloading the file (or the server times out, whichever happens first)?

The longer back-story:

I have a website with lots of large mp3 files (sermons for a local church). Not all files in the audio archive are allowed to be downloaded, so the /sermon/{filename}.mp3 path is rewritten to really execute /sermon.php?filename={filename} and if the file is allowed to be downloaded then the content type is set to "audio/mpeg" and the file streamed out using readfile(). I've been getting complaints (almost exclusively from iPhone users who are streaming the downloads over 3G) that the files don't fully download, or that they cut off after about 10 or 15 minutes. When I switched from streaming out the file with a readfile() to simply redirecting to the file -- header("Location: $file_url"); -- all of the complaints went away (I even checked with a few users who could reliably reproduce the problem on demand previously).

This leads me to suspect that when using readfile() the PHP script engine is in use until the file is fully downloaded but I cannot find any references which confirm or deny this theory. I'll admit I'm more at home in the ASP.NET world and the dotNet equivalent of readfile() pushes the whole file to the IIS output buffer immediately so the ASP.NET execution pipeline can complete independently of the delivery of the file to the end client... is there an equivalent to this behavior with PHP+Apache?

Revent

2,0732 gold badges18 silver badges32 bronze badges

asked Aug 2, 2012 at 22:25

Hướng dẫn php readfile large file

2

You may still have PHP output buffering active while performing the readfile(). Check that with:

if (ob_get_level()) ob_end_clean();

or

while (ob_get_level()) ob_end_clean();

This way theonly remaining output Buffer should be apache's Output Buffer, see SendBufferSize for apache tweaks.

EDIT

You can also have a look at mod_xsendfile (an SO post on such usage, PHP + apache + x-sendfile), so that you simply tell the web server you have done the security check and that now he can deliver the file.

answered Aug 3, 2012 at 11:59

regileroregilero

29k6 gold badges58 silver badges98 bronze badges

0

a few things you can do (I am not reporting all the headers that you need to send that are probably the same ones that you currently have in your script):

set_time_limit(0);  //as already mention
readfile($filename);
exit(0);

or

passthru('/bin/cat '.$filename);
exit(0);

or

//When you enable mod_xsendfile in Apache
header("X-Sendfile: $filename");

or

//mainly to use for remove files
$handle = fopen($filename, "rb");
echo stream_get_contents($handle);
fclose($handle);

or

$handle = fopen($filename, "rb");
while (!feof($handle)){
    //I would suggest to do some checking
    //to see if the user is still downloading or if they closed the connection
    echo fread($handle, 8192);
}
fclose($handle);

answered Oct 19, 2012 at 13:52

Hướng dẫn php readfile large file

FabrizioFabrizio

3,6942 gold badges28 silver badges32 bronze badges

1

The script will be running until the user finishes downloading the file. The simplest, most efficient and surely working solution is to redirect the user:

header("Location: /real/path/to/file");
exit;

But this may reveal the location of the files. It's a good idea to password-protect the files that may not be downloaded by everyone anyway with an .htaccess file, but perhaps you use a database to detemine access and this is no option.

Another possible solution is setting the maximum execution time of PHP to 0, which disables the limit:

set_time_limit(0);

Your host may disallow this, though. Also PHP reads the file into the memory first, then goes through Apache's output buffer, and finally makes it to the network. Making users download the file directly is much more efficient, and does not have PHP's limitations like the maximum execution time.

Edit: The reason you get this complaint a lot from iPhone users is probably that they have a slower connection (e.g. 3G).

answered Aug 2, 2012 at 22:33

LucLuc

4,5232 gold badges43 silver badges44 bronze badges

1

downloading files thru php isnt very efficient, using a redirect is the way to go. If you dont want to expose the location of the file, or the file isnt in a public location then look into internal redirects, here is a post that talks about it a bit, Can I tell Apache to do an internal redirect from PHP?

answered Aug 2, 2012 at 22:32

hackattackhackattack

1,0976 silver badges9 bronze badges

4

Try using stream_copy_to_stream() instead. I find is has fewer problems than readfile().

set_time_limit(0);
$stdout = fopen('php://output', 'w');
$bfname = basename($fname);

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$bfname\"");

$filein = fopen($fname, 'r');
stream_copy_to_stream($filein, $stdout);

fclose($filein);
fclose($stdout);

answered Feb 21, 2017 at 16:29

2

Under Apache, there is a nice elgant solution not involving php at all:

Just place an .htaccess config file into the folder containing the files to be offered for download with the following contents:


ForceType applicaton/octet-stream

This tells the Apache to offer all files in this folder (and all its subfolders) for download, instead of directly displaying them in the browser.

answered Apr 22, 2016 at 11:53

See below url

http://php.net/manual/en/function.readfile.php


answered Aug 2, 2012 at 23:15

Abid HussainAbid Hussain

7,6062 gold badges32 silver badges50 bronze badges

Not the answer you're looking for? Browse other questions tagged php apache or ask your own question.