So i was trying to generate a zip file with a bunch of pdfs in it.
After some time I got it working but the problem servers gives me ERR_EMPTY_RESPONSE.
Server's apache is 2.2 on windows server 2003...
PHP Version is 5.2.
This is the code:
<?php
$file_names=$pdfs; //This is an array of names of files in PDF format: 1.pdf, 2pdf, 3pdf...
$zip = new ZipArchive;
$zip_name = ("test.zip");
$path_zip = ("C:/www/test/docs/");
$zip->open($path_zip.$zip_name,ZipArchive::CREATE);
foreach ($file_names as $file) {
$zip->addFile($file,basename($file));
}
$zip->close();
//then send the headers to force download the zip file
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$zip_name");
header("Pragma: no-cache");
header("Expires: 0");
#readfile($path_zip.$zip_name);
exit;
?>
THE PDFs ARE PREVIOUSLY DOWNLOADED FROM THE INTERNET WITH ANOTHER CODE
How do I fix this??
EDIT::
Adding a image showing the zip.
EDIT 2::
I removed the # at the last line and tested. Nothing works as intended.
So...
It's ugly but it works...
I just changed
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$zip_name");
header("Pragma: no-cache");
header("Expires: 0");
readfile($path_zip.$zip_name);
exit;
for
header("Location: ".$path_zip.$zip_name);
As I say, it's pretty ugly, but it works, it make the user download the file and it doesn't get stuck or something like that.
If someone want to make another true fix, I will test it, as I don't want to change the location.
Bye.
Related
I'm creating a ZIP file with several scripts in it (for example: test.php, functions.js and style.css).
The scripts works just fine, the only problem is that the ZIP file gets placed on my webserver. Is there a way to prevent this? I've read multiple similar questions: this one seems to work, but I can't figure it out how to use that.
So, I wan't to delete the file after it has been placed (even if user aborts it) or (even better) that my scripts never puts the file on the webserver.
download.php
$scriptId = checkNumeric($_GET['sid']);
//Check if user has access to the script
if(isLoggedIn() && hasScriptAccess($scriptId)) {
//Create ZIP
$zip = new ZipArchive();
$zipName = "script.zip";
if ($zip->open($zipName, ZIPARCHIVE::CREATE)!== TRUE) {
exit(); //Something went wrong while creating the ZIP
}
//Get associated codes
$query = $mysqli->query("SELECT * FROM code WHERE script_id = '{$scriptId}'");
while($code = $query->fetch_assoc()) {
$filename = $code['title'];
$content = $code['code'];
//Add file to ZIP
$zip->addFromString($filename, $content);
}
$zip->close();
//Set headers
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='" . $zipName . "'");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($zipName));
clearstatcache(); //Make sure the file size isn't cached
readfile($zipName); //Output the file
$zip->deleteName($zipName);
}
From my understanding the zip file must be saved, it can not be stored in memory. $zip->close(); is what actually triggers the file creation. I am sure someone smarter than I will figure out how to write it to memory but for now there is a simple work around.
I just did something similar. The trick is to use:
// Keep script running even if user aborts
ignore_user_abort(true);
Add this as the first line of your script. What this does is allow your download script to run even if the user aborts the download. That will ensure your delete command gets called.
I am not sure if you are saying if the file is or is not deleting properly even if the user is not aborting. But if your current delete command is not working as expected you could use a simple:
unlink( $zipName);
Hope this helps.
I've created a function to issue a download once user click a link, the file is located in 3rd party storage service (Sugar Sync) and is accessed via their REST API. Now I've created the force download function and tested it runs fine on localhost (a download dialog is prompted), but when I run the function on the server it returns an error page of 'File not Found'. I figured this might be some PHP configuration that needs to be set on server side, but I've got no clue which, so any help or hint is greatly appreciated.
Here's a snippet of the code:
$sugarsync = new SugarSync($refreshtoken);
$response = $sugarsync->get($url);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate");
header("Content-Type: ".$response->mediaType);
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".$response->displayName.";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$response->size);
//file is returned as binary data from the API
print($sugarsync->download(urldecode($url)));
exit();
As it turns out, after further troubleshooting, the problem is related to output buffering, so I just need to enable that on the server config.
Try adding ob_get_clean(); before your print function like so:
ob_get_clean();
//file is returned as binary data from the API
print($sugarsync->download(urldecode($url)));
exit();
This has been posted, but I've tried lot of solutions found on SO and more (like this: http://davidwalsh.name/php-force-download)
I basically have this:
{
$filePath = '../public/myfile.png';
$fileName = basename($filePath);
$fileSize = filesize($filePath);
if (!is_file) {
die("File not found");
} else {
header("Content-Description: File Transfer");
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename= " . $fileName);
header("Content-Transfer-Encoding: binary");
readfile($filePath);
}
}
Files are recognized and downloaded, but .PNGs are empty and .DOCs are corrupted (and Word asks me to fix the file, then it's ok). I have tried also PDFs, and no problem with that.
I trues to put all sort of options (Pragma, Cache-Control, Expires, Content-Length, etc.), still downloaded files but corrupted in some way...
Did you ever had my problem? Please consider I'm on IIS 7.5
Thanks in advance
Open the downloaded files with a plain text editor like Notepad++. At the top you will find a PHP Error notice, it will tell you what's going wrong.
The error is probably "session already send". Then add ob_start(); at the beginning of your script.
I am selling a digital product and want to hide the true location of the download.
So I'm using a redirect script like this:
protected function redirectDownload ($realfilename) {
ob_start();
$mm_type="application/octet-stream";
header("Cache-Control: public, must-revalidate");
header("Pragma: no-cache");
header("Content-Type: " . $mm_type);
header("Content-Length: " .(string)(filesize($realfilename)) );
header('Content-Disposition: attachment; filename="'.$this->fakefilename.'"');
header("Content-Transfer-Encoding: binary\n");
ob_end_clean();
readfile($realfilename);
}
The zip file is always corrupted when I download it, but when I download it directly it is fine.
Does anyone know why this might be?
I think this was working fine on another server, but would need to confirm that.
If I can't solve this, is there any other techniques or services I can use to do this?
Open the downloaded(corrupted) file in an text-editor, i guess there has already been some output before you call the function.
You should better use ob_start() at the begin of your script instead of the begin of the function.
I am downloading a file from another server. I wish to push this file to my users rather than saving it to my server.
In other words, pass them the file handle so it just passes through my server and saves to their machine. How can I do this? I have this so far:
$handle = fopen($_GET['fileURL'], 'r');
$filename = stream_get_contents($handle);
How do I push this to the user, maybe using headers?
Thank you for any help and direction.
EDIT
I have the headers:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
Its just that it doesn't push the headers. I just get a blank page after about 15 seconds which looks like it downloading the file but not giving it to me.
I wish for the script to immediately send the headers to the user as a stream.
exit();
You can try this
$filetype = mime_content_type($filename);
header('Content-type: '.$filetype);
header('Content-Disposition: attachment; filename="'.$filename.'"');
UPDATE for your EDIT:
Do you have errors disabled, since this sounds like the headers already sent error?
error_reporting(E_ALL | E_STRICT);
You don't have to use fopen() when using readfile();
Just include the filename inside readfile() like this:
readfile($_GET['fileUrl']);
Although this is very dangerous security-wise as the user could specify any file on your file server. If you only have a few files you want someone to be able to download perhaps you should store them in an array (or database, preferebly)
Here's an array example:
$files = array('file1.jpg', 'file2.png', 'file3.pdf');
//assume $_GET['file_id'] == 0, 1 or 2
if (file_exists($files[$_GET['file_id']]))
readfile($files[$_GET['file_id']]);