Why does php download stop on large files? - php

I have a php script that allows users to download large files. The script works well except for files of over around 500mb. Everytime I try to download a file that is 664mb the download stops at about 460mb ( around 15-17 mins). There is no error. What can I do? I
suspect the script is timing out but I can't see why. I've spent days trying to get it to work and just can't make any progress. Any thoughts or suggestions would be great. I'm using a hosted server so cannot try modx_sendfile sadly. I'm using php 7.0.25
$db = new mysqli($dbHost, $dbUsername, $dbPassword, $dbName);
ob_start() or die('Cannot start output buffering');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$strDownloadFolder = "files/";
//- turn off compression on the server
//#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 'Off');
//Download a file more than once
$boolAllowMultipleDownload = 2;
if(!empty($_GET['key'])){
//check the DB for the key
$sql = "SELECT * FROM downloads WHERE downloadkey = '".mysqli_real_escape_string($db,$_GET['key'])."' LIMIT 1";
$resCheck=mysqli_query($db, $sql);
$arrCheck = mysqli_fetch_array($resCheck); //Create array from first result
if(!empty($arrCheck['file'])){
//check that the download time hasnt expired
if($arrCheck['expires']>=time()){
if(!$arrCheck['downloads'] OR $boolAllowMultipleDownload){
//everything is ok -let the user download it
$strDownload = $strDownloadFolder.$arrCheck['file'];
if(file_exists($strDownload)){
$file_path = $arrCheck['file'];
$path_parts = pathinfo($file_path);
$file_name = $path_parts['basename'];
$file_ext = $path_parts['extension'];
$file_path = 'files/' . $file_name;
// allow a file to be streamed instead of sent as an attachment
$is_attachment = isset($_REQUEST['stream']) ? false : true;
// make sure the file exists
if (is_file($file_path))
{
$file_size = filesize($file_path);
$file = #fopen($file_path,"rb");
if ($file)
{
// set the headers, prevent caching
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Disposition: attachment; filename=\"$file_name\"");
// set appropriate headers for attachment or streamed file
if ($is_attachment) {
header("Content-Disposition: attachment; filename=\"$file_name\"");
}
else {
header('Content-Disposition: inline;');
header('Content-Transfer-Encoding: binary');
}
// set the mime type based on extension, add yours if needed.
$ctype_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
);
$ctype = isset($content_types[$file_ext]) ? $content_types[$file_ext] : $ctype_default;
header("Content-Type: " . $ctype);
//check if http_range is sent by browser (or download manager)
if(isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if ($size_unit == 'bytes')
{
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
header('HTTP/1.1 416 Requested Range Not Satisfiable');
exit;
}
}
else
{
$range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1))
{
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
header('Content-Length: '.($seek_end - $seek_start + 1));
}
else
header("Content-Length: $file_size");
header('Accept-Ranges: bytes');
set_time_limit(0);
fseek($file, $seek_start);
while(!feof($file))
{
print(#fread($file, 1024*8));
ob_flush();
flush();
if (connection_status()!=0)
{
#fclose($file);
exit;
}
}
// file save was a success
#fclose($file);
exit;
}
else
{
// file couldn't be opened
header("HTTP/1.0 500 Internal Server Error");
exit;
}
}
else
{
// file does not exist
header("HTTP/1.0 404 Not Found");
exit;
}
}else{
echo "We couldn't find the file to download.";
}
}else{
//this file has already been downloaded and multiple downloads are not allowed
echo "This file has already been downloaded.";
}
}else{
//this download has passed its expiry date
echo "This download has expired.";
}
}else{
//the download key given didnt match anything in the DB
echo "No file was found to download.";
}
}else{
//No download key wa provided to this script
echo "No download key was provided. Please return to the previous page and try again.";
}
A much simpler piece of code that still throws up the same problem (but works with smaller files) mkaes me think it is a hosting / php.ini issue although I don't know why.
<?php
$local_file = 'my_big_file.zip';
$download_file = 'my_big_file.zip';
// set the download rate limit (=> 20,5 kb/s)
if(file_exists($local_file) && is_file($local_file))
{
header('Cache-control: private');
header('Content-Type: application/octet-stream');
header('Content-Length: '.filesize($local_file));
header('Content-Disposition: filename='.$download_file);
flush();
$file = fopen($local_file, "r");
while(!feof($file))
{
// send the current file part to the browser
print fread($file, round(1024 * 1024));
// flush the content to the browser
flush();
// sleep one second
sleep(1);
}
fclose($file);}
else {
die('Error: The file '.$local_file.' does not exist!');
}
?>
This script stops downloading after about 17 minutes.

Related

Why does Mozilla Extension like downthemall cause requests to a URL to appear hitting multiple times?

I develop a PHP code and count how much data was downloaded by the client. My code is working fine if someone directly requests my file from a browser. But if someone installs a Mozilla extensions like ‘’downthemall’’ and then the url is requested by that extension then it requests the file URL 4 times so I get the downloaded data 4 times. How do I fix this? The same happened when the user is using jDownloader software or any software.
<?php
function getMimeType($fileName)
{
$c_type_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
"mp4" => "video/mp4",
);
// echo isset($content_types[pathinfo($fileName, PATHINFO_EXTENSION)]) ? $content_types[pathinfo($fileName, PATHINFO_EXTENSION)] : $c_type_default;
return isset($content_types[pathinfo($fileName, PATHINFO_EXTENSION)]) ? $content_types[pathinfo($fileName, PATHINFO_EXTENSION)] : $c_type_default;
}
function output_file($file, $name)
{
/*
This function takes a path to a file to output ($file), the filename that the browser will see ($name) and the MIME type of the file ($mime_type, optional).
*/
//Check the file premission
if(!is_readable($file)) die('File not found or inaccessible!');
$size = filesize($file);
$name = rawurldecode($name);
//turn off output buffering to decrease cpu usage
#ob_end_clean();
include('../includes/configg.php');
// Start Code For Total Downloaded Data Size by The LoggedIn User
$user="select * from $TBusers where id=".$_SESSION['log_id'];
$result_user = mysqli_query($conn, $user) ;
$row = mysqli_fetch_assoc($result_user);
$lastsotrage = $row['down'];
$curr_date= $row['curr_date'];
$today_date= date('d-m-y');
$daily_downloaded_data= $row['daily_downloaded_data'];
if($curr_date != $today_date)
{
$update_curr_date="update $TBusers set curr_date ='$today_date', daily_downloaded_data =0 where id=".$_SESSION['log_id']; // Set Curr_date by Today Date For check Daily Downloaded Data Limit
mysqli_query($conn,$update_curr_date) ;
$daily_downloaded_data=0;
}
/*else
{
if($daily_downloaded_data>=(20*1024*1024*1024)){ // Check Daily Download Data Limit 20GB Exceed or not
header('Location: http://idownload.club/members/download.php');
exit;}
}*/
// required for IE, otherwise Content-Disposition may be ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: ' . getMimeType($name));
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']))
{
list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
list($range) = explode(",",$range,2);
list($range, $range_end) = explode("-", $range);
$range=intval($range);
if(!$range_end) {
$range_end=$size-1;
} else {
$range_end=intval($range_end);
}
$new_length = $range_end-$range+1;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $new_length");
header("Content-Range: bytes $range-$range_end/$size");
} else {
$new_length=$size;
header("Content-Length: ".$size);
}
/* Will output the file itself */
$chunksize = 1*(1024*1024); //you may want to change this
$bytes_send = 0;
if ($file = fopen($file, 'r'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length)
)
{
$buffer = fread($file, $chunksize);
print($buffer); //echo($buffer); // can also possible
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
$lastsotrage= $lastsotrage + $size;
$daily_downloaded_data+=$size;
$sql="update $TBusers set down =". $lastsotrage." where id=".$_SESSION['log_id'];
$sql2="update $TBusers set daily_downloaded_data = $daily_downloaded_data where id=".$_SESSION['log_id'];
$sql3= "update test set count=count+1 where id=1" ;
mysqli_query($conn,$sql) ;
mysqli_query($conn,$sql2) ;mysqli_query($conn,$sql3) ;
file_put_contents('data.txt', print_r($_SERVER, true), FILE_APPEND);
} else
//If no permissiion
die('Error - can not open file.');
//die
die();
}
//Set the time out
set_time_limit(0);
//path to the file
$file_dir=$_GET['directory'];
$file_name = str_replace("/", "", $_GET['file']);
$file_name = str_replace("\\", "", $file_name);
$file = $file_dir . "/".$file_name;
//Call the download function with file path,file name and file type
output_file($file, ''.$file_name.'');
?>

(PHP)Script in Apache works great, but not in IIS

I didn't know wrote what in Title, sorry!
I have this script that I got from MediaDivision for downloading data with header:
<?php
// hide notices
#ini_set('error_reporting', E_ALL & ~ E_NOTICE);
//- turn off compression on the server
#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 'Off');
//Getting upload center and append file name
$file_path = $_SERVER['DOCUMENT_ROOT'] . $dir_path;
$file_name = pathinfo($file_path)['basename'];
// allow a file to be streamed instead of sent as an attachment
$is_attachment = isset($_REQUEST['stream']) ? false : true;
// make sure the file exists
if (is_file($file_path))
{
$file_size = filesize($file_path);
$file = #fopen($file_path,"rb");
if ($file)
{
// set the headers, prevent caching
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Disposition: inline; filename=\"$file_name\"");
header("Content-Type: video/x-msvideo");
if(isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if ($size_unit == 'bytes')
{
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
header('HTTP/1.1 416 Requested Range Not Satisfiable');
exit;
}
}
else
{
$range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1))
{
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
header('Content-Length: '.($seek_end - $seek_start + 1));
}
else
header("Content-Length: $file_size");
header('Accept-Ranges: bytes');
set_time_limit(0);
fseek($file, $seek_start);
while(!feof($file))
{
print(#fread($file, 1024*8));
ob_flush();
flush();
if (connection_status()!=0)
{
#fclose($file);
exit;
}
}
// file save was a success
#fclose($file);
exit;
}
else
{
// file couldn't be opened
header("HTTP/1.0 500 Internal Server Error");
exit;
}
}
else
{
// file does not exist
header("HTTP/1.0 404 Not Found");
exit;
}
?>
This script works great in Linux servers that I tested with. I can resume downloads and get 8 connection in IDM and everything, But is IIS I just get 1 connection and after every pause, I have to wait a few seconds or I get Server Closed Connection.
I have exact php version installed in both servers, And did all the configs that I found in tutorials with Windows Server 2012 and IIS 8.
So what's the problem here?
(Although I have to say that direct download from Server 2012 has no problem and works great.)
Edit:
I test the script on windows server with Nginx too, but same as IIS, It doesn't work right.

PHP download script failed when download file > 1GB show network failed error

I am using the following code to download a file in PHP. Code works fine for most videos, but when I try to download video larger than 1 GB it failed and shows me a download error when it get to 1gb (exactly 1gb, no less, no more), this error happens with all browsers. But, if I use jdownloader or DownThemAll or any software all downloads are succesfully downloaded.
<?php
set_time_limit(0);
ini_set('memory_limit', '2G');
function getMimeType($fileName)
{
$c_type_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
"mp4" => "video/mp4",
);
// echo isset($content_types[pathinfo($fileName, PATHINFO_EXTENSION)]) ? $content_types[pathinfo($fileName, PATHINFO_EXTENSION)] : $c_type_default;
return isset($content_types[pathinfo($fileName, PATHINFO_EXTENSION)]) ? $content_types[pathinfo($fileName, PATHINFO_EXTENSION)] : $c_type_default;
}
function output_file($file, $name)
{
/*
This function takes a path to a file to output ($file), the filename that the browser will see ($name) and the MIME type of the file ($mime_type, optional).
*/
//Check the file premission
if(!is_readable($file)) die('File not found or inaccessible!');
$size = filesize($file);
$name = rawurldecode($name);
//turn off output buffering to decrease cpu usage
#ob_end_clean();
include('../includes/configg.php');
// Start Code For Total Downloaded Data Size by The LoggedIn User
$user="select * from $TBusers where id=".$_SESSION['log_id'];
$result_user = mysqli_query($conn, $user) ;
$row = mysqli_fetch_assoc($result_user);
$lastsotrage = $row['down'];
$curr_date= $row['curr_date'];
$today_date= date('d-m-y');
$daily_downloaded_data= $row['daily_downloaded_data'];
if($curr_date != $today_date)
{
$update_curr_date="update $TBusers set curr_date ='$today_date', daily_downloaded_data =0 where id=".$_SESSION['log_id']; // Set Curr_date by Today Date For check Daily Downloaded Data Limit
mysqli_query($conn,$update_curr_date) ;
$daily_downloaded_data=0;
}
/*else
{
if($daily_downloaded_data>=(20*1024*1024*1024)){ // Check Daily Download Data Limit 20GB Exceed or not
header('Location: http://idownload.club/members/download.php');
exit;}
}*/
// required for IE, otherwise Content-Disposition may be ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: ' . getMimeType($name));
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: 0");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']))
{
list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
list($range) = explode(",",$range,2);
list($range, $range_end) = explode("-", $range);
$range=intval($range);
if(!$range_end) {
$range_end=$size-1;
} else {
$range_end=intval($range_end);
}
$new_length = $range_end-$range+1;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $new_length");
header("Content-Range: bytes $range-$range_end/$size");
} else {
$new_length=$size;
header("Content-Length: ".$size);
}
/* Will output the file itself */
$chunksize = 8*(1024*1024); //you may want to change this
$bytes_send = 0;
if ($file = fopen($file, 'r'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length)
)
{
$buffer = fread($file, $chunksize);
print($buffer); //echo($buffer); // can also possible
//flush();
$bytes_send += strlen($buffer);
}
fclose($file);
$lastsotrage= $lastsotrage + $size;
$daily_downloaded_data+=$size;
$sql="update $TBusers set down =". $lastsotrage." where id=".$_SESSION['log_id'];
$sql2="update $TBusers set daily_downloaded_data = $daily_downloaded_data where id=".$_SESSION['log_id'];
$sql3= "update test set count=count+1 where id=1" ;
mysqli_query($conn,$sql) ;
mysqli_query($conn,$sql2) ;mysqli_query($conn,$sql3) ;
file_put_contents('data.txt', print_r($_SERVER, true), FILE_APPEND);
} else
//If no permissiion
die('Error - can not open file.');
//die
die();
}
//Set the time out
set_time_limit(0);
//path to the file
$file_dir=$_GET['directory'];
$file_name = str_replace("/", "", $_GET['file']);
$file_name = str_replace("\\", "", $file_name);
$file = $file_dir . "/".$file_name;
//Call the download function with file path,file name and file type
output_file($file, ''.$file_name.'');
?>

Why does Mozilla Extension cause requests to a URL to appear hitting multiple times?

I develop a PHP code and count how much data was downloaded by the client. My code is working fine if someone directly requests my file from a browser. But if someone installs a Mozilla extensions like ‘’downthemall’’ and then the url is requested by that extension then it requests the file URL 4 times so I get the downloaded data 4 times. How do I fix this? The same happened when the user is using jDownloader software or any software.
Here is My full download code :-
<?php
function getMimeType($fileName)
{
$c_type_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
"mp4" => "video/mp4",
);
// echo isset($content_types[pathinfo($fileName, PATHINFO_EXTENSION)]) ? $content_types[pathinfo($fileName, PATHINFO_EXTENSION)] : $c_type_default;
return isset($content_types[pathinfo($fileName, PATHINFO_EXTENSION)]) ? $content_types[pathinfo($fileName, PATHINFO_EXTENSION)] : $c_type_default;
}
function output_file($file, $name)
{
/*
This function takes a path to a file to output ($file), the filename that the browser will see ($name) and the MIME type of the file ($mime_type, optional).
*/
//Check the file premission
if(!is_readable($file)) die('File not found or inaccessible!');
$size = filesize($file);
$name = rawurldecode($name);
//turn off output buffering to decrease cpu usage
#ob_end_clean();
include('../includes/configg.php');
// Start Code For Total Downloaded Data Size by The LoggedIn User
$user="select * from $TBusers where id=".$_SESSION['log_id'];
$result_user = mysqli_query($conn, $user) ;
$row = mysqli_fetch_assoc($result_user);
$lastsotrage = $row['down'];
$curr_date= $row['curr_date'];
$today_date= date('d-m-y');
$daily_downloaded_data= $row['daily_downloaded_data'];
if($curr_date != $today_date)
{
$update_curr_date="update $TBusers set curr_date ='$today_date', daily_downloaded_data =0 where id=".$_SESSION['log_id']; // Set Curr_date by Today Date For check Daily Downloaded Data Limit
mysqli_query($conn,$update_curr_date) ;
$daily_downloaded_data=0;
}
/*else
{
if($daily_downloaded_data>=(20*1024*1024*1024)){ // Check Daily Download Data Limit 20GB Exceed or not
header('Location: http://idownload.club/members/download.php');
exit;}
}*/
// required for IE, otherwise Content-Disposition may be ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: ' . getMimeType($name));
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']))
{
list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
list($range) = explode(",",$range,2);
list($range, $range_end) = explode("-", $range);
$range=intval($range);
if(!$range_end) {
$range_end=$size-1;
} else {
$range_end=intval($range_end);
}
$new_length = $range_end-$range+1;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $new_length");
header("Content-Range: bytes $range-$range_end/$size");
} else {
$new_length=$size;
header("Content-Length: ".$size);
}
/* Will output the file itself */
$chunksize = 1*(1024*1024); //you may want to change this
$bytes_send = 0;
if ($file = fopen($file, 'r'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length)
)
{
$buffer = fread($file, $chunksize);
print($buffer); //echo($buffer); // can also possible
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
$lastsotrage= $lastsotrage + $size;
$daily_downloaded_data+=$size;
$sql="update $TBusers set down =". $lastsotrage." where id=".$_SESSION['log_id'];
$sql2="update $TBusers set daily_downloaded_data = $daily_downloaded_data where id=".$_SESSION['log_id'];
$sql3= "update test set count=count+1 where id=1" ;
mysqli_query($conn,$sql) ;
mysqli_query($conn,$sql2) ;mysqli_query($conn,$sql3) ;
file_put_contents('data.txt', print_r($_SERVER, true), FILE_APPEND);
} else
//If no permissiion
die('Error - can not open file.');
//die
die();
}
//Set the time out
set_time_limit(0);
//path to the file
$file_dir=$_GET['directory'];
$file_name = str_replace("/", "", $_GET['file']);
$file_name = str_replace("\\", "", $file_name);
$file = $file_dir . "/".$file_name;
//Call the download function with file path,file name and file type
output_file($file, ''.$file_name.'');
?>
Because of segmented/parallel download.
Mentioned extensions are requesting ranges of content (as opposed to full content when accessing from browser).
This feature allows them to download file content concurrently, most often in shorter time.
Read more about partial content and range requests.
On client side, this can be changed (DownThemAll):

PHP download resume in Chrome HTTP RANGE not working

I'm using the following code, I adapted: http://ee.php.net/manual/en/function.fread.php#84115 to my code to allow download resume, it works great on firefox but doesn't work at all in chrome. If I try in chrome, the file is downloading, I pause it, wait a few minutes, but then when I resume it the download finishes instantly and the file is corrupted.
Any idea why?
function dl_file_resumable($file, $is_resume=TRUE)
{
//First, see if the file exists
if (!is_file($file))
{
die("<b>404 File not found!</b>");
}
//Gather relevent info about file
$size = filesize($file);
$fileinfo = pathinfo($file);
//workaround for IE filename bug with multiple periods / multiple dots in filename
//that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe
$filename = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ?
preg_replace('/\./', '%2e', $fileinfo['basename'], substr_count($fileinfo['basename'], '.') - 1) :
$fileinfo['basename'];
$file_extension = strtolower($path_info['extension']);
$ctype='application/octet-stream';
//check if http_range is sent by browser (or download manager)
if($is_resume && isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if ($size_unit == 'bytes')
{
//multiple ranges could be specified at the same time, but for simplicity only serve the first range
//http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
}
}
else
{
$range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//add headers if resumable
if ($is_resume)
{
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($size - 1))
{
header('HTTP/1.1 206 Partial Content');
}
header('Accept-Ranges: bytes');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size);
}
//headers for IE Bugs (is this necessary?)
//header("Cache-Control: cache, must-revalidate");
//header("Pragma: public");
header('Content-Type: ' . $ctype);
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: '.($seek_end - $seek_start + 1));
//open the file
$fp = fopen($file, 'rb');
//seek to start of missing part
fseek($fp, $seek_start);
//start buffered download
while(!feof($fp))
{
//reset time limit for big files
set_time_limit(0);
print(fread($fp, 1024*8));
flush();
ob_flush();
}
fclose($fp);
exit;
}
dl_file_resumable('/home/var/www/app/back/media/ready/5a58hGuRFR.tar');
I did not tried execute your code, but it looks like there is some mess with switch statement:
It does not have any meaning - if $ext is set at all, it will fall into one and only default section
It has wrong syntax - after default should be :
It has variable $new_name which isn't set anywhere
In the end, having these errors in reply, different browsers will handle them differently.

Categories