Reputation: 21
Hihi,
I have a form with multiple check boxes where it allow user to select the brochures they want before they are prompted to download the zip file. The zip archive download function is working without problem. But I realized the download session will be terminated without downloading the entire file (say 8MB) and the downloaded zip file will turn out corrupted.
Referring to the codes below, it does not solve the problem. Anybody can advise what are the settings I need to look into or am I missing out any functionality?
if($send) {
// Make sure program execution doesn't time out
// Set maximum script execution time in seconds (0 means no limit)
set_time_limit(0);
$post = $_POST;
$file_folder = "pdf/"; // folder to load files
$zip = new ZipArchive(); // Load zip library
$zip_name = "File-".time().".zip"; // Zip name
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){ // Opening zip file to load files
$error .= "* Sorry ZIP creation failed at this time<br/>";
}
foreach($post['brochure'] as $file){
$zip->addFile($file_folder.$file); // Adding files into zip
}
$zip->close();
if(file_exists($zip_name)){
// set headers push to download the zip
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-Transfer-Encoding: Binary");
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
header("Content-Length: ".filesize($zip_name));
readfile($zip_name);
// remove zip file is exists in temp path
unlink($zip_name);
$fp = @fopen($zip_name, "rb");
if ($fp) {
while(!feof($fp)) {
print(fread($fp, 1024*8));
flush(); // this is essential for large downloads
if (connection_status()!=0) {
@fclose($file);
die();
}
}
@fclose($file);
}
}
Upvotes: 1
Views: 2445
Reputation: 21
Manage to resolve my problem with the codes below. Basically I shouldn't have unlink the file before calling for fopen.
if($send) {
// Make sure program execution doesn't time out
// Set maximum script execution time in seconds (0 means no limit)
set_time_limit(0);
$post = $_POST;
$file_folder = "pdf/"; // folder to load files
$zip = new ZipArchive(); // Load zip library
$zip_name = "File-".time().".zip"; // Zip name
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){ // Opening zip file to load files
$error .= "* Sorry ZIP creation failed at this time<br/>";
}
foreach($post['brochure'] as $file){
$zip->addFile($file_folder.$file); // Adding files into zip
}
$zip->close();
if(file_exists($zip_name)){
// set headers push to download the zip
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-Transfer-Encoding: Binary");
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
header("Content-Length: ".filesize($zip_name));
//readfile($zip_name);
// remove zip file is exists in temp path
//unlink($zip_name);
$fp = @fopen($zip_name, "rb");
if ($fp) {
while(!feof($fp)) {
echo fread($fp, 8192);
flush(); // this is essential for large downloads
if (connection_status()!=0) {
@fclose($zip_name);
die();
}
}
@fclose($zip_name);
}
unlink($zip_name);
}
}
Upvotes: 0
Reputation: 5552
First of all, your if ($fp) {...}
block should never be executed because you've done a unlink($zip_name);
just before. So this block is useless.
Secondary, I suggest that you replace
readfile($zip_name);
with
ob_clean();
flush();
readfile($zip_name);
This will prevent for unexpected border effects.
And finally, if you still have the corrupted archive (I believe that), then I think it is because some PHP error has occurred before, during or after the download flushing (please note that your PHP code doesn't seem to be ending after the download, so the code may continue and some error may happen after). If such a PHP error or PHP notice has occurred, the PHP error message has been output with streaming. This is easy to check: open the corrupted archive with a text editor in order to see the binary contents, and then the PHP error message should appear clear and readable at the very start or the very bottom of the binary contents of the archive. No need to open the archive in HEXA mode.
Upvotes: 0
Reputation: 2016
instead of making a "readfile()" did you try this kind of solution ?
if(file_exists($zip_name)){
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-Transfer-Encoding: Binary");
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
header("Content-Length: ".filesize($zip_name));
echo file_get_contents($file);
exit
}
For me it's simpler and it worked fine for me at many times.
After this the problem i see is that you make :
unlink($zip_name);
$fp = @fopen($zip_name, "rb");
if ($fp) {
...
}
This part of the code should never go on, because you unlink the file before opening it !
Upvotes: 1