I have problem with a php managed file download where the browser do no show progress of a file download. In fact, the browser appears to be waiting and waiting and waiting, until the file is completely downloaded. The file will then appear in the download list (with chrome and firefox). I cannot even download the file with IE8. I would like the browser to show the actual file size and the progress of the download.
Strangely the download is not even visible in firebug (no line appear in the network tab if you paste the download url).
I suspected problem with compression/zlib so I disabled both: no change. I disabled output buffering with the same result.
Live example can be found here: http://vps-1108994-11856.manage.myhosting.com/download.php
Phpinfo: http://vps-1108994-11856.manage.myhosting.com/phpinfo.php
The code is below, your help is appreciated.
<?php
$name = "bac.epub";
$publicname = "bac.epub";
#apache_setenv('no-gzip', 1);
ini_set("zlib.output_compression", "Off");
header("Content-Type: application/epub+zip");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($name));
header("Content-disposition: attachment; filename=" . $publicname) );
ob_end_flush();
flush();
// dump the file and stop the script
$chunksize = 1 * (128 * 1024); // how many bytes per chunk
$size = filesize($name);
if ($size > $chunksize) {
$handle = fopen($name, 'rb');
$buffer = '';
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
sleep(1);
}
fclose($handle);
} else {
readfile($name);
}
exit;
The sleep in the code was to ensure that the download is long enough to see the progress.
Keep it, really, really, simple.
<?php
header("Content-Type: application/epub+zip");
header("Content-disposition: attachment; filename=" . $publicname) );
if(!readfile($name))
echo 'Error!';
?>
It is all you really need.
header("Content-Type: application/epub+zip");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($file_path));
header("Content-disposition: attachment; filename=" . $local_file_name);
// dump the file and stop the script
$chunksize = 128 * 1024; // how many bytes per chunk (128 KB)
$size = filesize($file_path);
if ($size > $chunksize)
{
$handle = fopen($file_path, 'rb');
$buffer = '';
while (!feof($handle))
{
$buffer = fread($handle, $chunksize);
echo $buffer;
flush();
sleep(1);
}
fclose($handle);
}
else
{
readfile($file_path);
}
I have modified your code Francis. And now it works ... :)
This is likely caused by a firewall or some sort of proxy between you and the remote site. I was wrestling with the same problem - disabling gzip, flushing buffers etc. until I tried it under a web VPN and the progress indicator re-appeared.
I don't think that the progress indicator is buggy - it's just that the content is being embargoed before it gets to you, which appears as a waiting state in the download. Then when the content is scanned or approved, it may come down very quickly relative to the normal download speed of your site. For large enough files, maybe you could see a progress indicator at this stage.
Nothing you can do about it except to determine if this is the real reason for this behaviour.
Related
I am trying to download 700mb file using the following code
header("Pragma: public", true);
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".basename($File));
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize('movies/'.$File));
flush();
$fp = fopen('movies/'.$File, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush();
}
fclose($fp);
but this is taking too long to start downloading file, it takes about 2-3 minutes to start the download. This code is just for mkv file, other video files are working perfect with location header.
File is not downloading without any of the content-type header missing
I want to start downloading fast
I am having some major problems when with a script I have to download files from S3.
The problem I'm encountering is that every time I try to download a file, the download starts perfectly, but about halfway through a download the file just stops. Every time. On every file. These are video files, so a lot of them are significantly big. Not sure what to do or how to approach this. Here's my script:
<?php
// other code exists; this is the main download logic
set_time_limit(0);
ignore_user_abort(false);
ini_set('output_buffering', 0);
ini_set('zlib.output_compression', 0);
$chunk = 10 * 1024 * 1024; // bytes per chunk (10 MB)
$fh = fopen($video->getMp4Source(), "rb");
if ($fh === false) {
echo "Unable open file";
}
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Expires: 0');
header('Pragma: public');
header('Content-Description: File Transfer');
header('Content-type: MP4');
header('Content-length: ' . $video->getFileSize());
header('Content-Disposition: attachment; filename="'.$video->getMp4Source().'"');
while (!feof($fh)) {
echo fread($fh, $chunk);
ob_flush(); // flush output
flush();
}
exit;
I'm not sure what is wrong, or why it keeps happening. There are no errors being logged, and no errors are occurring outside from the file failing to complete its download. I have tried this with readfile(), but it was using up too many resources and it wasn't completing, regardless.
Any help would be great.
I am trying to make a file download dependent inside a session. Here is the code:
<?php>
session_name("My-Download");
session_start();
$_SESSION['Download-Authorized'] = 1;
echo "<a class='invlink' rel='nofollow' download target='_blank' href='download.php?download_file=file.to.download.pdf'>Name of File</a><br /><br />";
?>
The download script ('download.php') comes next:
<?php
session_start();
if(!isset($_SESSION['Download-Authorized'])) {
exit;
}
$path = $_SERVER['DOCUMENT_ROOT']."/downdir/";
$fullPath = $path.$_GET['download_file'];
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fsize);
while(!feof($fd)) {
$buffer = fread($fd, 2048);
print($buffer);
flush();
}
fclose ($fd);
} else {
die("File does not exist. Make sure you specified correct file name.");
}
exit;
?>
All works fine as long as the verification of '$_SESSION['Download-Authorized'] ist commented out.
When I check the session-variable $_SESSION['Download-Authorized'] is set
the download will fail.
What's wrong with my code?
Any help appreciated.
After adding session_start() to the beginning of download.php the script still does not work.
It appears to be the case that the Session-ID as well as the Session-Name changes when "download.php" is called. Additionally $_SESSION['Downlad-Autorized'] is reset.
Your initial script stores the flag in a session explicitely renamed (session_name("My-Download");), but the download script uses the default session name (no session_name()).
Therefore your download script starts with another (possibly empty) session.
I am using the following code to control the bandwidth usage through download link. Here is the code that i am using with implementation of QOS Bandwidth Throttle PHP
// create new config
$config = new ThrottleConfig();
// enable burst rate for 30 seconds
$config->burstTimeout = 30;
// set burst transfer rate to 50000 bytes/second
$config->burstLimit = 10000;
// set standard transfer rate to 15.000 bytes/second (after initial 30 seconds of burst rate)
$config->rateLimit = 15000;
// enable module (this is a default value)
$config->enabled = true;
// start throttling
$x = new Throttle($config);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"".$zipname."\"");
header("Content-Transfer-Encoding: binary");
header("Content-type: application/force-download");
header("Content-Disposition: attachment; filename=\"".$zipname."\"");
header("Content-Length: ".filesize($directory_location . '/' . $zipname));
I am getting corrupted file, no actual size(4MB) and i get approximate (2KB) size. And if i use the readfile() function then i didn't found the throttle class working with readfile() :(
Can anyone please tell me, what wrong i have done here?
Try this:
$x = new Throttle($config);
$handle = fopen("yourfile.zip", "rb");
while (!feof($handle)) {
echo fread($handle, 8192);
flush();
}
fclose($handle);
You can also try ob_flush() instead of flush().
below is some part of code in my download gateway
if (!isset($_GET['f']) || empty($_GET['f'])) {die("<h1>URL Malfunction</h1><br/><p><i>Please Try Later</i>");}
if (strpos($_GET['f'], "\0") !== FALSE){ die("<h1>URL Malfunction</h1><br/><p><i>Please Try Later</i>");}
#Check URL, find resource Path
$fileName = basename($_GET['f']);
$file_path=(string)makeDownloadFilePath($fileName,"dir");
if(!is_file($file_path)){die("<h1>404 Not found</h1><br/><p><i>The resource you requested is not available</i>");}
$fileSize = filesize($file_path);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public"); #Build Response#
header("Content-Description: File Transfer");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=\"$fileName\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fileSize);
$file = #fopen($file_path,"rb");
if ($file) {
while(!feof($file)) { #File Transfer#
print(fread($file, 1024*8));
flush();
if (connection_status()!=0) {
#fclose($file);
die();
}
}
#fclose($file);
//The File is Downloaded . Closing Connections
I am using GET method to receive the filename. The filename and its path will e genrated from gateway. Now the problem is When i click on download in a page, instead of showing a Download dialog, the browser just renders the file content as text on screen. For eg, i am downloading foo.mp3. the binary contents are displayed as weird text on screen.
Its echoing a warning like: We cannot change the Headers. headers already sent to ...
Can any one tell , where i had made the mistake?
Thanks
We cannot change the Headers. headers already sent to..
This error comes when you print any thing before php your header command.
The most common cause of this error by a long, long way is that you have some leading white-space before the opening <?php tag in your file (or one of it's includes).
The < should be the first character in the file, anything before it is written to the output buffer directly and will probably result in the headers being sent. When forcing file download in this manner, it will also result in corrupted files.
Use readfile instead of fopen as follow and use ob_clean() , ob_flush() :
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$Name.'"');
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($musicPath));
ob_clean();
flush();
readfile($musicPath);
ob_flush();
Are you using the output buffer?
try adding ob_start(); before you send out the header information, this may solve your issue.
You can find out more information about it here
Thanks all for the help. The problem was i was using a
error_reporting(E_ALL);
ini_set('display_errors', true);
flush();
for debugging in one of my includes.
I just removed it.Now it works.