To Zip Folder

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
Shendemiar
Forum Contributor
Posts: 404
Joined: Thu Jan 08, 2004 8:28 am

To Zip Folder

Post by Shendemiar »

How do i zip a folder, and all of it's contents (maintaining the structure)

I cannot use EXEC

The file can stay at the server and be overwritten each time.

[EDITED]
Last edited by Shendemiar on Wed Dec 29, 2004 9:48 am, edited 2 times in total.
redmonkey
Forum Regular
Posts: 836
Joined: Thu Dec 18, 2003 3:58 pm

Post by redmonkey »

Depends on which zip class you are using (there are plenty out there)? some (most) will work by you scripting something to parse each directory in question and then read each file in and pass it to the zip class.

I very much doubt you can continually write the output to the same zip file as you may end up with two or more people requesting the page within a short space of time which could result in one user trying to download a file that is currently being written to.
User avatar
dull1554
Forum Regular
Posts: 680
Joined: Sat Nov 22, 2003 11:26 am
Location: 42:21:35.359N, 76:02:20.688W

Post by dull1554 »

so have a database where for every zip file that would be created and downloaded there is a row with file name and a status value, when the script starts running set the status to 1 for active, and that way you could have the script check if its active, if its active that person will have to wait till the first user is done downloading the file and the have that script update the db and set status back to 0
something like that might work.....
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

їphp]if (file_exists($filename)) {
unlink($filename);
}
exec("zip $filename $directory");

header('Content-type: application/zip');
header('Content-Transfer-Encoding: Binary');
header('Content-length: ' . filesize($filename));
readfile($filename);
ї/php]
?>
Shendemiar
Forum Contributor
Posts: 404
Joined: Thu Jan 08, 2004 8:28 am

Post by Shendemiar »

No problem about multiple users, so i can just skip that problem. The last post seems promising, thanks.
Shendemiar
Forum Contributor
Posts: 404
Joined: Thu Jan 08, 2004 8:28 am

Post by Shendemiar »

Couldnt i just execute the system's zip command with parameters?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

that's what arborint's example does. :)
Shendemiar
Forum Contributor
Posts: 404
Joined: Thu Jan 08, 2004 8:28 am

Post by Shendemiar »

Seems like i cant exec anything.

What's the alternative?

Somekind of recursive funtion to collect the stuff and then zip it. With memory reservation/problems etc. Way out of my league...

And yes, lets drop the download for now.
User avatar
Joe
Forum Regular
Posts: 939
Joined: Sun Feb 29, 2004 1:26 pm
Location: UK - Glasgow

Post by Joe »

This class works great: (with thanks to Zend)

Code: Select all

<?php
class PHPZip 
{ 
 function Zip($dir, $zipfilename) 
 { 
  if (function_exists('gzcompress')) 

   $curdir = getcwd(); 
   if (is_array($dir)) 
   { 
     $filelist = $dir; 
   } 
   else 
   { 
    $filelist = $this -> GetFileList($dir); 
   } 

   if ((!empty($dir))&&(!is_array($dir))&&(file_exists($dir))) chdir($dir); 
   else chdir($curdir); 


   if (count($filelist)>0) 
   { 
    foreach($filelist as $filename) 
    { 
     if (is_file($filename)) 
     { 
      $fd = fopen ($filename, "r"); 
      $content = fread ($fd, filesize ($filename)); 
      fclose ($fd); 


      if (is_array($dir)) $filename = basename($filename); 
      $this -> addFile($content, $filename); 
     } 
    } 
    $out = $this -> file(); 

    chdir($curdir); 
    $fp = fopen($zipfilename, "w"); 
    fwrite($fp, $out, strlen($out)); 
    fclose($fp); 
   } 
   return 1; 
  } 

 function GetFileList($dir) 
 { 
  if (file_exists($dir)) 
  { 
   $args = func_get_args(); 
   $pref = $args[1]; 


   $dh = opendir($dir); 
   while($files = readdir($dh)) 
   { 
    if (($files!=".")&&($files!="..")) 
    { 
     if (is_dir($dir.$files)) 
     { 
      $curdir = getcwd(); 
      chdir($dir.$files); 
      $file = array_merge($file, $this -> GetFileList("", "$pref$files/")); 
      chdir($curdir); 
     } 
     else $file[]=$pref.$files; 
    } 
   } 
   closedir($dh); 
  } 
  return $file; 
 } 


    var $datasec = array(); 
    var $ctrl_dir = array(); 
    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; 
    var $old_offset = 0; 


    /** 
     * Converts an Unix timestamp to a four byte DOS date and time format 
(date 
     * in high two bytes, time in low two bytes allowing magnitude 
comparison). 
     * 
     * param integer the current Unix timestamp 
     * 
     * return integer the current date in a four byte DOS format 
     * 
     * access private 
     */ 
    function unix2DosTime($unixtime = 0) { 
        $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime); 


        if ($timearray['year'] < 1980) { 
         $timearray['year'] = 1980; 
         $timearray['mon'] = 1; 
         $timearray['mday'] = 1; 
         $timearray['hours'] = 0; 
         $timearray['minutes'] = 0; 
         $timearray['seconds'] = 0; 
        } // end if 


        return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 
21) | ($timearray['mday'] << 16) | 
                ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | 
($timearray['seconds'] >> 1); 
    } // end of the 'unix2DosTime()' method 



    /** 
     * Adds "file" to archive 
     * 
     * param string file contents 
     * param string name of the file in the archive (may contains the 
path) 
     * param integer the current timestamp 
     * 
     * access public 
     */ 
    function addFile($data, $name, $time = 0) 
    { 
        $data = str_replace("\x0a", "\x0d\x0a", $data); 
        $name = str_replace('\'', '/', $name); 


        $dtime = dechex($this->unix2DosTime($time)); 
        $hexdtime = '\x' . $dtime[6] . $dtime[7] 
                  . '\x' . $dtime[4] . $dtime[5] 
                  . '\x' . $dtime[2] . $dtime[3] 
                  . '\x' . $dtime[0] . $dtime[1]; 
        eval('$hexdtime = "' . $hexdtime . '";'); 


        $fr = "\x50\x4b\x03\x04"; 
        $fr .= "\x14\x00"; // ver needed to extract 
        $fr .= "\x00\x00"; // gen purpose bit flag 
        $fr .= "\x08\x00"; // compression method 
        $fr .= $hexdtime; // last mod time and date 


        // "local file header" segment 
        $unc_len = strlen($data); 
        $crc = crc32($data); 
        $zdata = gzcompress($data); 
        $c_len = strlen($zdata); 
        $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
        $fr .= pack('V', $crc); // crc32 
        $fr .= pack('V', $c_len); // compressed filesize 
        $fr .= pack('V', $unc_len); // uncompressed filesize 
        $fr .= pack('v', strlen($name)); // length of filename 
        $fr .= pack('v', 0); // extra field length 
        $fr .= $name; 


        // "file data" segment 
        $fr .= $zdata; 

        $fr .= pack('V', $crc); // crc32 
        $fr .= pack('V', $c_len); // compressed filesize 
        $fr .= pack('V', $unc_len); // uncompressed filesize 


        // add this entry to array 
        $this -> datasec[] = $fr; 
        $new_offset = strlen(implode('', $this->datasec)); 


        // now add to central directory record 
        $cdrec = "\x50\x4b\x01\x02"; 
        $cdrec .= "\x00\x00"; // version made by 
        $cdrec .= "\x14\x00"; // version needed to extract 
        $cdrec .= "\x00\x00"; // gen purpose bit flag 
        $cdrec .= "\x08\x00"; // compression method 
        $cdrec .= $hexdtime; // last mod time & date 
        $cdrec .= pack('V', $crc); // crc32 
        $cdrec .= pack('V', $c_len); // compressed filesize 
        $cdrec .= pack('V', $unc_len); // uncompressed filesize 
        $cdrec .= pack('v', strlen($name) ); // length of filename 
        $cdrec .= pack('v', 0 ); // extra field length 
        $cdrec .= pack('v', 0 ); // file comment length 
        $cdrec .= pack('v', 0 ); // disk number start 
        $cdrec .= pack('v', 0 ); // internal file attributes 
        $cdrec .= pack('V', 32 );

        $cdrec .= pack('V', $this -> old_offset ); 
        $this -> old_offset = $new_offset; 


        $cdrec .= $name; 


        // optional extra field, file comment goes here 
        // save to central directory 
        $this -> ctrl_dir[] = $cdrec; 
    } // end of the 'addFile()' method 



    /** 
     * Dumps out file 
     * 
     * return string the zipped file 
     * 
     * access public 
     */ 
    function file() 
    { 
        $data = implode('', $this -> datasec); 
        $ctrldir = implode('', $this -> ctrl_dir); 


        return 
            $data . 
            $ctrldir . 
            $this -> eof_ctrl_dir . 
            pack('v', sizeof($this -> ctrl_dir)) . 
            pack('v', sizeof($this -> ctrl_dir)) . 
            pack('V', strlen($ctrldir)) . // size of central dir 
            pack('V', strlen($data)) . 
            "\x00\x00"; 
    } // end of the 'file()' method 

} // end of the 'PHPZip' class 
?>
And zip a dir by implementing the class using this procedure:

Code: Select all

$directory = "home/public_html";
$filename = "file.zip";

$zipfile = new PHPZip();
$zipfile -> Zip($directory, $filename);
I have used this many times with no problems.
Shendemiar
Forum Contributor
Posts: 404
Joined: Thu Jan 08, 2004 8:28 am

Post by Shendemiar »

Joe wrote:This class works great: (with thanks to Zend)
Great thanks.

(I can't stop wondering this forum's greatness...)
User avatar
Joe
Forum Regular
Posts: 939
Joined: Sun Feb 29, 2004 1:26 pm
Location: UK - Glasgow

Post by Joe »

No problem :D
Shendemiar
Forum Contributor
Posts: 404
Joined: Thu Jan 08, 2004 8:28 am

Post by Shendemiar »

Works ok for some folders but for one i need it gives:

I get undefined offset in line 56 (of that code)
redmonkey
Forum Regular
Posts: 836
Joined: Thu Dec 18, 2003 3:58 pm

Post by redmonkey »

I could be wrong as I haven't tested it but I suspect the above class will have problems with recursion into sub directories (i.e. it won't). It also uses some strange choices of functions (in my mind).
Post Reply