I'm using a script to download video, but it take lot of time to download. Are there any processes or other scripts that could help me?
// set headers
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: $mtype");
header("Content-Disposition: attachment; filename=\"$asfname\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fsize);
// download
// #readfile($file_path);
$file = #fopen($file_path,"rb");
if ($file) {
while(!feof($file)) {
print(fread($file, 1024*100));
flush();
if (connection_status()!=0) {
#fclose($file);
die();
}
}
#fclose($file);
}
Using the readfile() function (as you originally had) will allow you to spool directly from the file to output, rather than using a chunking loop and printing as you're doing. So why have you chosen to do this chunk loop?
As above, readfile() is one way.
The other, even more preferred method depends on your webserver. NginX, Lighttpd and there's also a module for Apache, allows you to pass a header with a filepath/name to the server, and it will send the file directly from the server itself, and so not need to use PHP resources to do it. If thats not possible, then readfile() is the best you probably have - if you can't just give someone a direct URL to download it.
Related
I have a zip files that I want users to be able to download. The trick is I don't want the users to see what the url is and I don't want to download the file to my server.
So I want users to click a link like this:
http://example.com/download/4
which server-side accesses my S3 bucket with this url:
https://s3.amazonaws.com/my-bucket/uploads/4.zip
I've tried cURL, using S3 methods, and various headers() in my download($file_id) function but can't get this to work. This has to be easy, right?
Your right, its quite easy. Probably you will have to write something like this:
$path = '/my-bucket/uploads/4.zip'; // the file made available for download via this PHP file
$mm_type="application/x-compressed"; // modify accordingly to the file type of $path, but in most cases no need to do so
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: " . $mm_type);
header("Content-Length: " .(string)(filesize($path)) );
header('Content-Disposition: attachment; filename="'.basename($path).'"');
header("Content-Transfer-Encoding: binary\n");
readfile($path); // outputs the content of the file
exit();
You set various headers to make your user download the .zip. Afterwards you put your file into the output buffer with readfile() Afterwards you end your script with exit() for security's sake. This should work for you! Remember to change the path to your file.
Thanks #Xatenev for the help. This is actually what worked for me:
$path = '/my-bucket/uploads/4.zip'; // the file made available for download via this PHP file
$mm_type="application/zip"; // modify accordingly to the file type of $path, but in most cases no need to do so
header("Content-Type: " . $mm_type);
header('Content-Disposition: attachment; filename="'.basename($path).'"');
readfile($path); // outputs the content of the file
exit();
What I am trying to implement is force download of a file through PHP.
There are 2 issues that I am facing, and I've broken my head thinking about what is possibly going wrong here.
Whenever I try to download the file using IE, the download gets interrupted about midway i.e. say my file is 1024Kb in size, around 500Kb is when the download stops as I get an error message in IE say 'Download was interrupted'
The other issue that I encounter frequently (but not always) is that the downloaded file (which is actually a zip file) gets corrupted at times for some reason! The file on the server is alright - if I download it directly from there, no issues at all. However, if I download using my PHP script and then try to unzip the file - Windows says 'Invalid or corrupt file...'
I really need some help on this.
Following is the block of code downloading the file:-
$fileName = "./SomeDir/Somefile.zip";
$fsize = filesize($fileName);
set_time_limit(0);
// required for IE, otherwise Content-Disposition may be ignored
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
// set headers
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=\"".basename($fileName)."\";");
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
header("Content-Length: " . $fsize);
// download
$file = #fopen($fileName,"rb");
if ($file) {
while(!feof($file)) {
print(fread($file, 1024*8));
flush();
if (connection_status()!=0) {
#fclose($file);
die();
}
}
#fclose($file);
}
Try this
<?php
$file = "./SomeDir/Somefile.zip";
set_time_limit(0);
$name = "Somefile.zip";
// Print headers and print to output.
header('Cache-Control:');
header('Pragma:');
header("Content-type: application/zip");
header("Content-Length: ". filesize($file));
header("Content-Disposition: attachment; filename=\"{$name}\"");
readfile($file);
?>
I think that your content-length reports more bytes than the amount really transferred.
Check in the server's log. The server could gzip the content and when it closes the connection the client is still waiting for the remaining declared bytes.
I'm using the following the PHP script to download a 20mb file:
(filepath & filename are set earlier in the script)
$fullPath = $filepath.$filename;
if ($fd = fopen($fullPath, "r")) {
// http headers for zip downloads
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/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($fullPath));
while(!feof($fd)) {
echo(fread($fd, 1024*8));
flush();
if (connection_status()!=0) {
fclose($fd);
die();
}
}
}
fclose($fd);
exit();
It works fine if the download finishes, but if the download is canceled by the user, and they click on the link to re-download, the server is completely unresponsive for several minutes, and then the download will begin. It seems like it is waiting for the script to time out...but isn't the "if (connection_status()!=0)..." part supposed to kil the script?
Any help is much appreciated! Thank you in advance!
I think you're over-engineering your solution somewhat. Try using readfile() instead of your fopen/fread loop.
Better yet, unless there's a compelling reason why you need PHP to mediate the file transfer, don't use a PHP script at all and simply provide a direct link to the file in question.
The best code is always the code you don't have to write.
For the past 3 months my site has been using a PHP file handler in combination with htaccess.
Users accessing the uploads folder of the site would be redirected to the handler as such:
RewriteRule ^(.+)\.*$ downloader.php?f=%{REQUEST_FILENAME} [L]
The purpose of the file handler is pseudo coded below, followed by actual code.
//Check if file exists and user is downloading from uploads directory; True.
//Check against a file type white list and set the mime type(); $ctype = mime type;
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
As of yesterday, the handler started returning garbled files, unreadable images, and had to be bypassed. I'm wondering what settings could have gone awry to cause this.
-EDIT-
Problem found, but not resolved. Including a path to a php library I was using for integrating with Wordpress was corrupting the files. Removing that block of code solves the corruption issue but leaves the files accessible without the desired authentication.
#include_once($_SERVER['DOCUMENT_ROOT'].'/wp-blog-header.php');
if(!is_user_logged_in())
{
auth_redirect(); //Kicks the user to a login page.
}
//resume download script
Maybe more tests will reveal the problem...
if ( !isset($filename) ) {
die('parameter "filename" not set');
}
else if ( !file_exists($filename) ) {
die('file does not exist');
}
else if ( !is_readable($filename) ) {
die('file not readable');
}
else if ( false===($size=filesize($filename)) ) {
die('stat failed');
}
else if ( headers_sent() || ob_get_length()>0) {
die('something already sent output.');
}
else {
$basename = basename($filename);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".$basename."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$size);
readfile($filename);
}
How are the files corrupted? Truncated? 0-byte? Completely different content? Random sections replaced with garbage?
Is it possible the server's PHP memory limit has been lowered? readfile() will buffer the whole file in memory before outputing it. Therefore a 40meg file will fail is the memory limit is 39.9999, kind of thing.
For streaming a file to the user, it's best to NOT use php's own "dump file to browser" functions, as they're all subject to the memory limit. It's best to do an fopen/fwrite/fclose loop and spit the file out in small manageable chunks (4k, 16k, etc...).
I am downloading a file from another server. I wish to push this file to my users rather than saving it to my server.
In other words, pass them the file handle so it just passes through my server and saves to their machine. How can I do this? I have this so far:
$handle = fopen($_GET['fileURL'], 'r');
$filename = stream_get_contents($handle);
How do I push this to the user, maybe using headers?
Thank you for any help and direction.
EDIT
I have the headers:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
Its just that it doesn't push the headers. I just get a blank page after about 15 seconds which looks like it downloading the file but not giving it to me.
I wish for the script to immediately send the headers to the user as a stream.
exit();
You can try this
$filetype = mime_content_type($filename);
header('Content-type: '.$filetype);
header('Content-Disposition: attachment; filename="'.$filename.'"');
UPDATE for your EDIT:
Do you have errors disabled, since this sounds like the headers already sent error?
error_reporting(E_ALL | E_STRICT);
You don't have to use fopen() when using readfile();
Just include the filename inside readfile() like this:
readfile($_GET['fileUrl']);
Although this is very dangerous security-wise as the user could specify any file on your file server. If you only have a few files you want someone to be able to download perhaps you should store them in an array (or database, preferebly)
Here's an array example:
$files = array('file1.jpg', 'file2.png', 'file3.pdf');
//assume $_GET['file_id'] == 0, 1 or 2
if (file_exists($files[$_GET['file_id']]))
readfile($files[$_GET['file_id']]);