Anyway to bring up the 'Open / Save' dialogue for the user? - php

Not sure if the title makes sense sorry... basically I'm generating Word documents that I wanted to open automatically on the client's machine, but it seems this isn't possible, so instead of just presenting a list and having them manually click on each one, I was wondering if at the very least it could bring up the 'Would you like to save or open this file' dialogue :(
Long shot, but I know a lot of sites will do this when you download stuff... re-directing to download server etc
Thanks

The best you can do is provide a "hint" with the Content-disposition header.
http://php.net/manual/en/function.header.php
Specifying something like
<?php
header('Content-type: application/msword');
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// output content of document
?>
should cause most browsers to prompt the user to download the document, while this:
header('Content-Dispotion: inline')
should usually cause the browser to show the file in the existing window.

You can set the contenttype and content-disposition header to open the open/save dialog box in browser.
See
Header Field Definition
for details.

You need to send the correct header and so on.
I found this that seems good:
<?php
function send_file($name) {
ob_end_clean();
$path = "protected/".$name;
if (!is_file($path) or connection_status()!=0) return(FALSE);
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Content-Type: application/octet-stream");
header("Content-Length: ".(string)(filesize($path)));
header("Content-Disposition: inline; filename=$name");
header("Content-Transfer-Encoding: binary\n");
if ($file = fopen($path, 'rb')) {
while(!feof($file) and (connection_status()==0)) {
print(fread($file, 1024*8));
flush();
}
fclose($file);
}
return((connection_status()==0) and !connection_aborted());
}
?>
And here's an example of using the function:
<?php
if (!send_file("platinumdemo.zip")) {
die ("file transfer failed");
// either the file transfer was incomplete
// or the file was not found
} else {
// the download was a success
// log, or do whatever else
}
?>

Related

PHP File Download - Maximum execution time occurs randomly

It seems I have a problem with file downloading. My logs show the error "Maximum execution time of 60 seconds exceeded" but the requested file is just a little css-file with only 1.64 KB. So it shouldn't take 60 seconds to deliver and unfortunately the error is not exactly reproducable. If I open the url it works perfectly, but my errorlog shows errors occuring (randomly?) on other clients several times. Is there a bug in my code?
// this code is from: http://www.richnetapps.com/the-right-way-to-handle-file-downloads-in-php/
// fix for IE catching or PHP bug issue
header("Pragma: public");
header("Expires: -1"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); // browser must download file from server instead of cache
if(substr($filename, -4) == ".css")
{
$mimeType = "text/css";
}
header("Content-Type: ".$mimeType);
header("Content-length: ".$filesize);
$filehandle = fopen($filename, "rb");
// large file handling:
while(!feof($filehandle))
{
print(#fread($filehandle, 1024*8));
ob_flush();
flush();
if(connection_status() != 0)
{
#fclose($filehandle);
unlink($filename);
exit;
}
}
#fclose($filehandle);
unlink($filename);
exit;
The errorline is always within the while-loop, but it's not always the same line.
Thanks for help! :)
Why all this OB fuss for a simple css output? I am sure its that connection status check which causes your request to hang sometimes.
if(connection_status() != 0) // that specifically
Why do you even need it? You can simply do
header("Pragma: public");
header("Expires: -1"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: text/css");
header("Content-length: ".$filesize);
readfile($filename);

download file with php

i want to create a link to download an excel file from the root in server computer, using php. so i wrote a simple code as below,
<?php
header("Content-disposition: attachment; filename=example.xls");
header("Content-type: application/vnd.ms-excel");
readfile("example.xls");
?>
it then can be downloaded however when i want to open it, i got the error saying the file i downloaded is in a different format than specified by the file extension. i also tried the same method with jpeg file and didnt get the same error but when i click it, it shows nothing. can someone help me? im not very good with programming. thank you in advance!
Try this
$file='example.xls'; $filesize=filesize($file);
header("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
header("Pragma: no-cache");
header('Content-type: application/vnd.ms-excel');
header('Content-Disposition: inline; filename="'.basename($file).'"');
header("Content-Length: " . $filesize);
$fh = fopen("$file, "rb");
// output file
while(!feof($fh))
{
# output file without bandwidth limiting
print(fread($fh, filesize($file)));
}
fclose($fh);

set-cookie header multiple times

I have this code in a assets controller to get images:
function images($path,$image_name)
{
$image = "../assets/images/$path/$image_name";
if (file_exists ($image) && (is_file($image))) {
$name = $image_name;
} else {
}
$file = getimagesize($image);
$filesize = filesize($image);
$time_cache = 360000000000;
$ts = gmdate("D, d M Y H:i:s", time() + $time_cache) . " GMT";
header("Content-Type: {$file['mime']}\n");
header("Content-disposition: inline; filename=\"$name\"\n");
header("Content-Length: $filesize\n");
header("Expires: $ts");
header("Pragma: cache");
header("Cache-Control: max-age=$time_cache");
readfile ($image);
}
I have set csrf protection to true in config/config.php file and every request for an image is sent with Set-Cookie header. So the csrf-cookie can get set multiple times on some pages. Is that something to worry about, and if so, is there a way to prevent this?
I managed to do this with header_remove("set-cookie");
So the code looks like this
header("Content-Type: {$file['mime']}\n");
header("Content-disposition: inline; filename=\"$name\"\n");
header("Content-Length: $filesize\n");
header("Expires: $ts");
header("Pragma: cache");
header("Cache-Control: max-age=$time_cache");
header_remove("set-cookie");
readfile ($image);
If in only one page/image request you uses setcookie function many times, php will send many times the same cookie to browser in one response. Maybe some browsers crashes reading that.
I've had problems with ajax requests in Internet Explorer due to multiple cookie definitions, when accidentally start the session object in CakePHP into a loop. I only detected that problem sniffing the connection with wireshark.

Force file download in php

I have built a simple file manager where users can download any type of file such as pdf, word or gif files. I want all of them to download file rather than view it in browsers. The uploaded filenames are stored in database.
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>
http://php.net/manual/en/function.header.php
You can use the "Content-Disposition" header for that:
header("Content-Disposition: attachment");
The PHP manual provides an excellent example for that.
Normally setting the Content-Disposition to attachment before sending a file force a download by the browser.
You either need to configure your web server to provide this header for the files or send them yourself via PHP, sending a specific header before like :
header('Content-Disposition: attachment; filename=your_file_name.pdf');
Beware that the first solution is better as you won't risk your downloads being cut because the script running time is too long (you could also alter it).
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT\n");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Content-type: application/pdf;\n");
$len = filesize($filename);
header("Content-Length: $len;\n");
header("Content-Disposition: attachment; filename=\"downfile.pdf\";\n\n");
echo readfile($filename)
source code taken from the TCPDF library
// download PDF as file
if (ob_get_contents()) {
$this->Error('Some data has already been output, can\'t send PDF file');
}
header('Content-Description: File Transfer');
if (headers_sent()) {
$this->Error('Some data has already been output to browser, can\'t send PDF file');
}
header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
// force download dialog
if (strpos(php_sapi_name(), 'cgi') === false) {
header('Content-Type: application/force-download');
header('Content-Type: application/octet-stream', false);
header('Content-Type: application/download', false);
header('Content-Type: application/pdf', false);
} else {
header('Content-Type: application/pdf');
}
// use the Content-Disposition header to supply a recommended filename
header('Content-Disposition: attachment; filename="'.basename($name).'";');
header('Content-Transfer-Encoding: binary');
$this->sendOutputData($this->getBuffer(), $this->bufferlen);
break;
anyways the most important part is
header('Content-Disposition: attachment; filename="'.basename($name).'";');
and notice that final ; inside the string, without it, it won't work

header() problem in IE

I have a function for outputting documents, images etc:
public function direct($theMimeType, $thePath)
{
header('Content-type: '.$theMimeType);
ob_clean(); // clean output buffer
flush(); // flush output buffer
readfile($thePath);
exit;
}
It works great in Firefox. The file opens whether it is PDF, DOCX or any other file. However, in IE it freezes and nothing shows up.
What could cause this?
EDIT:
I have added few other headers:
public function direct($theMimeType, $thePath)
{
$aSize = filesize($thePath);
$aBegin = 0;
$aEnd = $aSize;
$aFilename = end(explode('/', $thePath));
$aTime = date('r', filemtime($thePath));
$aContentDisposition = ('application/pdf' === $theMimeType) ? 'inline' : 'atachment';
header('HTTP/1.0 200 OK');
header("Content-Type: $theMimeType");
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Accept-Ranges: bytes');
header('Content-Length:'.($aEnd-$aBegin));
header("Content-Range: bytes $aBegin-$aEnd/$aSize");
header("Content-Disposition: $aContentDisposition; filename=$aFilename");
header("Content-Transfer-Encoding: binary\n");
header("Last-Modified: $aTime");
header('Connection: close');
ob_clean(); // clean output buffer
flush(); // flush output buffer
readfile($thePath);
exit;
}
Well, it works in IE now but still it opens the file much slower than Firefox. There seems to be few seconds freeze up before the IE browser opens the file.
Make this file download directly, not using any scripts
make sure it works in IE
in firefox, use LiveHTTPHeaders to watch what headers being sent by web-server
in firefox, use LiveHTTPHeaders to watch what headers being sent by your script
make your script's headers the same as web-server's
Most of those headers aren't really necessary. I prefer to keep things simple:
header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header ('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); // always modified
header ('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header ('Pragma: public');
header ('Content-Type: '.$theMimeType);
header ('Content-Disposition: '.$aContentDisposition.'; filename="'.$aFilename.'"');
header ('Content-Transfer-Encoding: binary');
header ('Content-Length: '.$aSize);
Watch out for the \n at the end of your Content-Transfer-Encoding header.
The 'Pragma: public' is a workround specifically to handle a problem with IE and https connections. The other key difference is $aFilename in quotes.

Categories