Developers experience issues while downloading large files using PHP, there are no of possible things to cause issue, i.e incorrect headers for browsers or incorrect file streaming.

Lets see how the correct headers are passed and how the large files are streamed in chunks

Note: Best practice is to zip your file/contents.

Lets talk about headers

You need to send correct headers to browser

//path to your orignal file
$file = "/home/xyz/";

//will be downloaded as "" to users, you can use original name as well.
$downloadName = "";

//telling browser that the content type is zip file
header('Content-Type: application/zip');

//telling browser about correct length of file in bytes
header('Content-Length: ' . filesize($file));

//tell browser to download it
header('Content-Disposition: attachment; filename="' . $downloadName . '"');

//handle caching	
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);

//tell browser the encoding of file
header('Content-Transfer-Encoding: binary'); 

Once header part is done we move to reading file in chunks of bytes and sending those chunks instantly to browser, in other words streaming the file.

//set download speed in bytes
$bitrate = 1024; 
//1024 bytes = 1Kb

//how much bytes to read in a chunk
$chunkSize = $bitrate * 1024;

//open file for reading in binary mode
$handle = fopen($file, 'rb');

//read file chunks by chunk and send output to browser until end of file is not reached
while (!feof($handle)) {
    //read chunk of a file
    echo fread($handle, $chunkSize);

    //send an application-initiated buffer

    //usually FastCGI has a socket buffer on its own so use flush() to send the current content.


You can use $bitrate variable to control the speed of download for example

//set speed to 100kb
$bitrate = 100;