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.
Related
I am loading an mp3 into an html <audio> tag. The source of that tag is really a php script which returns a song that is not hosted in the public directory.
Omitting most of validation and other code, the headers used to output the mp3 are:
header( 'Content-type: {$mime_type}' );
header( 'Content-length: ' . filesize( $file ));
header( 'Content-Disposition: inline;filename="'.$filename.'"' );
header( 'Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0' );
header( 'Pragma: no-cache' );
header( 'Content-Transfer-Encoding: binary');
header( 'Expires: 0');
readfile( $file );
This works on Firefox, Chrome (and mobile), Edge (and mobile) and Opera. However I can't seem to get Safari to use the generated url as an audio source. In fact, no audio source appears in the DOM after the page has rendered:
The url might look like, www.website.com/song.php?sid=234234234234
I have tried tweaking this file plenty of times but can't see to figure out why this is happening on Safari. My intuition is the way the browser deals with mp3s and the like, which should be dealt with in the header.
Any guidance, hints or help would be appreciated.
Thanks.
update:
Added the network, shows that it loads the mp3 but then the second request doesn't?
response headers:
Name Value
Server Apache
Content-Type audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3
Date Wed, 28 Dec 2016 17:24:48 GMT
Cache-Control no-cache
X-Powered-By PHP/5.3.29
Content-Disposition inline;filename="148_2793d1c49976a3689147634359577ec1aa5619f1.mp3"
Content-Length 834312
Expires 0
Connection Keep-Alive
Content-Transfer-Encoding binary
Accept-Ranges bytes
Keep-Alive timeout=5, max=100
Pragma no-cache
You need to pass the Multiple ranges header, because it's a partial content: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
header("Accept-Ranges: 0-filesize( $file )");
EDIT
Take a look here:
http://www.techstruggles.com/mp3-streaming-for-apple-iphone-with-php-readfile-file_get_contents-fail/
You need to define some headers for safari, even for the mobile version.
I had this issue sometime ago, sorry if I don't remember correctly how I fixed that, but is a header issue (its the main part I can remember, and I don't use comments for adding the answer because its too long)
Try with this..
header( 'Accept-Ranges: bytes');
header("Pragma: public");
header("Expires: 0");
header('Cache-Control: no-cache, no-store');
header('Content-Transfer-Encoding: binary');
header('Content-Disposition: inline; filename="'.$filename.'"');
header('Content-Length: '.$fsize);
header('Content-Type: audio/'.$t);
header('Accept-Ranges: bytes');
header('Connection: Keep-Alive');
header('Content-Range: bytes 0-'.$shortlen.'/'.$fsize);
header('X-Pad: avoid browser bug');
header('Etag: '.$etag);
Where:
$filename = "myaudio.mp3";
$path = 'music/'.$filename;
$fsize = filesize($path);
$shortlen = $fsize - 1;
$fp = fopen($path, 'r');
$etag = md5(serialize(fstat($fp)));
fclose($fp);
$t = "mpeg";
Hope this helps, but the 2 main headers you need is "Etag" and "Accept-Ranges" if I'm not wrong.
I am using PHPPowerpoint to create a pptx file with some charts, and have no problem storing it in the same folder as the PHP script. PHPPowerpoint does that on itself.
I want to download the pptx file after it has been created, and so far I have tried every option I could locate on the web. This is how i try to do it atm.:
$file = str_replace('generate_report.php', 'export_download.pptx', __FILE__);
header('Content-Description: File Transfer');
header('Content-disposition: attachment; filename="' . $file . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation');
header('Expires: 0');
header('Cache-Control: ');
header('Pragma: ');
flush();
ob_clean();
readfile($file);
Nothing is downloaded when I execute the script. My pptx is created on the server and I can open it, no problem. But it wont download the file. I got the content type from this thread: What is a correct mime type for docx, pptx etc?. I also tried with many other types. When I console log my response i get a weird string (very long), beginning like this: PKCTDD����[Content_Types].xml͗�n�0E�|E�-J��*�X�����+���m���wBhE
Also tried this:
$handle = fopen($file, 'rb');
$buffer = '';
while (!feof($handle)) {
$buffer = fread($handle, 4096);
echo $buffer;
ob_flush();
flush();
}
fclose($handle);
Anybody who can help?
The following headers should work; and it's also better streaming directly to php://output rather than save to disk file and then spooling that disk file to the browser
// Redirect output to a client’s web browser
header('Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation');
header('Content-Disposition: attachment;filename="' . $file . '"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
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'); // HTTP/1.0
$objWriter = PHPPowerPoint_IOFactory::createWriter($objPHPPowerPoint, 'PowerPoint2007');
$objWriter->save('php://output');
I'm trying to display a PDF in the browser if possible--and I know I can do this in Chrome, which is what I'm testing in. The trouble is, every time I try, it prompts a download instead.
I'm using PHP sessions, so I know there are some extraneous headers being sent, so I called header_remove() to reset everything.
I call this function to show the PDF:
<?php
// For demonstrative purposes
session_start();
if (!isset($_SESSION['auth'])) {
header('Location: login.php');
die;
}
/*
* void viewPDF (Report $report)
* Outputs the PDF of the report
*/
function viewPDF ($report) {
// Tell the browser we are going to serve a PDF file.
$file = dirname(__FILE__).'/../reports/'.$report->id.'.pdf';
// The location of the PDF
if (!file_exists($file)) {
die ('The PDF does not exist.');
// Somehow the file does not exist.
}
header_remove();
// I'm using PHP sessions, so remove the headers
// automatically set that might break something.
header('Content-Disposition: inline;filename='.$report->id.'.pdf');
header('Content-Transfer-Encoding: binary');
header('Content-Type: application/pdf');
header('Content-Length: '.filesize($file));
readfile($file);
// Serve the report PDF file from the reports
// repository.
die;
// Any whitespace could corrupt the PDF, so be extra
// sure nothing else gets printed.
}
// For demonstrative purposes:
$report = new StdClass;
$report->id = 1;
viewPDF($report);
?>
These are the headers being sent:
Date: Tue, 08 Oct 2013 18:41:32 GMT
Server: Apache/2.2.22 (Win32) PHP/5.4.15
Content-Type: application/pdf
Content-Transfer-Encoding: binary
Content-Disposition: inline;filename=1.pdf
Connection: Keep-Alive
Keep-Alive: timeout=5, max=100
Content-Length: 73464
It's still prompting a download though. Once it downloads, I can open it in Adobe Reader just fine.
Am I missing something?
Thanks.
This code worked for me :
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($file).'"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
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
I am trying to generate an excel file with php. This works fine in Firefox but with IE I am only getting an empty file. This is what I am doing basically:
header('Content-type: application/ms-excel');
header('Content-Disposition: inline; attachment; filename='.$filename);
echo $data;
I have tried various header settings but no success. I have also tried to output the content as a text file, same result here. No content in IE.
Any ideas?
header("Cache-Control: no-stor,no-cache,must-revalidate");
header("Cache-Control: post-check=0,pre-check=0", false);
header("Cache-control: private");
header("Content-Type: application/octet-stream");
header('Content-Disposition: inline; attachment; filename='.$filename);
header("Content-Transfer-Encoding: binary");
header("Pragma: no-cache");
header("Expires: 0");
--
header('Pragma: public');
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: pre-check=0, post-check=0, max-age=0');
header ("Pragma: no-cache");
header("Expires: 0");
header('Content-Transfer-Encoding: none');
header('Content-Type: application/vnd.ms-excel;');
header("Content-type: application/x-msexcel");
header('Content-Disposition: inline; attachment; filename='.$filename);
Just two Options, also tried some other combinations.
Thanks,
Roland
Had the same problem: IE times out after some short time if it doesn't get a response, even if the TCP connection is still open. What helped me was this: disable output buffering, send headers and flush them out. Send data when you have them. This was enough to keep the connection open.
Something like this:
// reset all output buffering
while (ob_get_level() > 0) {
ob_end_clean();
}
header('Content-type: application/ms-excel');
header('Content-Disposition: inline; attachment; filename='.$filename);
// we can't send any more headers after this
flush();
$excel = new PhpExcel();
$excel->setActiveSheetIndex(0);
$sheet = $excel->getActiveSheet();
// in this example, $data was an array in the format row => value
// data structure is not relevant to issue
foreach ($data as $key => $value) {
// add data to sheet here
$sheet->SetCellValue('A' . $key, $value);
// etc...
}
$writer = new PHPExcel_Writer($excel);
// push to browser
$writer->save('php://output');
Set your header to header("Content-Type: application/octet-stream"); to force a download.
or another version of your header is adding vnd so application/vnd.ms-excel but if you send this header then you should also send your current header along side it as some browsers vary.