Source for file jZipCreator.class.php

Documentation is available at jZipCreator.class.php

  1. <?php
  2. /**
  3.  * @package    jelix
  4.  * @subpackage utils
  5.  * @author     Laurent Jouanneau
  6.  * @contributor Julien Issler
  7.  * @copyright  2006 Laurent Jouanneau
  8.  * @copyright 2008 Julien Issler
  9.  * @link       http://www.jelix.org
  10.  * @licence    GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  11.  */
  12.  
  13. /**
  14.  * Class to create a zip file.
  15.  * @package    jelix
  16.  * @subpackage utils
  17.  * @link http://www.pkware.com/business_and_developers/developer/appnote/ Official ZIP file format
  18.  */
  19. class jZipCreator {
  20.  
  21.     /**
  22.      * contains all file records
  23.      * @var  array $fileRecords 
  24.      */
  25.     protected $fileRecords = array();
  26.  
  27.     /**
  28.      * Contains the central directory
  29.      * @var  array $centralDirectory 
  30.      */
  31.     protected $centralDirectory = array();
  32.  
  33.     /**
  34.      * Offset of the central directory
  35.      * @var  integer  $centralDirOffset 
  36.      */
  37.     protected $centralDirOffset   = 0;
  38.  
  39.     /**
  40.      * adds a physical file to the zip archive
  41.      *
  42.      * @param  string  $filename  the path of the physical file you want to add
  43.      * @param  string  $zipPath  the path of the file inside the zip archive
  44.      */
  45.     public function addFile($filename$zipFileName=''){
  46.         if($zipFileName == ''$zipFileName $filename;
  47.         if(file_exists($filename)){
  48.             $this->addContentFile($zipFileNamefile_get_contents($filename)filemtime($filename));
  49.         }else{
  50.             throw new jException('jelix~errors.file.notexists'$filename);
  51.         }
  52.     }
  53.  
  54.     /**
  55.      * adds the content of a directory to the zip archive
  56.      *
  57.      * @param  string  $path  the path of the physical directory you want to add
  58.      */
  59.     public function addDir($path$zipDirPath=''$recursive false){
  60.         if(file_exists($path)){
  61.             if($zipDirPath !='' && substr($zipDirPath,-1,1!= '/')
  62.                 $zipDirPath.='/';
  63.             if(substr($path,-1,1!= '/')
  64.                 $path.='/';
  65.  
  66.             if ($handle opendir($path)) {
  67.                 $this->addEmptyDir($zipDirPath,filemtime($path));
  68.                 while (($file readdir($handle)) !== false{
  69.                     if($file == '.' || $file == '..')
  70.                         continue;
  71.                     if (!is_dir($path.$file))
  72.                         $this->addFile($path.$file$zipDirPath.$file);
  73.                     else if ($recursive)
  74.                         $this->addDir($path.$file,$zipDirPath.$filetrue);
  75.                 }
  76.                 closedir($handle);
  77.             }
  78.         }else{
  79.             throw new jException('jelix~errors.file.notexists'$path);
  80.         }
  81.     }
  82.  
  83.     /**
  84.      * add a "logical" file to the zip archive
  85.      *
  86.      * @param  string   $zipFileName    the path of the file into the zip archive
  87.      * @param  string   $content    the content of the file
  88.      * @param  integer  $filetime   the time modification of the file
  89.      */
  90.     public function addContentFile($zipFileName$content$filetime 0){
  91.  
  92.         $filetime $this->_getDOSTimeFormat($filetime);
  93.  
  94.         /*
  95.         generation of the file record
  96.  
  97.         file record:
  98.          - local file header signature     4 bytes  (0x04034b50)
  99.          - version needed to extract       2 bytes  14
  100.          - general purpose bit flag        2 bytes  0
  101.          - compression method              2 bytes  0x8
  102.          - last mod file time              2 bytes (fileinfo)
  103.          - last mod file date              2 bytes (fileinfo)
  104.          - crc-32                          4 bytes (fileinfo)
  105.          - compressed size                 4 bytes (fileinfo)
  106.          - uncompressed size               4 bytes (fileinfo)
  107.          - file name length                2 bytes (fileinfo)
  108.          - extra field length              2 bytes (here 0) (fileinfo)
  109.          - file name (variable size)
  110.          - extra field (variable size)      (here nothing)
  111.          - compressed content
  112.         */
  113.         $zipFileName     str_replace('\\''/'$zipFileName);
  114.  
  115.         $zippedcontent    substr(gzcompress($content)2-4)// compress and fix crc bug
  116.  
  117.         $fileinfo  $filetime.pack('V'crc32($content));
  118.         $fileinfo .= pack('V'strlen($zippedcontent))pack('V'strlen($content));
  119.         $fileinfo .= pack('v'strlen($zipFileName))."\x00\x00";
  120.  
  121.         $filerecord "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$fileinfo.
  122.             $zipFileName.$zippedcontent;
  123.  
  124.         $this->fileRecords[$filerecord;
  125.  
  126.         $this->_addCentralDirEntry($zipFileName$fileinfo);
  127.  
  128.         $this->centralDirOffset += strlen($filerecord);
  129.  
  130.     }
  131.  
  132.     /**
  133.      * adds an empty dir to the zip file
  134.      */
  135.     public function addEmptyDir($name$time=0){
  136.  
  137.         $time $this->_getDOSTimeFormat($time);
  138.  
  139.         $name str_replace('\\''/'$name);
  140.  
  141.         if(substr($name,-1,1)!=='/')
  142.             $name .= '/';
  143.  
  144.         if($name == '/')
  145.             return;
  146.  
  147.         $fileinfo $time."\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
  148.             pack('v'strlen($name))."\x00\x00";
  149.  
  150.         $filerecord "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$fileinfo.$name;
  151.  
  152.         $this->fileRecords[$filerecord;
  153.  
  154.         $this->_addCentralDirEntry($name$fileinfotrue);
  155.  
  156.         $this->centralDirOffset += strlen($filerecord);
  157.     }
  158.  
  159.  
  160.     /**
  161.      * create the contenu of the zip file
  162.      * @return  string  the content of the zip file
  163.      */
  164.     public function getContent(){
  165.  
  166.         $centraldir implode(''$this->centralDirectory);
  167.         $c pack('v'count($this ->centralDirectory));
  168.  
  169.         /*
  170.         zip file :
  171.            - file records
  172.            - central dir
  173.            - end of central dir signature    4 bytes  (0x06054b50)
  174.            - number of this disk             2 bytes   (0 here)
  175.            - number of the disk with the
  176.               start of the central directory 2 bytes   (0 here)
  177.            - total number of entries in the
  178.               central directory on this disk 2 bytes
  179.            - total number of entries in
  180.               the central directory          2 bytes
  181.            - size of the central directory   4 bytes
  182.            - offset of start of central directory with respect to
  183.              the starting disk number        4 bytes
  184.            - .ZIP file comment length        2 bytes
  185.            - .ZIP file comment       (variable size)
  186.         */
  187.         return implode(''$this->fileRecords).$centraldir."\x50\x4b\x05\x06\x00\x00\x00\x00".$c.$c.
  188.             pack('V'strlen($centraldir)).pack('V'$this ->centralDirOffset)."\x00\x00";
  189.     }
  190.  
  191.     protected function _getDOSTimeFormat($timestamp){
  192.         // converts unix timestamp to dos binary format
  193.         if($timestamp == 0)
  194.             $timestamp time();
  195.         elseif($timestamp 315529200// 01/01/1980
  196.             $timestamp 315529200;
  197.  
  198.         $dt getdate($timestamp);
  199.  
  200.         return pack('V',($dt['seconds'>> 1($dt['minutes'<< 5($dt['hours'<< 11|
  201.                 ($dt['mday'<< 16($dt['mon'<< 21(($dt['year'1980<< 25));
  202.  
  203.     }
  204.  
  205.     protected function _addCentralDirEntry($name$info$isDir false){        
  206.         /*
  207.          register the file into the central directory record
  208.          it contains an header for each file
  209.            - central file header signature   4 bytes  (0x02014b50)
  210.            - version made by                 2 bytes  0=DOS
  211.            - version needed to extract       2 bytes  0x14
  212.            - general purpose bit flag        2 bytes  0
  213.            - compression method              2 bytes  0x8
  214.            - last mod file time              2 bytes (fileinfo)
  215.            - last mod file date              2 bytes (fileinfo)
  216.            - crc-32                          4 bytes (fileinfo)
  217.            - compressed size                 4 bytes (fileinfo)
  218.            - uncompressed size               4 bytes (fileinfo)
  219.            - file name length                2 bytes (fileinfo)
  220.            - extra field length              2 bytes   0 (fileinfo)
  221.            - file comment length             2 bytes   0
  222.            - disk number start               2 bytes   0
  223.            - internal file attributes        2 bytes   0
  224.            - external file attributes        4 bytes   32 : 'archive' bit set ; 16 : for empty folder support
  225.            - relative offset of local header 4 bytes
  226.            - file name (variable size)
  227.            - extra field (variable size)
  228.            - file comment (variable size)
  229.         */
  230.  
  231.         $cdrecord "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00".$info;
  232.         $cdrecord .= "\x00\x00\x00\x00\x00\x00";
  233.         if($isDir)
  234.             $cdrecord .= pack('V'16);
  235.         else
  236.             $cdrecord .= pack('V'32);
  237.         $cdrecord .= pack('V'$this ->centralDirOffset );
  238.         $cdrecord .= $name;
  239.  
  240.         $this->centralDirectory[$cdrecord;
  241.     }
  242. }

Documentation generated on Thu, 22 Mar 2012 22:17:40 +0100 by phpDocumentor 1.4.3