Search code examples
phpfwritefread

Using fread to send chunks of large data


This is a bit of a continue from my previous thread (PHP CURL Chunked encoding a large file (700mb)) but I've now improvised something else.

Right now, I'm trying to use fread and then sending files through CURL chunk by chunk (each chunk around 1MB) and while the idea is good and it does work. It does timeout the server, so I was wondering if there was any way to reduce the amount of times it sends a chunk per second or a way to make it so it doesn't completely overload my PHP process.

$length             = (1024 * 1024) * 1;
$handle             = fopen($getFile, "r");

while (($buffer = fread($handle, $length)) !== false) {
    if ($response = sendChunk($getServer, $buffer)) {
        $chunk++;
        print "Chunk " . $chunk . " Sent (Code: " . $response . ")! \n";
    }
}

The function sendChunk is

function sendChunk($url, $chunk) {
    $POST_DATA = [
        'file'  =>      base64_encode($chunk)
    ];

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_TIMEOUT, 2048);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $POST_DATA);
    curl_exec($curl);
    $response = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close ($curl);
    return $response;
}

I tried making it so you can read the file line by line, but it doesn't work since a video file (mp4, wmv) is lots of random characters and what not.

UPDATE: I have discovered the issue and the timing out was actually a result of CloudFlare timing out when there's no such HTTP Response. So I decided to run the script using SSH and it worked fine .... except for one thing.

After the file does get successfully sent over it will just keep sending chunks of 0 bytes in this endless loop and I was told it was because feof() isn't always accurate in measuring that. So I tried using the ($buffer = fread($handle, $length) !== false) trick and it still repeats the same thing. Any ideas?


Solution

  • After working on this for around 8 hours, I noticed that I wasn't using $buffer to send the chunk so now I have done that.

    while (!feof($fp) && ($buffer = fread($handle, $length)) !== false) {
        if ($response = sendChunk($getServer, $buffer)) {
            $chunk++;
            print "Chunk " . $chunk . " Sent (Code: " . $response . ")! \n";
        }
    }
    

    Everything works fine, I did some other touchups like check for a response code of 200. But the core of it works.

    A lesson for anyone that is using Cloudflare and is wanting to transfer a file (Up to 2GB) to another server and want to use it via CURL.

    • There is better ways than just using CURL for this in my opinion, but client has requested it done via this way, but it works.
    • Cloudflare only has a maximum upload limit of 250MB for Free users, you cannot do chunked uploading through CURL's supported stream function as Cloudflare still reads it as > 250MB in the header.
    • When I managed to get this code to work, it would timeout on certain chunks and it was because Cloudflare needs an HTTP header within 100 seconds or it times out. Thankfully my script will be executed via CRON so it doesn't need to go through Cloudflare to work. However, if you are looking to execute code within the browser then you may want to take a look at this. https://github.com/marcialpaulg/Fixing-Cloudflare-Error-524