Is it possible to count only fully file downloads (when user click accept when save dialog apparents) using nginx or apache (php on backend, but nginx deliver files)?
A pure PHP solution could look like this (simplified):
<?php
$file = $_GET['file'];
check_if_file_is_ok_for_download($file);
header('Content-Type: ...');
header('Content-Length: ...');
header('Content-Dispostion: ...');
// more headers if necesarry ...
// output the file
readfile($file);
// count the finished download
database_add_finished_download($file);
Then use download links like:
http://yourserver.com/download.php?file=...
Which can be url-rewritten to something like:
http://yourserver.com/download/...
Related
I need to get a remote file and give it to user without saving it to my server disk (for hiding original URL) and found a lot of posts about download external files with various functions like file_get_contents or readfile. Already I'm using this one:
function startDownload($url){
if($this->url_exists($url))
{
//get filename from url
$name=$this->getFileName($url);
//first flush clear almost output
ob_end_flush();
//final clear
ob_clean();
//set headers
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . $name . "\"");
//send file to client;
readfile($url);
//exit command is important
exit;
}
else JFactory::getApplication()->enqueueMessage(JText::_('URL_NOT_FOUND'), 'error');
}
And that's working but there is a problem! For a file with 200 MB size it takes ~ 10 seconds to start download in client browser. I think it's because readfile first downloads whole file to my server buffer and then give it to user. Is that right?
And is it possible to make it faster? for example download be started before fetch ended or it isn't possible technically?
In fact I don't know that this method is optimised or not. Any technical advice would be appreciated.
Note :
I know that this function should be changed for big files and that's not my concern now.
I consider to buy the external server in the same datacenter to make this download faster.
Target is that [File server] be separate than the file [online shop].
I tested curl method that mentioned by #LawrenceCherone. It worked nicely but when moved it to my project the result was the same as readfile (white screen for a few seconds).
So suspect to readfile() function. Separate my previous code to a single PHP file and result was amazing! Download starts immediately.
So I think my guess wasn't right and problem was not related to readfile function.
After a little search found a minor modification. I added below line :
while (ob_get_level()) ob_end_clean();
before the :
readfile($url);
And now download starts before whole file fetched in my server.
On my web server, I have a bat (harmless) file.
And I have code,
Test Bat File
But when the user clicks, it shows the code instead of downloading the file.
You have to right click "save as.." to download the bat file.
Is there way that when a user clicks, it downloads (not having to right click save as)?
Maybe a pop up window that asks user if he/she wants to download the file or not?
you could write a php file, which adds a content-disposition header, sets the mime type to something binary and echo the files content.
Example:
file.php
$batchfile = file_get_contents('batchlocation');
$size = strlen($batchfile);
header('Content-Disposition: attachment; filename="downloaded.bat"');
header('Content-Type: BAT MIME TYPE or something like application/octet-stream');
header('Content-Lenght: '.$size);
echo $batchfile;
You can do so through setting the file in the PHP header() function.
It is explained here:
How to Automatically Start a Download in PHP?
I am doing the follwoing on a web page: A click on an element sends a set of data (attached to the element) to my server which will then generate a custom zip-file:
$.post(urlprefix + 'makeZip.php', params, function(data){
window.location = urlprefix + 'getZip.php?file=' + data; //get file
}).error(handleAJAXError);
makeZip.php works just fine and returns the name of the (temporary) zip file that the client should then download. As I want to keep my server clean I route the file through another script called getZip.php which does the following:
/* RETURN REQUESTED FILE AND DELETE FROM SERVER*/
$filename = $_GET['file'];
/* TRANSFER FILE CONTENTS */
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="customDownload.zip"');
header('Content-Length: '.filesize($filename));
readfile($filename);
/* REMOVE FILE FROM SERVER */
unlink($filename);
All browsers will download the file successfully, yet I am facing one problem: the files can get rather big (up to 200MB) so I thought it would be nice to have an estimate of how long the download's going to take. That's why I am sending the Content-Length header (the specified filesize is correct). Yet, all browsers I tested this is are telling me the filesize is unknown (which might lead to the user skipping the download).
Is this some kind of problem with my header information? Is it a client-side problem? Should I use another approach to getting the client to download the file?
If the client shows "unknown filesize" in the dialog when downloading a file provided via readfile, you'd better check if mod_deflate, mod_gzip, mod_something-that-shrinks-http is installed on your server, and put an exception for given download.
More info here
EDIT by m90:
In my particular case (running Apache) I turned shrinking off by using:
#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 0);
Filesize headers are sent and received correctly now in all browsers
I have a pdf file which is located off my webpage's root. I want to serve a file in ../cvs to my users using php.
Here is the code I have sofar:
header('Content-type: application/pdf');
$file = file_get_contents('/home/eamorr/sites/eios.com/www/cvs/'.$cv);
echo $file;
But when I call this php page, nothing gets printed! I'd like to simply serve the pdf file stored whose name is in $cv (e.g. $cv = 'xyz.pdf').
The ajax response to this PHP page returns the text of the pdf (gobbldy-gook!), but I want the file, not the gobbldy-gook!
I hope this makes sense.
Many thanks in advance,
Here's the AJAX I'm using
$('#getCurrentCV').click(function(){
var params={
type: "POST",
url: "./ajax/getCV.php",
data: "",
success: function(msg){
//msg is gobbldy-gook!
},
error: function(){
}
};
var result=$.ajax(params).responseText;
});
I'd like the user to be prompted to download the file.
Don't use XHR (Ajax), just link to a script like the one below. The HTTP headers the script outputs will instruct the browser to download the file, so the user will not navigate away from the current page.
<?php
// "sendfile.php"
//remove after testing - in particular, I'm concerned that our file is too large, and there's a memory_limit error happening that you're not seeing messages about.
error_reporting(E_ALL);
ini_set('display_errors',1);
$file = '/home/eamorr/sites/eios.com/www/cvs/'.$cv;
//check sanity and give meaning error messages
// (also, handle errors more gracefully here, you don't want to emit details about your
// filesystem in production code)
if (! file_exists($file)) die("$file does not exist!");
if (! is_readable($file)) die("$file is unreadable!");
//dump the file
header('Cache-Control: public');
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="some-file.pdf"');
header('Content-Length: '.filesize($file));
readfile($file);
?>
Then, simplify your javascript:
$('#getCurrentCV').click(function(){
document.location.href="sendfile.php";
});
How about using readfile instead? Provided that the file exists, that should work. Make sure your web process has permission to read the directory and the file. There is an example on the readfile page that sets some headers as well.
I'm trying to prompt the user to download the pdf file.
You can't (and don't need to) send a binary download to the user's browser using Ajax. You need to send the user to an actual URL where the PDF is located.
Use #timdev's code, and point the user there using e.g.
location.href = "scriptname.php";
It sounds like you're trying to serve the pdf to user for download via AJAX.
What you want to do is use AJAX to confirm the files exists, and security if any, then simply use js to redirect the browser to that files url, or in this case the url of the php script delivering the pdf. When your browser gets the pdf header it wont try to redirect the page itself but prompt for download, or whatever the users browser settings are.
Something like:
(js)
window.location.href = http://example.com/getApdf.php?which=xyz
(php)
if( !isset( $_GET['which'] ) ) die( 'no file specified' );
if( !file_exists( $_GET['which'] . '.pdf' ) ) die( 'file doesnt exist');
header('Content-type: application/pdf');
readfile( $_GET['which'] . '.pdf' );
This question is for those who have used PHP library FPDF (http://www.fpdf.org ) to generate PDF documents using PHP. I am generating a PDF file using the php file 'my_file.php'. I want users to be able to download that PDF file. But in the browser the see the file in the address bar as ..somepath..../my_file.php . I want them to see it as a file with .pdf extension. Any idea how this can be done ?
when you create the object and then try to make output like this
$filePath = "files/cache/myPdf.pdf";
$pdf=new FPDF('p');
...
$pdf->Output($filePath,'I');
you can change and send the file name
To force download:
$pdf->Output('D'); //Force download and set filename as 'doc.pdf'
or setting your own filename:
$pdf->Output('MyFilename.pdf','D');
Your browser shall not open another tab whit yourpath/my_file.php
You can't change the browser address bar, but you can change the address on your server. For example if you're using Apache, there's mod_rewrite which allows you to do such things.
If your problem is that when downloading the file, the browser wants to save it as .php, you could use those headers to force the download and a filename.
header('Content-Type: application/octet-stream');
header('Content-Length: ' . FILESIZE_HERE);
header('Content-Disposition: attachment; filename=' . FILENAME.pdf_HERE);