| <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed'); | 
| /** | 
|  * CodeIgniter | 
|  * | 
|  * An open source application development framework for PHP 5.1.6 or newer | 
|  * | 
|  * @package        CodeIgniter | 
|  * @author        ExpressionEngine Dev Team | 
|  * @copyright    Copyright (c) 2008 - 2011, EllisLab, Inc. | 
|  * @license        http://codeigniter.com/user_guide/license.html | 
|  * @link        http://codeigniter.com | 
|  * @since        Version 1.0 | 
|  * @filesource | 
|  */ | 
|   | 
| // ------------------------------------------------------------------------ | 
|   | 
| /** | 
|  * Zip Compression Class | 
|  * | 
|  * This class is based on a library I found at Zend: | 
|  * http://www.zend.com/codex.php?id=696&single=1 | 
|  * | 
|  * The original library is a little rough around the edges so I | 
|  * refactored it and added several additional methods -- Rick Ellis | 
|  * | 
|  * @package        CodeIgniter | 
|  * @subpackage    Libraries | 
|  * @category    Encryption | 
|  * @author        ExpressionEngine Dev Team | 
|  * @link        http://codeigniter.com/user_guide/libraries/zip.html | 
|  */ | 
| class CI_Zip  { | 
|   | 
|     var $zipdata    = ''; | 
|     var $directory    = ''; | 
|     var $entries    = 0; | 
|     var $file_num    = 0; | 
|     var $offset        = 0; | 
|     var $now; | 
|   | 
|     /** | 
|      * Constructor | 
|      */ | 
|     public function __construct() | 
|     { | 
|         log_message('debug', "Zip Compression Class Initialized"); | 
|   | 
|         $this->now = time(); | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Add Directory | 
|      * | 
|      * Lets you add a virtual directory into which you can place files. | 
|      * | 
|      * @access    public | 
|      * @param    mixed    the directory name. Can be string or array | 
|      * @return    void | 
|      */ | 
|     function add_dir($directory) | 
|     { | 
|         foreach ((array)$directory as $dir) | 
|         { | 
|             if ( ! preg_match("|.+/$|", $dir)) | 
|             { | 
|                 $dir .= '/'; | 
|             } | 
|   | 
|             $dir_time = $this->_get_mod_time($dir); | 
|   | 
|             $this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']); | 
|         } | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      *    Get file/directory modification time | 
|      * | 
|      *    If this is a newly created file/dir, we will set the time to 'now' | 
|      * | 
|      *    @param string    path to file | 
|      *    @return array    filemtime/filemdate | 
|      */ | 
|     function _get_mod_time($dir) | 
|     { | 
|         // filemtime() will return false, but it does raise an error. | 
|         $date = (@filemtime($dir)) ? filemtime($dir) : getdate($this->now); | 
|   | 
|         $time['file_mtime'] = ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2; | 
|         $time['file_mdate'] = (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday']; | 
|   | 
|         return $time; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Add Directory | 
|      * | 
|      * @access    private | 
|      * @param    string    the directory name | 
|      * @return    void | 
|      */ | 
|     function _add_dir($dir, $file_mtime, $file_mdate) | 
|     { | 
|         $dir = str_replace("\\", "/", $dir); | 
|   | 
|         $this->zipdata .= | 
|             "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00" | 
|             .pack('v', $file_mtime) | 
|             .pack('v', $file_mdate) | 
|             .pack('V', 0) // crc32 | 
|             .pack('V', 0) // compressed filesize | 
|             .pack('V', 0) // uncompressed filesize | 
|             .pack('v', strlen($dir)) // length of pathname | 
|             .pack('v', 0) // extra field length | 
|             .$dir | 
|             // below is "data descriptor" segment | 
|             .pack('V', 0) // crc32 | 
|             .pack('V', 0) // compressed filesize | 
|             .pack('V', 0); // uncompressed filesize | 
|   | 
|         $this->directory .= | 
|             "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00" | 
|             .pack('v', $file_mtime) | 
|             .pack('v', $file_mdate) | 
|             .pack('V',0) // crc32 | 
|             .pack('V',0) // compressed filesize | 
|             .pack('V',0) // uncompressed filesize | 
|             .pack('v', strlen($dir)) // length of pathname | 
|             .pack('v', 0) // extra field length | 
|             .pack('v', 0) // file comment length | 
|             .pack('v', 0) // disk number start | 
|             .pack('v', 0) // internal file attributes | 
|             .pack('V', 16) // external file attributes - 'directory' bit set | 
|             .pack('V', $this->offset) // relative offset of local header | 
|             .$dir; | 
|   | 
|         $this->offset = strlen($this->zipdata); | 
|         $this->entries++; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Add Data to Zip | 
|      * | 
|      * Lets you add files to the archive. If the path is included | 
|      * in the filename it will be placed within a directory.  Make | 
|      * sure you use add_dir() first to create the folder. | 
|      * | 
|      * @access    public | 
|      * @param    mixed | 
|      * @param    string | 
|      * @return    void | 
|      */ | 
|     function add_data($filepath, $data = NULL) | 
|     { | 
|         if (is_array($filepath)) | 
|         { | 
|             foreach ($filepath as $path => $data) | 
|             { | 
|                 $file_data = $this->_get_mod_time($path); | 
|   | 
|                 $this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']); | 
|             } | 
|         } | 
|         else | 
|         { | 
|             $file_data = $this->_get_mod_time($filepath); | 
|   | 
|             $this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']); | 
|         } | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Add Data to Zip | 
|      * | 
|      * @access    private | 
|      * @param    string    the file name/path | 
|      * @param    string    the data to be encoded | 
|      * @return    void | 
|      */ | 
|     function _add_data($filepath, $data, $file_mtime, $file_mdate) | 
|     { | 
|         $filepath = str_replace("\\", "/", $filepath); | 
|   | 
|         $uncompressed_size = strlen($data); | 
|         $crc32  = crc32($data); | 
|   | 
|         $gzdata = gzcompress($data); | 
|         $gzdata = substr($gzdata, 2, -4); | 
|         $compressed_size = strlen($gzdata); | 
|   | 
|         $this->zipdata .= | 
|             "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00" | 
|             .pack('v', $file_mtime) | 
|             .pack('v', $file_mdate) | 
|             .pack('V', $crc32) | 
|             .pack('V', $compressed_size) | 
|             .pack('V', $uncompressed_size) | 
|             .pack('v', strlen($filepath)) // length of filename | 
|             .pack('v', 0) // extra field length | 
|             .$filepath | 
|             .$gzdata; // "file data" segment | 
|   | 
|         $this->directory .= | 
|             "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00" | 
|             .pack('v', $file_mtime) | 
|             .pack('v', $file_mdate) | 
|             .pack('V', $crc32) | 
|             .pack('V', $compressed_size) | 
|             .pack('V', $uncompressed_size) | 
|             .pack('v', strlen($filepath)) // length of filename | 
|             .pack('v', 0) // extra field length | 
|             .pack('v', 0) // file comment length | 
|             .pack('v', 0) // disk number start | 
|             .pack('v', 0) // internal file attributes | 
|             .pack('V', 32) // external file attributes - 'archive' bit set | 
|             .pack('V', $this->offset) // relative offset of local header | 
|             .$filepath; | 
|   | 
|         $this->offset = strlen($this->zipdata); | 
|         $this->entries++; | 
|         $this->file_num++; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Read the contents of a file and add it to the zip | 
|      * | 
|      * @access    public | 
|      * @return    bool | 
|      */ | 
|     function read_file($path, $preserve_filepath = FALSE) | 
|     { | 
|         if ( ! file_exists($path)) | 
|         { | 
|             return FALSE; | 
|         } | 
|   | 
|         if (FALSE !== ($data = file_get_contents($path))) | 
|         { | 
|             $name = str_replace("\\", "/", $path); | 
|   | 
|             if ($preserve_filepath === FALSE) | 
|             { | 
|                 $name = preg_replace("|.*/(.+)|", "\\1", $name); | 
|             } | 
|   | 
|             $this->add_data($name, $data); | 
|             return TRUE; | 
|         } | 
|         return FALSE; | 
|     } | 
|   | 
|     // ------------------------------------------------------------------------ | 
|   | 
|     /** | 
|      * Read a directory and add it to the zip. | 
|      * | 
|      * This function recursively reads a folder and everything it contains (including | 
|      * sub-folders) and creates a zip based on it.  Whatever directory structure | 
|      * is in the original file path will be recreated in the zip file. | 
|      * | 
|      * @access    public | 
|      * @param    string    path to source | 
|      * @return    bool | 
|      */ | 
|     function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL) | 
|     { | 
|         if ( ! $fp = @opendir($path)) | 
|         { | 
|             return FALSE; | 
|         } | 
|   | 
|         // Set the original directory root for child dir's to use as relative | 
|         if ($root_path === NULL) | 
|         { | 
|             $root_path = dirname($path).'/'; | 
|         } | 
|   | 
|         while (FALSE !== ($file = readdir($fp))) | 
|         { | 
|             if (substr($file, 0, 1) == '.') | 
|             { | 
|                 continue; | 
|             } | 
|   | 
|             if (@is_dir($path.$file)) | 
|             { | 
|                 $this->read_dir($path.$file."/", $preserve_filepath, $root_path); | 
|             } | 
|             else | 
|             { | 
|                 if (FALSE !== ($data = file_get_contents($path.$file))) | 
|                 { | 
|                     $name = str_replace("\\", "/", $path); | 
|   | 
|                     if ($preserve_filepath === FALSE) | 
|                     { | 
|                         $name = str_replace($root_path, '', $name); | 
|                     } | 
|   | 
|                     $this->add_data($name.$file, $data); | 
|                 } | 
|             } | 
|         } | 
|   | 
|         return TRUE; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Get the Zip file | 
|      * | 
|      * @access    public | 
|      * @return    binary string | 
|      */ | 
|     function get_zip() | 
|     { | 
|         // Is there any data to return? | 
|         if ($this->entries == 0) | 
|         { | 
|             return FALSE; | 
|         } | 
|   | 
|         $zip_data = $this->zipdata; | 
|         $zip_data .= $this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00"; | 
|         $zip_data .= pack('v', $this->entries); // total # of entries "on this disk" | 
|         $zip_data .= pack('v', $this->entries); // total # of entries overall | 
|         $zip_data .= pack('V', strlen($this->directory)); // size of central dir | 
|         $zip_data .= pack('V', strlen($this->zipdata)); // offset to start of central dir | 
|         $zip_data .= "\x00\x00"; // .zip file comment length | 
|   | 
|         return $zip_data; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Write File to the specified directory | 
|      * | 
|      * Lets you write a file | 
|      * | 
|      * @access    public | 
|      * @param    string    the file name | 
|      * @return    bool | 
|      */ | 
|     function archive($filepath) | 
|     { | 
|         if ( ! ($fp = @fopen($filepath, FOPEN_WRITE_CREATE_DESTRUCTIVE))) | 
|         { | 
|             return FALSE; | 
|         } | 
|   | 
|         flock($fp, LOCK_EX); | 
|         fwrite($fp, $this->get_zip()); | 
|         flock($fp, LOCK_UN); | 
|         fclose($fp); | 
|   | 
|         return TRUE; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Download | 
|      * | 
|      * @access    public | 
|      * @param    string    the file name | 
|      * @param    string    the data to be encoded | 
|      * @return    bool | 
|      */ | 
|     function download($filename = 'backup.zip') | 
|     { | 
|         if ( ! preg_match("|.+?\.zip$|", $filename)) | 
|         { | 
|             $filename .= '.zip'; | 
|         } | 
|   | 
|         $CI =& get_instance(); | 
|         $CI->load->helper('download'); | 
|   | 
|         $get_zip = $this->get_zip(); | 
|   | 
|         $zip_content =& $get_zip; | 
|   | 
|         force_download($filename, $zip_content); | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Initialize Data | 
|      * | 
|      * Lets you clear current zip data.  Useful if you need to create | 
|      * multiple zips with different data. | 
|      * | 
|      * @access    public | 
|      * @return    void | 
|      */ | 
|     function clear_data() | 
|     { | 
|         $this->zipdata        = ''; | 
|         $this->directory    = ''; | 
|         $this->entries        = 0; | 
|         $this->file_num        = 0; | 
|         $this->offset        = 0; | 
|     } | 
|   | 
| } | 
|   | 
| /* End of file Zip.php */ | 
| /* Location: ./system/libraries/Zip.php */ |