Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP using fwrite and fread with input stream

I'm looking for the most efficient way to write the contents of the PHP input stream to disk, without using much of the memory that is granted to the PHP script. For example, if the max file size that can be uploaded is 1 GB but PHP only has 32 MB of memory.

define('MAX_FILE_LEN', 1073741824); // 1 GB in bytes
$hSource = fopen('php://input', 'r');
$hDest = fopen(UPLOADS_DIR.'/'.$MyTempName.'.tmp', 'w');
fwrite($hDest, fread($hSource, MAX_FILE_LEN));
fclose($hDest);
fclose($hSource);

Does fread inside an fwrite like the above code shows mean that the entire file will be loaded into memory?

For doing the opposite (writing a file to the output stream), PHP offers a function called fpassthru which I believe does not hold the contents of the file in the PHP script's memory.

I'm looking for something similar but in reverse (writing from input stream to file). Thank you for any assistance you can give.

like image 916
Lakey Avatar asked Mar 07 '12 03:03

Lakey


1 Answers

Yep - fread used in that way would read up to 1 GB into a string first, and then write that back out via fwrite. PHP just isn't smart enough to create a memory-efficient pipe for you.

I would try something akin to the following:

$hSource = fopen('php://input', 'r');
$hDest = fopen(UPLOADS_DIR . '/' . $MyTempName . '.tmp', 'w');
while (!feof($hSource)) {
    /*  
     *  I'm going to read in 1K chunks. You could make this 
     *  larger, but as a rule of thumb I'd keep it to 1/4 of 
     *  your php memory_limit.
     */
    $chunk = fread($hSource, 1024);
    fwrite($hDest, $chunk);
}
fclose($hSource);
fclose($hDest);

If you wanted to be really picky, you could also unset($chunk); within the loop after fwrite to absolutely ensure that PHP frees up the memory - but that shouldn't be necessary, as the next loop will overwrite whatever memory is being used by $chunk at that time.

like image 123
pauld Avatar answered Sep 22 '22 05:09

pauld