I have to write a php script to download potentially large files. The file I’m reporting here works fine most of the times. However, if the client’s connection is slow the request ends (with status code 200) in the middle of the downloading, but not always at the very same point, and not at the very same time. I tried to overwrite some php.ini variables (see the first statements) but the problem remains.
I don’t know if it’s relevant but my hosting server is SiteGround, and for simple static file requests, the download works fine also with slow connections.
I’ve found Forced downloading large file with php but I didn’t understand mario’s answer. I’m new to web programming.
So here’s my code.
<?php
ini_set('memory_limit','16M');
ini_set('post_max_size', '30M');
set_time_limit(0);
include ('../private/database_connection.php');
$downloadFolder = '../download/';
$fileName = $_POST['file'];
$filePath = $downloadFolder . $fileName;
if($fileName == NULL)
{
exit;
}
ob_start();
session_start();
if(!isset($_SESSION['Username']))
{
// or redirect to login (remembering this download request)
$_SESSION['previousPage'] = 'download.php?file=' . $fileName;
header("Location: login.php");
exit;
}
if (file_exists($filePath))
{
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
//header('Content-Disposition: attachment; filename='.$fileName);
header("Content-Disposition: attachment; filename=\"$fileName\"");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
//header('Pragma: public');
header('Content-Length: ' . filesize($filePath));
ob_clean();
flush();
// download
// 1
// readfile($filePath);
// 2
$file = @fopen($filePath,"rb");
if ($file) {
while(!feof($file)) {
print(fread($file, 1024*8));
flush();
if (connection_status()!=0) {
@fclose($file);
die();
}
}
@fclose($file);
}
exit;
}
else
{
header('HTTP/1.1 404 File not found');
exit;
}
?>
HTTP Status Code of 200 means everything executed okay.
Check that your Content-Length is correct, and try without the connection_status() function. It may be reporting improperly that the user disconnected. PHP has a connection_aborted() function which may be what you need.
Update: Because you asked about Mario’s answer, what he means is that you should redirect your user to the actual file on the server and let your sever handle it instead of attempting to duplicate what the server can already do. In other words, you should use
header("Location: " . $filePath), or a link to the filepath instead of using your script. The disadvantage is that you can’t use the attachment style download, but you can open it in a new window, which will have a similar effect.