Jump to content

[SOLVED] force download corrupting zip file


CMK08

Recommended Posts

I am having trouble using this code I found on a different thread. If I force the download by redirecting the user with header(Location: file.zip) all works well, except that instead of getting a "download" dialog, the user gets a "now opening" dialog.

 

With the code below, I get the "downloading" dialog, but the file gets corrupted. Can anyone spot the problem?

 

thanks

 

<?php 


// My Zip file to Download
$zipfile = "myZip.zip";

header("Pragma: public");

// set expiration time
header("Expires: 0"); 

// browser must download file from server instead of cache
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");

// force download dialog
header("Content-Type: application/force-download");
header("Content-Type: application/zip");
header("Content-Type: application/download");


// Display the save dialog to the user with the filename
header("Content-Disposition: attachment; filename=".basename($zipfile).";");


// Shows a progress bar for the downloading file
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($zipfile));

@readfile($zipfile);
?>

Link to comment
Share on other sites

Nothing wrong with the code from what i can see.. do you have an online example or a damaged zip i can see ?

whats the zip file size ?

as a guess i would say the file is getting truncated or has some php output ie memory problems..

remember the <?php MUST be at the very start of the file..

Link to comment
Share on other sites

I've downloaded a file, opened it with notepad and got:

 

<br />
<b>Warning</b>:  filesize() [<a href='function.filesize'>function.filesize</a>]: stat failed for reports.zip in <b>/home/cristina/www/www/downloads/test.php</b> on line <b>10</b><br />
<br />
<b>Warning</b>:  Cannot modify header information - headers already sent by (output started at /home/cristina/www/www/downloads/test.php:10) in <b>/home/cristina/www/www/downloads/test.php</b> on line <b>10</b><br />

 

Line 10 and it's area has nothing to do with filesize(). Can you show the full script?

 

Orio.

Link to comment
Share on other sites

I moved that script back to my form, tried the download, and it looks like it is downloading the code instead of "reports.zip"... I did this locally, and this is what I got in the zip folder:

 

<form action=zip.php method=post><p><input type="checkbox" name= 1 >contact.html</p><p><input type="checkbox" name= 2 >index.php</p>
<p><input type="checkbox" name= 3 >re.txt</p><p><input type="checkbox" name= 4 >korean_test.pdf</p>
<input type=submit name=submit value=Download></form>index.php<br>Archive created successfully.

 

That would explain why the zip files from the website were blank after I removed the filesize line. Even though I am specifying a file to be downloaded, the code is trying to download the html page.

 

 

test.php is supposed to handle the zip.php form:

<?php
$zipFile = 'reports.zip';
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0');
header('Content-type: application/download');
header('Content-type: application/zip');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename='.basename($zipFile).';');
header('Content-Transfer-Encoding: binary');
//header('Content-Length: '.filesize($zipFile).';');
@read($zipFile);
?>

 

Link to comment
Share on other sites

First, there's no such function as read(). Should be readfile() I guess.

 

Now, the reports.zip file is in the same folder as test.php? I can't think of a reason it'd give the previous error.

How exactly can it show the HTML file? Are you sure you've showed the full script?

 

Orio.

Link to comment
Share on other sites

It looks like a logical error on my form...

<?php
//this array is built with query result

$fileList2= array('1'=>'contact.html','2'=>'index.php','3'=>'re.txt','4'=>'korean_test.pdf');

echo '<form action=zip.php method=post>';

foreach ($fileList2 as $value=>$name){

echo "<p><input type=\"checkbox\" name= $value >$name</p>";

}
echo "<input type=submit name=submit value=Download></form>";

// after form is submitted: 

if(isset($_POST['submit'])){  

//prepare list of items to zip

$fileList = array();

foreach($fileList2 as $value=>$name){

if(isset($_POST[$value])){

	$fileList[]= $name;

}
}

//if at least one item was selected zip them up and send it to the browser

  if (!empty($fileList)){

// create object
	$zip = new ZipArchive();

	// open archive 
 	if ($zip->open('reports.zip', ZIPARCHIVE::CREATE) !== TRUE) {
   	 		 die ("Could not open archive");
	}

	$numFiles = $zip->numFiles;
	if($numFiles>0){
	  for ($x = 0; $x<$numFiles;$x++){

		$file = $zip->statIndex($x);

		$zip->deleteIndex($x) or die("ERROR: Could not delete file");
    
}	

}

$item = $fileList[0];
echo $item.'<br>';

// add files
 foreach ($fileList as $f) {
    $zip->addFile($f) or die ("ERROR: Could not add file: $f");   
	}
    
// close and save archive
$zip->close();
$filename='reports.zip';
//header('Location: reports.zip'); 
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0');
header('Content-type: application/download');
header('Content-type: application/zip');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename='.basename('reports.zip').';');
header('Content-Transfer-Encoding: binary');
//header('Content-Length: '.filesize('reports.zip').';');
@read('reports.zip');
exit;

} Else{ echo "you must select an item";}}
else {

echo "Please select the reports you would like to download";}

?>

 

The message that should appear after the file has been created is ending up in the zip file that is downloaded. It is as if the zip folder is being downloaded before the files get in it. I checked this folder (which is in the same directory as the scripts) and the correct files are in it.

Link to comment
Share on other sites

Try it this way:

 

<?php

//this array is built with query result

$fileList2= array('1'=>'contact.html','2'=>'index.php','3'=>'re.txt','4'=>'korean_test.pdf');



// after form is submitted: 

if(isset($_POST['submit']))
{

//prepare list of items to zip

$fileList = array();

foreach($fileList2 as $value=>$name){

   if(isset($_POST[$value])){

      $fileList[]= $name;

   }
}

//if at least one item was selected zip them up and send it to the browser

if (!empty($fileList)){

   // create object
      $zip = new ZipArchive();

      // open archive 
       if ($zip->open('reports.zip', ZIPARCHIVE::CREATE) !== TRUE) {
              die ("Could not open archive");
      }
      
      $numFiles = $zip->numFiles;
      if($numFiles>0){
        for ($x = 0; $x<$numFiles;$x++){
         
         $file = $zip->statIndex($x);
         
         $zip->deleteIndex($x) or die("ERROR: Could not delete file");
    
		}   

	}
                              
	$item = $fileList[0];
	//echo $item.'<br>';

	// add files
    foreach ($fileList as $f) {
    $zip->addFile($f) or die ("ERROR: Could not add file: $f");   
    }
    
	// close and save archive
	$zip->close();
	$filename='reports.zip';
	//header('Location: reports.zip'); 
	header('Pragma: public');
	header('Cache-Control: must-revalidate, post-check=0');
	header('Content-type: application/download');
	header('Content-type: application/zip');
	header('Content-Type: application/force-download');
	header('Content-Disposition: attachment; filename='.basename('reports.zip').';');
	header('Content-Transfer-Encoding: binary');
	//header('Content-Length: '.filesize('reports.zip').';');
	@read('reports.zip');
	exit;

}
else
{
	echo "you must select an item";
}
}


echo '<form action="zip.php" method="post">';

foreach ($fileList2 as $value=>$name){

   echo "<p><input type=\"checkbox\" name=\"{$value}\" >{$name}</p>";

}
echo "<input type=\"submit\" name=\"submit\" value=\"Download\"></form>";
echo "<br>Please select the reports you would like to download";


?>

 

The thing is, if you are force downloading something you can't have any other output but the readfile's output. Otherwise, that data (you echoed) will be added to the zip file.

I've changed a bit the structure of your main if clause. Also removed the echo you have in the middle of the script (I've commented it). Should be working now.

 

Orio.

Link to comment
Share on other sites

I tested just this piece of the code:

<?php
$zipFile = 'reports.zip';
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0');
header('Content-type: application/download');
header('Content-type: application/zip');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename='.basename($zipFile).';');
header('Content-Transfer-Encoding: binary');
//header('Content-Length: '.filesize($zipFile).';');
@read($zipFile);
?>

 

While the zip folder does have files in it, the folder downloaded with this script is empty. I think I am missing something in this code.

Link to comment
Share on other sites

I've never had to use the ZIP library, but I guess the problem is there somehow, if you are getting an empty folder. Try going over the piece of code that creates the archive with the manual as a reference to see if you're doing it right.

 

Orio.

Link to comment
Share on other sites

Orio, you were right. I don't know why the script didn't work the first time I tried with the edits you made. After trying several different things, I ended up moving the form tags to the end (like you did) and now it works. The only difference between your edits and mine are the escaped quotes. I must have missed something when using your solution. Thank you very much!

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.