PHP readfile with PHPPowerpoint issue - php

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');

Related

Change saving directory in phpspreadsheet

Im using PhpSpreadsheet to generate XLS files, all the functions work perfect except that it saves local files in temporary directories and I want to save them in a specific folder.
use PhpOffice\PhpSpreadsheet\IOFactory;
require __DIR__ . '/Header.php';
$spreadsheet = require __DIR__ . '/templates/MyTemplate.php';
$filename = $helper->getFilename("MyFilename", 'xls');
$writer = IOFactory::createWriter($spreadsheet, 'Xls');
$callStartTime = microtime(true);
$writer->save($filename);
$helper->logWrite($writer, $filename, $callStartTime);
But the output is located in
Write Xls format to /var/folders/pn/lyj970q90lq20mjv39bpgx_80000gn/T/phpspreadsheet/MyFilename.xls in 0.0640 seconds
Is there an other function to set the saving directory I want the files in?
Use dot in path
$writer->save("./templates/MyFilename.xls");
On this line:
$filename = $helper->getFilename("MyFilename", 'xls');
Change to:
$filename = basename($helper->getFilename("MyFilename", 'xls'));
This way, $filename will only contain the file name. Then you can insert your path and make it work as you want, as I did with mine:
$writer->save('C:/xampp/htdocs/tmp/' . $outputFileName);
Make sure these lines are commented out. Since this parameter will tell the server to export Xlsx as downloadable file. Not in specific custom location.
// Redirect output to a client’s web browser (Xlsx)
// header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
// header('Content-Disposition: attachment;filename="'.$FileName.'"');
// 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
And finally you can save your file :
$writer->save("Location/Of/YourFolder".$YourFileName);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="myfile.xlsx"');
header('Cache-Control: max-age=0');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
source
https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#redirect-output-to-a-clients-web-browser

correct PHP headers for pdf file download

I'm really struggling to get my application to open a pdf when the user clicks on a link.
So far the anchor tag redirects to a page which sends headers that are:
$filename='./pdf/jobs/pdffile.pdf;
$url_download = BASE_URL . RELATIVE_PATH . $filename;
header("Content-type:application/pdf");
header("Content-Disposition:inline;filename='$filename");
readfile("downloaded.pdf");
this doesn't seem to work, has anybody successfully sorted this problem in the past?
Example 2 on w3schools shows what you are trying to achieve.
<?php
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");
?>
Also remember that,
It is important to notice that header() must be called before any
actual output is sent (In PHP 4 and later, you can use output
buffering to solve this problem)
$name = 'file.pdf';
//file_get_contents is standard function
$content = file_get_contents($name);
header('Content-Type: application/pdf');
header('Content-Length: '.strlen( $content ));
header('Content-disposition: inline; filename="' . $name . '"');
header('Cache-Control: public, must-revalidate, max-age=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');
echo $content;
There are some things to be considered in your code.
First, write those headers correctly. You will never see any server sending Content-type:application/pdf, the header is Content-Type: application/pdf, spaced, with capitalized first letters etc.
The file name in Content-Disposition is the file name only, not the full path to it, and altrough I don't know if its mandatory or not, this name comes wrapped in " not '. Also, your last ' is missing.
Content-Disposition: inline implies the file should be displayed, not downloaded. Use attachment instead.
In addition, make the file extension in upper case to make it compatible with some mobile devices. (Update: Pretty sure only Blackberries had this problem, but the world moved on from those so this may be no longer a concern)
All that being said, your code should look more like this:
<?php
$filename = './pdf/jobs/pdffile.pdf';
$fileinfo = pathinfo($filename);
$sendname = $fileinfo['filename'] . '.' . strtoupper($fileinfo['extension']);
header('Content-Type: application/pdf');
header("Content-Disposition: attachment; filename=\"$sendname\"");
header('Content-Length: ' . filesize($filename));
readfile($filename);
Technically Content-Length is optional but it is important if you want the user to be able to keep track of the download progress, and detect if the download was interrupted before the end. When using it you have to make sure you won't be send anything along with the file data. Make sure there is absolutely nothing before <?php or after ?>, not even an empty line.
I had the same problem recently and this helped me:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="FILENAME"');
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("PATH/TO/FILE"));
ob_clean();
flush();
readfile(PATH/TO/FILE);
exit();
I found this answer here
Can you try this, readfile need the full file path.
$filename='/pdf/jobs/pdffile.pdf';
$url_download = BASE_URL . RELATIVE_PATH . $filename;
//header("Content-type:application/pdf");
header("Content-type: application/octet-stream");
header("Content-Disposition:inline;filename='".basename($filename)."'");
header('Content-Length: ' . filesize($filename));
header("Cache-control: private"); //use this to open files directly
readfile($filename);
You need to define the size of file...
header('Content-Length: ' . filesize($file));
And this line is wrong:
header("Content-Disposition:inline;filename='$filename");
You messed up quotas.
header("Content-type:application/pdf");
// It will be called downloaded.pdf thats mean define file name would be show
header("Content-Disposition:attachment;filename= $fileName ");
// The PDF source is in original.pdf
readfile($file_url);

PHP - simple download script

I'm making a simple download script, where my users can download their own images etc.
But I'm having some weird problem.
When I've downloaded the file, it's having the contents from my index.php file no matter what filetype I've downloaded.. My code is like so:
$fullPath = $r['snptFilepath'] . $r['snptFilename'];
if (file_exists($fullPath)) {
#echo $fullPath;
// setting headers
header('Content-Description: File Transfer');
header('Cache-Control: public'); # needed for IE
header('Content-Type: '.$r['snptFiletype'].'');
header('Content-Disposition: attachment; filename='. $filename . '.' . $r['snptExtension']);
header('Content-Length: '.$r['snptSize'].'');
readfile($fullPath)or die('error!');
} else {
die('File does not exist');
}
$r is the result from my database, where I've stored size, type, path etc. when the file is uploaded.
UPDATE
When I'm uploading and downloading *.pdf files it's working with success. But when I'm trying to download *.zip and text/rtf, text/plain it's acting weird.
By weird I mean: It downloads the full index.php file, with the downloaded file contents inside of it.
ANSWER
I copied this from http://php.net/manual/en/function.readfile.php and it's working now. It seems that : ob_clean(); did the trick! Thanks for the help everyone.
#setting headers
header('Content-Description: File Transfer');
header('Content-Type: '.$type);
header('Content-Disposition: attachment; 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);
exit;
Try this function , or implement these headers to your code
function force_download($filename) {
$filedata = #file_get_contents($filename);
// SUCCESS
if ($filedata)
{
// GET A NAME FOR THE FILE
$basename = basename($filename);
// THESE HEADERS ARE USED ON ALL BROWSERS
header("Content-Type: application-x/force-download");
header("Content-Disposition: attachment; filename=$basename");
header("Content-length: " . (string)(strlen($filedata)));
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");
// THIS HEADER MUST BE OMITTED FOR IE 6+
if (FALSE === strpos($_SERVER["HTTP_USER_AGENT"], 'MSIE '))
{
header("Cache-Control: no-cache, must-revalidate");
}
// THIS IS THE LAST HEADER
header("Pragma: no-cache");
// FLUSH THE HEADERS TO THE BROWSER
flush();
// CAPTURE THE FILE IN THE OUTPUT BUFFERS - WILL BE FLUSHED AT SCRIPT END
ob_start();
echo $filedata;
}
// FAILURE
else
{
die("ERROR: UNABLE TO OPEN $filename");
}
}
I copied this from http://php.net/manual/en/function.readfile.php and it works now. ob_clean(); did the trick..
#setting headers
header('Content-Description: File Transfer');
header('Cache-Control: public');
header('Content-Type: '.$type);
header("Content-Transfer-Encoding: binary");
header('Content-Disposition: attachment; filename='. basename($file));
header('Content-Length: '.filesize($file));
ob_clean(); #THIS!
flush();
readfile($file);

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

Serve file to user over http via php

If I goto http://site.com/uploads/file.pdf I can retrieve a file.
However, if I have a script such as:
<?php
ini_set('display_errors',1);
error_reporting(E_ALL|E_STRICT);
//require global definitions
require_once("includes/globals.php");
//validate the user before continuing
isValidUser();
$subTitle = "Attachment";
$attachmentPath = "/var/www/html/DEVELOPMENT/serviceNow/selfService/uploads/";
if(isset($_GET['id']) and !empty($_GET['id'])){
//first lookup attachment meta information
$a = new Attachment();
$attachment = $a->get($_GET['id']);
//filename will be original file name with user name.n prepended
$fileName = $attachmentPath.$_SESSION['nameN'].'-'.$attachment->file_name;
//instantiate new attachmentDownload and query for attachment chunks
$a = new AttachmentDownload();
$chunks= $a->getRecords(array('sys_attachment'=>$_GET['id'], '__order_by'=>'position'));
$fh = fopen($fileName.'.gz','w');
// read and base64 encode file contents
foreach($chunks as $chunk){
fwrite($fh, base64_decode($chunk->data));
}
fclose($fh);
//open up filename for writing
$fh = fopen($fileName,'w');
//open up filename.gz for extraction
$zd = gzopen($fileName.'.gz', "r");
//iterate over file and write contents
while (!feof($zd)) {
fwrite($fh, gzread($zd, 60*57));
}
fclose($fh);
gzclose($zd);
unlink($fileName.'.gz');
$info = pathinfo($fileName);
header('Content-Description: File Transfer');
header('Content-Type: '.Mimetypes::get($info['extension']));
header('Content-Disposition: attachment; filename=' . basename($fileName));
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($fileName));
ob_clean();
flush();
readfile($fileName);
exit();
}else{
header("location: ".$links['status']."?".urlencode("item=incident&action=view&status=-1&place=".$links['home']));
}
?>
This results in sending me the file, but when I open it I receive an error saying:
"File type plain text document (text/plain) is not supported"
First off, I'd start by checking the HTTP headers. You can do this in Firefox easily using the "Live HTTP headers" extension; not sure about equivalents in other browsers offhand. This will let you verify if the header is actually getting set to "application/pdf" and whether your other headers are getting set as well.
If none of the headers are getting set, you might be inadvertently sending output before the calls to header(). Is there any whitespace before the <?php tag?
Are you sure application/pdf is the header your browser is actually seeing?
You can check that out with various HTTP dev tools, for instance HTTP Client for the Mac or Firebug for Firefox.
I use this one and it works.
if(file_exists($file_serverfullpath))
{
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
//sending download file
header("Content-Type: application/octet-stream"); //application/octet-stream is more generic it works because in now days browsers are able to detect file anyway
header("Content-Disposition: attachment; filename=\"" . basename($file_serverfullpath) . "\""); //ok
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($file_serverfullpath)); //ok
readfile($file_serverfullpath);
}
Try prepending "error_reporting(0);". I found this in the comments at http://php.net/readfile (where you took this example from).
Another thing that could be a problem is your file size. There have been issues reported in the past about PHP5 (we're talking 2005 here, so i hope this is fixed by now) having trouble reading files >2MB. If your file size exceeds this you may want to verify that it reads the whole file.

Categories