Update
Just found out from my error logs readfile() has been disabled for security reasons Any alternatives instead of readfile()? Will fopen or fread work with zip files?
==================================================================================
My script:
<?php
$str = "some blah blah blah blah";
file_put_contents('abc.txt', $str); // file is being created
create_zip(array('abc.txt'), 'abc.zip'); // zip file is also being created
// now creating headers for downloading that zip
header("Content-Disposition: attachment; filename=abc.zip");
header("Content-type: application/octet-stream; charset=UTF-8");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: public");
header('Content-Transfer-Encoding: binary'); // added this line as per suggestion
header('Content-Length: ' . filesize("abc.zip")); // added this line as per suggestion
readfile("abc.zip");
//echo 'do something'; // just for testing purpose to see if code is running till the end
exit;
When I run the above script, I get a blank page (No download prompt). When I uncomment the "do something" line, I get that on the screen. So the script is running till the last line.
I also put error_reporting(E_ALL) at the top of the page but nothing is showing up.
What am I missing here?
Try adding Content-Length headers.
See PHP readfile() documentation for a full example.
One alternative to readfile() would be to echo the link to the ZIP file itself where people can simply click on it and will then be prompted to save the file.
Using: echo "<a href='$filename'>File download</a>";
PHP
<?php
$str = 'some blah blah blah blah';
$zip = new ZipArchive();
$filename = "abc.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)==TRUE) {
$zip->addFromString("abc.txt", $str);
$zip->close();
}
echo "<a href='$filename'>File download</a>";
exit();
?>
This is usually the way to ZIP a file then open up a prompt to save file as...
<?php
ob_start();
$str = 'some blah blah blah blah';
$zip = new ZipArchive();
$filename = "abc.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open <$filename>\n");
}
$zip->addFromString("abc.txt", $str);
$zip->close();
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
clearstatcache();
header("Content-Length: ".filesize('abc.zip'));
ob_flush();
readfile('abc.zip');
?>
Related
I tried to write a php-script to create and download a zip file. When I tested the script on my localhost, the download works, but when it's uploaded to the server, things go wrong: instead of downloading the zip file, the content of the file is displayed in the browser.
Can somebody point me in the right direction?
The code
$zip = new ZipArchive();
$zip->open("$maand/zipfile.zip", ZipArchive::OVERWRITE);
$zip->addFile("$maand/ant/a_nb.txt", 'ant.txt');
$zip->addFile("$maand/lim/l_nb.txt", 'lim.txt');
$zip->addFile("$maand/oos/o_nb.txt", 'oos.txt');
$zip->addFile("$maand/vla/v_nb.txt", 'vla.txt');
$zip->addFile("$maand/wes/w_nb.txt", 'wes.txt');
$zip->close();
$filename = "zipfile.zip";
$filepath = "$maand/";
// headers for zip downloads
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Length: ".filesize($filepath.$filename));
ob_end_flush();
#readfile($filepath.$filename);
you missing ob_start()
example:
header('Content-Type: application/csv');
header('Content-Disposition: attachement; filename="' . $download . '"');
ob_start();
$str = '';
if(file_exists($file) === true){
$str = file_get_contents($file);
}
ob_end_clean();
echo $str;
I have a script that outputs an image.
Works fine
include('../myfolder/myImageScript.php'); // outputs image on page
Fails
echo file_get_contents('../myfolder/myImageScript.php'); // nothing displayed
I think this fails because in php a script, in my case myImageScript.php, isn't executed when called via the file_get_contents() function, but is when called using a include() the script is executed.
I am struggling to get a zip function to work due to the empty output of file_get_contents().
the file i'm trying to call via file_get_contents() is:
myImageScript.php
$imgstr = "data:image/jpeg;base64,/9j/........... rest of string";
if (!preg_match('/data:([^;]*);base64,(.*)/', $imgstr, $matches)) {
die("error");
}
// Decode the data
$content = base64_decode($matches[2]);
// Output the correct HTTP headers
header('Content-Type: '.$matches[1]);
//header("Content-Type: image/jpeg"); // tried this made no difference
// Output the actual image data
echo $content;
Any help would be greatly appreciated.
Something like this should work, BUT you need to enable ZipArchive http://php.net/manual/en/class.ziparchive.php (should not be a problem)
<?php
$imgstr = "data:image/gif;base64,R0lGODlhyAAiALMAAFONvX2pzbPN4p6/2tTi7mibxYiw0d/q86nG3r7U5l2UwZO31unx98nb6nOiyf///yH5BAUUAA8ALAAAAADIACIAAAT/8MlJq7046827/2AojmRpnmiqriwGvG/Qjklg28es73wHxz0P4gcgBI9IHVGWzAx/xqZ0KlpSLU9Y9MrtVqzeBwFBJjPCaC44zW4HD4TzZI0h2OUjON7EsMd1fXcrfnsfgYUSeoYLPwoLZ3QTDAgORAoGWxQHNzYSBAY/BQ0XNZw5mgMBRACOpxSpnLE3qKqWC64hk5WNmBebnA8MjC8KFAygMAUCErA2CZoKq6wHkQ8C0dIxhQRED8OrC1hEmQ+12QADFebnABTr0ukh1+wB20QMu0ASCdn16wgTDmCTNlDfhG/sFODi9iMLvAoOi6hj92LZhHfZ3FEEYNEDwnMK/ykwhDEATAN2C/5d3PiDiYSIrALkg6EAz0hiFDNFJKeqgIEyM1nhwShNo0+glhBhgKlA5qqaE25KY1KAYkGAYlYVSEAgQdU1DFbFe3DgKwysWcHZ+QjAAIWdFQaMgkjk2b4ySLtNkCvuh90NYYmMLUsErVRiC8o8OLmkAYF5hZkRKYCHgVmDAiJJLeZpVUdrq/DA7XB5rAV+gkn/MJ0hc8sKm6OuclDoo8tgBQFgffd335p3cykEjSK1gIXLEl+Oq9OgTIKZtymg/hHuAoHmZJ6/5gDcwvDOyysEDS7B9VkJoSsEhuEyN6KSPyxKrf4qsnIoFQ4syL0qum8i9AW0H/9F/l3gngXwwSAfEQ5csIoFUmH1oAVrTEhXQ+Cdd6GGD4z230b+TQdDgB8S6INeG76AlVSsoYeibBg+cOAX2z1g4Vv2sYggER15uFliZFwWnUAAQmhLGUKe+MMFEa1oH40/FMKYht1RMKVB7+AiwTvEMehdeB2CicwLlAlXI1m5kSjBmACUOQF0HWRpAZcZqngBbxWwqZtkZz4QlEsJvkDiejDIcRh5h4kG5pPBrEHkDw06GKMEhAJwGxx+uBIoAIOmlxaH9TWCh4h2fgqDAWcc019AqwTHwDtu1UmMRQnkdpuHRU6gZ3uWOOaHILmuScc6LlFDhKuwwgiqsjQNgAD/UWgFZaKuq/w0AHIAuHIYReR5+A4C12HkEksSfRvuqiuxR4GebSFw7SraMqoRuXvK2t+Z+JDb22bsxDqBh+YRVCO5RgT81JnEGiNtNvvKKwl/IzJKql8ORadqQuSZis7CANCWYnIScOyAiJHayFIUIpM8r0GUstsrbA4HhC2nJi9LwDuihKkuhEQpgAAiEQpjyc99aWHMppz2gSLBlCL9iFQrW2pdz0TDPCkGCRgQjU9GVPpZQAkgIICWHfQhABkNkM1svQxg9wcJfWSn1AlxI5DA3COYjbbaLJBKzhQRuiF4Cn8nMiMXgQ+uOAkBFDDA2wxABkPJiMe8+OUaECVNLMZUJI755xtoHmwXnoNuugUQp4bGLzf0dvrriy2wsAMD4A377YJjSgDfD0QAADs=";
if (!preg_match('/data:([^;]*);base64,(.*)/', $imgstr, $matches)) {
die("error");
$content = base64_decode($matches[2]);
$zip = new ZipArchive;
$filename = tempnam("/tmp", "testmeZip");
$res = $zip->open($filename, ZipArchive::CREATE);
if ($res === TRUE) {
$zip->addFromString('test.gif', $content);//you can use $matches to figure out extension
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"test.zip\"");
header("Content-Transfer-Encoding: binary");
// make sure the file size isn't cached
clearstatcache();
header("Content-Length: ".filesize($filename));
// output the file
readfile($filename);
I am trying to make a file download dependent inside a session. Here is the code:
<?php>
session_name("My-Download");
session_start();
$_SESSION['Download-Authorized'] = 1;
echo "<a class='invlink' rel='nofollow' download target='_blank' href='download.php?download_file=file.to.download.pdf'>Name of File</a><br /><br />";
?>
The download script ('download.php') comes next:
<?php
session_start();
if(!isset($_SESSION['Download-Authorized'])) {
exit;
}
$path = $_SERVER['DOCUMENT_ROOT']."/downdir/";
$fullPath = $path.$_GET['download_file'];
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fsize);
while(!feof($fd)) {
$buffer = fread($fd, 2048);
print($buffer);
flush();
}
fclose ($fd);
} else {
die("File does not exist. Make sure you specified correct file name.");
}
exit;
?>
All works fine as long as the verification of '$_SESSION['Download-Authorized'] ist commented out.
When I check the session-variable $_SESSION['Download-Authorized'] is set
the download will fail.
What's wrong with my code?
Any help appreciated.
After adding session_start() to the beginning of download.php the script still does not work.
It appears to be the case that the Session-ID as well as the Session-Name changes when "download.php" is called. Additionally $_SESSION['Downlad-Autorized'] is reset.
Your initial script stores the flag in a session explicitely renamed (session_name("My-Download");), but the download script uses the default session name (no session_name()).
Therefore your download script starts with another (possibly empty) session.
So what I am trying to do is take 2 strings and create 2 files. Then create a zip out of these files and let a user download them.
Here is what I have:
$string1 = 'Some data some data some data';
$string2 = 'Some data some data some data';
$zip = new ZipArchive();
$filename = "test.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open <$filename>\n");
}
$zip->addFromString("string1.txt", $string1);
$zip->addFromString("string2.txt", $string2);
$zip->close();
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize('test.zip'));
So far no luck. Any help is appreciated.
You missed the most important part - output the file! :)
Add:
readfile('test.zip');
to the end of the php file.
Also the calculation of the HTTP content-length header is wrong:
header("Content-Length: ".filesize($zip));
This will give you always 0 ( or false) as filesize expects a filename as its argument.
Change the line to:
header("Content-Length: ".filesize('test.zip'));
After doing both of this the zip will successfully download and contains the two files. For completenes, here comes the full working example:
$string1 = 'Some data some data some data';
$string2 = 'Some data some data some data';
$zip = new ZipArchive();
$filename = "test.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open <$filename>\n");
}
$zip->addFromString("string1.txt", $string1);
$zip->addFromString("string2.txt", $string1);
$zip->close();
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
// make sure the file size isn't cached
clearstatcache();
header("Content-Length: ".filesize('test.zip'));
// output the file
readfile('test.zip');
You have a PHP error (you probably dont have error reporting turned on or high enough error level).
the filesize() function takes a string not an object. filesize($filename) will work.
to turn on error reporting do:
error_reporting(E_ALL|E_STRICT);
ini_set('display_errors', 1);
alternatively do this in php.ini
After all those header() calls, I think you want:
readfile($filename);
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.