I'm trying to display a .pdf file in a php application. It works perfectly well on my local development setup but on production, the same code displays the pdf as garbled text.
These are the request headers i'm using:
<?php
$file = $_GET["f"];
$filename = 'contrato.pdf';
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' .$filename. '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
readfile($file);
?>
These are the production response headers according to chrome:
Connection:Keep-Alive
Content-Encoding:gzip
Content-Type:text/html
Date:Mon, 03 Apr 2017 21:31:19 GMT
Keep-Alive:timeout=15, max=189
Server:Apache
Transfer-Encoding:chunked
Vary:Accept-Encoding
On the development setup, the response headers are these:
Accept-Ranges:bytes
Connection:Keep-Alive
Content-Disposition:inline; filename="contrato.pdf"
Content-Transfer-Encoding:binary
Content-Type:application/pdf
Date:Mon, 03 Apr 2017 21:33:44 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.7 (Win32) PHP/5.5.8
Transfer-Encoding:chunked
X-Powered-By:PHP/5.5.8
Could it be due to the apache settings?
I think it's the error in this line:
header('Content-type: application/pdf');
Note the small letter t
this line should be like this:
header('Content-Type: application/pdf');
also note that you are reading a file using the $_GET["f"]
this is wrong, instead read the file from $filename variable.
Change the last line to :
readfile($filename);
Anyway here's the correction of your code:
<?php
$file = $_GET["f"];
$filename = 'abc.pdf';
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' .$file. '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
readfile($filename);
?>
Related
On my site I have a <a download></a> link and also a php function that downloads files on my desktop just fine -
ob_start();
$nameOld = 'https://my-other-server.online/path/to/file.mp4';
$save = '/var/path/to/file.mp4';
$nameNew = "download.mp4";
file_put_contents($save, fopen($nameOld, 'r'));
set_time_limit(0);
header('Connection: Keep-Alive');
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header("Content-Disposition: attachment; filename=$nameNew");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($save));
while (ob_get_level()) {
ob_end_clean();
}
readfile($save);
exit;
unlink($save);
On mobile devices (iphone) this doesnt work on chrome browser. (Im already aware about safari ios downloads, even though I've seen some downloads prompt the user to open another app to continue.)
So I've tried using the <a></a> download link, but when clicking on it, it simply opens the video in a new tab and plays it.
If I try with a php script, it opens the video in a new tab and shows a crossed out play button (video is not even playable). I've been searching for an answer for days, I've edited .htaccess files and testing different scripts, content-types, headers, etc.
This is how the current script looks like for mobile specific -
... first few lines same as above script ...
file_put_contents($save, fopen($nameOld, 'r'));
//echo file_get_contents($save);
//$headers = get_headers($nameOld, 1);
//$filesize = $headers['Content-Length'];
//set_time_limit(0);
ob_clean();
//if(ini_get('zlib.output_compression'))
// ini_set('zlib.output_compression', 'Off');
//$fp = #fopen($save, 'rb');
//header('Connection: Keep-Alive');
//header('Content-Description: File Transfer');
//header('Content-Type: application/force-download');
//header('Content-Type: application/octet-stream');
header('Content-Type: video/mp4');
//header("Content-Disposition: attachment; filename=$nameNew");
header("Content-disposition: attachment; filename=\"" . basename($save) . "\"");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
//header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($save));
//ob_end_clean();
while (ob_get_level()) {
ob_end_clean();
}
//fpassthru($fp);
// fclose($fp);
readfile($save);
//exit;
unlink($save);
die();
I also tried testing printing on mobile the headers of one of the files -
print_r(get_headers($url));
print_r(get_headers($url, 1));
The output today is as follows, but yesterday the content-type said application/octet-stream ---
Array ( [0] => HTTP/1.1 200 OK [1] => Date: Wed, 27 Feb 2019 14:51:56 GMT [2] => Server: Apache/2.4.29 (Ubuntu) [3] => Last-Modified: Tue, 26 Feb 2019 14:16:19 GMT [4] => ETag: "3e7e3a-582ccb37e75a7" [5] => Accept-Ranges: bytes [6] => Content-Length: 4095546 [7] => Connection: close [8] => Content-Type: video/mp4 ) Array ( [0] => HTTP/1.1 200 OK [Date] => Wed, 27 Feb 2019 14:51:56 GMT [Server] => Apache/2.4.29 (Ubuntu) [Last-Modified] => Tue, 26 Feb 2019 14:16:19 GMT [ETag] => "3e7e3a-582ccb37e75a7" [Accept-Ranges] => bytes [Content-Length] => 4095546 [Connection] => close [Content-Type] => video/mp4 )
I've also checked my php info settings and didnt see anything that could be causing an issue, but then again Im not too sure what to look for.
I know its possible to download files on chrome mobile because other sites work for me, just not my own.
What am I doing wrong?
Add this as a header : 'X-Content-Type-Options: nosniff';
it is made to prevent browsers from interpreting themself the received content.
In association wth Content-disposition: attachment; ... the browser should offer to download it.
Are you sure you are using the format:
<a href="myvideo.mp4" download>Download</a>
And as miken32 mentioned :
"You're setting the MIME type to video/mp4. If the browser can play that kind of video, it will do so. Change it back to application/octet-stream."
EDIT:
You could also try to set this in your .htaccess file:
AddType application/octet-stream .mp4
And then change it back to application/octet-stream.
Try this.
A while ago trying to make a small application and the download tag just worked for me in Chrome. Like this:
Download
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'm trying to code a function in PHP to export some data to Excel file.
The problem is if I save it to the server it does work, but if I try to send to the browser using php://output it just doesn't work. It doesn't even show the download window. I' ve been getting these as response:
PK����a�B%���a��������[Content_Types].xml͔]K�0���%��f�
"�v��R���kX�����m��+����4�<�'��2�jgs6�,+��v����Sz���a�����tr5^�=Bb�9+c����,��9��.T"�kXr/�J,���[.��`ck6�?h�\��,���ܠ}3�c�C+��9�-E��|c�j�BKPN�+�d��u��O1�
o��Ba +���G�
The headers are:
Response Headers
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection Keep-Alive
Content-Disposition attachment;filename="Report.xlsx"
Content-Type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Date Wed, 29 May 2013 10:08:10 GMT
Expires Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive timeout=15, max=78
Last-Modified Wed, 29 May 2013 10:08:11 GMT
Pragma no-cache
Server Apache/2.2.14 (Ubuntu)
Transfer-Encoding chunked
X-Powered-By PHP/5.3.2-1ubuntu4.19
Request Headers
Accept */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cookie PHPSESSID=075r4aaqrvcnbca5sshjvm0jq7; 87293ba76812d31889be0901b086dd73=5h4jriq5c7r9vdt3m2u2u9up43; d82d00149fafbe651c9ba75a9804bbc9=en-GB
Host 150.145.139.3:8889
Referer
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:20.0) Gecko/20100101 Firefox/20.0
X-Requested-With XMLHttpRequest
Here's my code:
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
date_default_timezone_set('Europe/Rome');
require_once 'Classes/PHPExcel.php';
/** PHPExcel_IOFactory */
include 'Classes/PHPExcel/IOFactory.php';
$target ='templates/';
$fileType = 'Excel2007';
$InputFileName = $target.'richiesta.xlsx';
$OutputFileName = $target .'Richiesta_'.$_SESSION['User'].'_'.$_SESSION['Last'].'_'.$dat.'.xlsx';
//Read the file (including chart template)
$objReader = PHPExcel_IOFactory::createReader($fileType);
//$objReader->setIncludeCharts(TRUE);
$objPHPExcel = $objReader->load($InputFileName);
//Change the file
$objPHPExcel->setActiveSheetIndex(0)
// Add data
->setCellValue('C3','10' )
->setCellValue('C4','20' )
->setCellValue('C5','30')
->setCellValue('C5','40' );
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, $fileType);
//$objWriter->save($OutputFileName); //This one WORKS FINE!!!
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="Report.xlsx"');
$objWriter->save('php://output'); //NOT WORKING :-(
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel);
exit;
I'm getting depressed about this problem once I have to finish the project this week.
I really appreciate any kind of help!
That's just from my code, as a hint, the problem seems to be with the Content-Type HTTP header:
if (strtolower($type) == 'excel2003') {
$objWriter = PHPExcel_IOFactory::createWriter($this->excel, 'Excel5');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $outFileName . '"');
header('Cache-Control: max-age=0');
} else {
$objWriter = PHPExcel_IOFactory::createWriter($this->excel, 'Excel2007');
header('Content-Type: application/xlsx');
header('Content-Disposition: attachment;filename="' . $outFileName . '"');
header('Cache-Control: max-age=0');
}
Try using these header() calls:
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");;
header("Content-Disposition: attachment;filename=Report.xlsx");
header("Content-Transfer-Encoding: binary ");
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$filename = '1111';
ob_end_clean();
header("Content-Type: application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet");
header('Content-Disposition:attachment;filename="'.$filename.'.xlsx"');
header("Cache-Control: max-age=0");
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
exit();
I had the same problem, and it seems that a download must be opened in a different tab instead of just downloading in the same tab. Meaning you need to redirect into a new tab before initializing the download.
I have this code set up that lets a user download a file through my server from a URL they specify. The file streams through using readfile() so it only uses my bandwidth.
<?php
set_time_limit(0);
$urlParts = explode("/", $_SERVER['PHP_SELF']);
$file = $urlParts[3];
header("Cache-Control: public, must-revalidate");
header("Pragma: hack");
header("Content-Type: application/force-download");
header('Content-Disposition: attachment; filename=' . $file);
header("Content-Transfer-Encoding: binary\n");
readfile($file);
?>
This script works, but it does not change the CRC hash of the downloaded file. What I want it to do is append some random bits to the end of the file so it can change the hash without corrupting it. I have tried adding something like echo md5(rand() . time()); to the end of the script but it doesn't work.
If this is possible with something like cURL I'd appreciate if someone could put up some code samples, because i'd switch to cURL if this was possible.
Thanks for your help.
Hmm, your code works for me:
test.php:
set_time_limit(0);
$urlParts = explode("/", $_SERVER['PHP_SELF']);
//$file = $urlParts[3];
$file = 'toread.txt';
header("Cache-Control: public, must-revalidate");
header("Pragma: hack");
header("Content-Type: application/force-download");
header('Content-Disposition: attachment; filename=' . $file);
header("Content-Transfer-Encoding: binary\n");
readfile($file);
echo md5(rand() . time());
?>
toread.txt:
This is the content of toread.txt
Now using curl, I get the following results:
>curl -i http://example.com/test.php
HTTP/1.1 200 OK
Date: Tue, 04 Mar 2014 07:09:39 GMT
Server: Apache
Cache-Control: public, must-revalidate
Pragma: hack
Content-Disposition: attachment; filename=toread.txt
Content-Transfer-Encoding: binary
Transfer-Encoding: chunked
Content-Type: application/force-download
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Age: 0
This is the content of toread.txt38d8a8009fad7315bdf5e823a06018e7
And the second one:
>curl -i http://example.com/test.php
HTTP/1.1 200 OK
Date: Tue, 04 Mar 2014 07:09:57 GMT
Server: Apache
Cache-Control: public, must-revalidate
Pragma: hack
Content-Disposition: attachment; filename=toread.txt
Content-Transfer-Encoding: binary
Transfer-Encoding: chunked
Content-Type: application/force-download
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Age: 0
This is the content of toread.txt3b87356ea9ee007b70cfd619e31da950
Here is my issue. I am trying to call a page: foo.php?docID=bar and return a PDF to the screen which is stored as a BLOB in the DB.
Here is the portion of my code which actually returns the PDF:
$docID = isset($_REQUEST['docID']) ? $_REQUEST['docID'] : null;
if ($docID == null){
die("Document ID was not given.");
}
$results = getDocumentResults($docID);
if (verifyUser($user, $results['ProductId'])){
header('Content-type: application/pdf');
// this is the BLOB data from the results.
print $results[1];
}
else{
die('You are not allowed to view this document.');
}
This works perfectly fine in Firefox.
However, in IE, it doesn't show anything at all. If i'm on another page (i.e. google.com), and I type in the URL to go to this page, it will say it's done, but I will still have google.com on my screen.
I checked the headers for the responses from both firefox and IE. They are identical.
Does anyone have any suggestions? Need more information?
EDIT: If it helps at all, here's the response header and the first line of the content:
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 349930
Content-Type: application/pdf
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: PHP/5.1.2
Set-Cookie: PHPSESSID=cql3n3oc13crv3r46h2q04dvq4; path=/; domain=.example.com
Content-Disposition: inline; filename='downloadedFile.pdf'
X-Powered-By: ASP.NET
Date: Tue, 21 Apr 2009 16:35:59 GMT
%PDF-1.4
EDIT: Also, the page which pulls out the pdf file actually uses HTTPS instead of HTTP.
Thanks in advance,
~Zack
I figured out what the issue was. It's an IE bug dealing with IE, HTTPS and addons. (See here)
It was a caching issue. When I set:
header("Cache-Control: max-age=1");
header("Pragma: public");
(see here), the PDF was in cache long enough for the adobe reader add-on to grab it.
I had this issue too, i used the following which seems to work fine
header("Content-type: application/pdf");
header("Content-Length: $length");
header("Content-Disposition: inline; filename='$filename'");
Try this:
header("Content-Type: application/pdf");
header("Content-Disposition: inline; filename=foo.pdf");
header("Accept-Ranges: bytes");
header("Content-Length: $len");
header("Expires: 0");
header("Cache-Control: private");
Also, if you are using sessions, you can try setting
session_cache_limiter("none");
or
session_cache_limiter("private");
if ( USR_BROWSER_AGENT == 'IE' ) {
header( 'Content-Disposition: inline; filename="' . $name . '"');
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Pragma: public' );
} else {
header( 'Content-Disposition: attachment; filename="' . $name . '"' );
header( 'Expires: 0' );
header( 'Pragma: no-cache' );
}
This was the only header I needed to change:
header("Pragma: public");
I think you need to add more headers.
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Disposition: attachment; filename=THEFILENAME.pdf;");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . strlen($results[1]));