I am doing some work on a web site that has a secure area which is available to users only after they have logged in. In this area there is a page with links to pdf documents which can be downloaded. The physical documents are outside of the web site's root directory. The links to the pdf documents look something like this:
index.php?page=secure-area/download&file=protected.pdf
Which executes the following (note: I know this is the way to force a download rather than open the file inside the browser):
// check security, get filename from request, prefix document download directory and check for file existance then...
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Connection: Close');
set_time_limit(0);
readfile($file);
This works well but in Firefox 3 and Internet Explorer 7 (I haven't tested with any other browser) won't open this file inside the browser, they both show the download dialog box (as expected). If I select Open rather than Save, the document is downloaded and Adobe Reader is started outside of the browser to render the document.
The problem I have is downloading the file inside the browser and having the correct default file name if saved.
I would like the document to open in the browser. One way of doing this is using the header "Content-Disposition: inline;" but this means that I can't specify a filename (because is seems to be ignored by the browser). The problem with doing that is when I save the document, the default name is that of the URL, not the filename of the pdf document:
http___example.com_index.php_page=secure_area_download&file=protected.pdf
How can I get Firefox and Internet Explorer to open the document inside the browser and provide the correct default filename to save?
I've finally come up with a work around for this problem.
Although the RFC 2183 shows that a filename parameter can be used for both attachment and inline for the Content-Disposition header field, it seems that browsers ignore the filename parameter when inline is used but rather try to work out what the filename should be based on the URL. If the URL has no query string then the part of the URL that follows the last / seems to be used as the filename.
I have changed the links that download the protected PDF documents to use nice URLs that don't contain a query string and use mod_rewrite with a .htaccess file to convert those nice URLs to execute the correct script with the correct parameters:
Old link:
index.php?page=secure-area/download&file=document.pdf
New Link:
file/secure-area/download/document.pdf
.htaccess:
RewriteEngine On
RewriteRule ^file/secure-area/download/(.*)$ index.php?page=secure-area/download&file=$1 [L]
The script used to actually send the file is the same as I used before (note the example in the question uses Content-Disposition: attachment rather then Content-Disposition: inline to demonstrate browsers saving the document with the correct filename when not inline).
// check security, get filename from request, prefix document download directory and check for file existance then...
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($file) . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Connection: Close');
set_time_limit(0);
readfile($file);
Now the PDF document opens inside the browser and when saved the default filename is
document.pdf
and not
http___example.com_index.php_page=secure_area_download&file=document.pdf
IE 7 converts spaces in the filename to +'s and single quotes to %27's when saved (Firefox doesn't), I would like to stop that from happening but for the meantime I'm happy with what I've got.
Try using
Content-Disposition: inline;
No, what she is saying is it is not possible to specify the filename when 'Content-disposition:inline' is used. 'Filename' is only used when using 'Content-disposition:attachment', as in her first example. This results in the document being downloaded with the correct filename. However what this solution is trying achieve is a document rendered INLINE, which when downloaded from the browser uses the correct filename, instead of the script name.
Is there any other way of specifying the filename when using 'inline' other than url rewriting? The page I have written to render docs takes a database ID, so rewriting would be more difficult I think (the filename would have to be queried from the database).
Content-disposition:inline
can be used with the filename. But only some browsers undertand and follow this. The effect is seen only when you save the file name yourself, the filename you define with content disposition will be used.
You're telling it to do that by using Content-disposition: attachment. Try using Content-disposition: inline.