PageRenderTime 26ms CodeModel.GetById 19ms app.highlight 5ms RepoModel.GetById 0ms app.codeStats 1ms

/system/libraries/Zip.php

http://bitstopdev-hostedqueuesys.googlecode.com/
PHP | 359 lines | 186 code | 45 blank | 128 comment | 17 complexity | 20e9638903b7b178270e3072091cf5d5 MD5 | raw file
Possible License(s): Unlicense
  1<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2/**
  3 * CodeIgniter
  4 *
  5 * An open source application development framework for PHP 4.3.2 or newer
  6 *
  7 * @package		CodeIgniter
  8 * @author		ExpressionEngine Dev Team
  9 * @copyright	Copyright (c) 2008 - 2010, EllisLab, Inc.
 10 * @license		http://codeigniter.com/user_guide/license.html
 11 * @link		http://codeigniter.com
 12 * @since		Version 1.0
 13 * @filesource
 14 */
 15
 16// ------------------------------------------------------------------------
 17
 18/**
 19 * Zip Compression Class
 20 *
 21 * This class is based on a library I found at Zend:
 22 * http://www.zend.com/codex.php?id=696&single=1
 23 *
 24 * The original library is a little rough around the edges so I
 25 * refactored it and added several additional methods -- Rick Ellis
 26 *
 27 * @package		CodeIgniter
 28 * @subpackage	Libraries
 29 * @category	Encryption
 30 * @author		ExpressionEngine Dev Team
 31 * @link		http://codeigniter.com/user_guide/libraries/zip.html
 32 */
 33class CI_Zip  {
 34
 35	var $zipdata 	= '';
 36	var $directory 	= '';
 37	var $entries 	= 0;
 38	var $file_num 	= 0;
 39	var $offset		= 0;
 40
 41	function CI_Zip()
 42	{
 43		log_message('debug', "Zip Compression Class Initialized");
 44	}
 45
 46	// --------------------------------------------------------------------
 47
 48	/**
 49	 * Add Directory
 50	 *
 51	 * Lets you add a virtual directory into which you can place files.
 52	 *
 53	 * @access	public
 54	 * @param	mixed	the directory name. Can be string or array
 55	 * @return	void
 56	 */
 57	function add_dir($directory)
 58	{
 59		foreach ((array)$directory as $dir)
 60		{
 61			if ( ! preg_match("|.+/$|", $dir))
 62			{
 63				$dir .= '/';
 64			}
 65
 66			$this->_add_dir($dir);
 67		}
 68	}
 69
 70	// --------------------------------------------------------------------
 71
 72	/**
 73	 * Add Directory
 74	 *
 75	 * @access	private
 76	 * @param	string	the directory name
 77	 * @return	void
 78	 */
 79	function _add_dir($dir)
 80	{
 81		$dir = str_replace("\\", "/", $dir);
 82
 83		$this->zipdata .=
 84			"\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 85			.pack('V', 0) // crc32
 86			.pack('V', 0) // compressed filesize
 87			.pack('V', 0) // uncompressed filesize
 88			.pack('v', strlen($dir)) // length of pathname
 89			.pack('v', 0) // extra field length
 90			.$dir
 91			// below is "data descriptor" segment
 92			.pack('V', 0) // crc32
 93			.pack('V', 0) // compressed filesize
 94			.pack('V', 0); // uncompressed filesize
 95
 96		$this->directory .=
 97			"\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 98			.pack('V',0) // crc32
 99			.pack('V',0) // compressed filesize
100			.pack('V',0) // uncompressed filesize
101			.pack('v', strlen($dir)) // length of pathname
102			.pack('v', 0) // extra field length
103			.pack('v', 0) // file comment length
104			.pack('v', 0) // disk number start
105			.pack('v', 0) // internal file attributes
106			.pack('V', 16) // external file attributes - 'directory' bit set
107			.pack('V', $this->offset) // relative offset of local header
108			.$dir;
109
110		$this->offset = strlen($this->zipdata);
111		$this->entries++;
112	}
113	
114	// --------------------------------------------------------------------
115
116	/**
117	 * Add Data to Zip
118	 *
119	 * Lets you add files to the archive. If the path is included
120	 * in the filename it will be placed within a directory.  Make
121	 * sure you use add_dir() first to create the folder.
122	 *
123	 * @access	public
124	 * @param	mixed
125	 * @param	string
126	 * @return	void
127	 */	
128	function add_data($filepath, $data = NULL)
129	{
130		if (is_array($filepath))
131		{
132			foreach ($filepath as $path => $data)
133			{
134				$this->_add_data($path, $data);
135			}
136		}
137		else
138		{
139			$this->_add_data($filepath, $data);
140		}
141	}
142
143	// --------------------------------------------------------------------
144
145	/**
146	 * Add Data to Zip
147	 *
148	 * @access	private
149	 * @param	string	the file name/path
150	 * @param	string	the data to be encoded
151	 * @return	void
152	 */	
153	function _add_data($filepath, $data)
154	{
155		$filepath = str_replace("\\", "/", $filepath);
156
157		$uncompressed_size = strlen($data);
158		$crc32  = crc32($data);
159
160		$gzdata = gzcompress($data);
161		$gzdata = substr($gzdata, 2, -4);
162		$compressed_size = strlen($gzdata);
163
164		$this->zipdata .=
165			"\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
166			.pack('V', $crc32)
167			.pack('V', $compressed_size)
168			.pack('V', $uncompressed_size)
169			.pack('v', strlen($filepath)) // length of filename
170			.pack('v', 0) // extra field length
171			.$filepath
172			.$gzdata; // "file data" segment
173
174		$this->directory .=
175			"\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
176			.pack('V', $crc32)
177			.pack('V', $compressed_size)
178			.pack('V', $uncompressed_size)
179			.pack('v', strlen($filepath)) // length of filename
180			.pack('v', 0) // extra field length
181			.pack('v', 0) // file comment length
182			.pack('v', 0) // disk number start
183			.pack('v', 0) // internal file attributes
184			.pack('V', 32) // external file attributes - 'archive' bit set
185			.pack('V', $this->offset) // relative offset of local header
186			.$filepath;
187
188		$this->offset = strlen($this->zipdata);
189		$this->entries++;
190		$this->file_num++;
191	}
192	
193	// --------------------------------------------------------------------
194
195	/**
196	 * Read the contents of a file and add it to the zip
197	 *
198	 * @access	public
199	 * @return	bool
200	 */	
201	function read_file($path, $preserve_filepath = FALSE)
202	{
203		if ( ! file_exists($path))
204		{
205			return FALSE;
206		}
207
208		if (FALSE !== ($data = file_get_contents($path)))
209		{
210			$name = str_replace("\\", "/", $path);
211			
212			if ($preserve_filepath === FALSE)
213			{
214				$name = preg_replace("|.*/(.+)|", "\\1", $name);
215			}
216
217			$this->add_data($name, $data);
218			return TRUE;
219		}
220		return FALSE;
221	}
222
223	// ------------------------------------------------------------------------
224	
225	/**
226	 * Read a directory and add it to the zip.
227	 *
228	 * This function recursively reads a folder and everything it contains (including
229	 * sub-folders) and creates a zip based on it.  Whatever directory structure
230	 * is in the original file path will be recreated in the zip file.
231	 *
232	 * @access	public
233	 * @param	string	path to source
234	 * @return	bool
235	 */	
236	function read_dir($path)
237	{	
238		if ($fp = @opendir($path))
239		{
240			while (FALSE !== ($file = readdir($fp)))
241			{
242				if (@is_dir($path.$file) && substr($file, 0, 1) != '.')
243				{					
244					$this->read_dir($path.$file."/");
245				}
246				elseif (substr($file, 0, 1) != ".")
247				{
248					if (FALSE !== ($data = file_get_contents($path.$file)))
249					{						
250						$this->add_data(str_replace("\\", "/", $path).$file, $data);
251					}
252				}
253			}
254			return TRUE;
255		}
256	}
257
258	// --------------------------------------------------------------------
259
260	/**
261	 * Get the Zip file
262	 *
263	 * @access	public
264	 * @return	binary string
265	 */	
266	function get_zip()
267	{
268		// Is there any data to return?
269		if ($this->entries == 0)
270		{
271			return FALSE;
272		}
273
274		$zip_data = $this->zipdata;
275		$zip_data .= $this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00";
276		$zip_data .= pack('v', $this->entries); // total # of entries "on this disk"
277		$zip_data .= pack('v', $this->entries); // total # of entries overall
278		$zip_data .= pack('V', strlen($this->directory)); // size of central dir
279		$zip_data .= pack('V', strlen($this->zipdata)); // offset to start of central dir
280		$zip_data .= "\x00\x00"; // .zip file comment length
281
282		return $zip_data;
283	}
284	
285	// --------------------------------------------------------------------
286
287	/**
288	 * Write File to the specified directory
289	 *
290	 * Lets you write a file
291	 *
292	 * @access	public
293	 * @param	string	the file name
294	 * @return	bool
295	 */	
296	function archive($filepath)
297	{
298		if ( ! ($fp = @fopen($filepath, FOPEN_WRITE_CREATE_DESTRUCTIVE)))
299		{
300			return FALSE;
301		}
302
303		flock($fp, LOCK_EX);	
304		fwrite($fp, $this->get_zip());
305		flock($fp, LOCK_UN);
306		fclose($fp);
307
308		return TRUE;	
309	}
310
311	// --------------------------------------------------------------------
312
313	/**
314	 * Download
315	 *
316	 * @access	public
317	 * @param	string	the file name
318	 * @param	string	the data to be encoded
319	 * @return	bool
320	 */
321	function download($filename = 'backup.zip')
322	{
323		if ( ! preg_match("|.+?\.zip$|", $filename))
324		{
325			$filename .= '.zip';
326		}
327
328		$zip_content =& $this->get_zip();
329
330		$CI =& get_instance();
331		$CI->load->helper('download');
332
333		force_download($filename, $zip_content);
334	}
335
336	// --------------------------------------------------------------------
337
338	/**
339	 * Initialize Data
340	 *
341	 * Lets you clear current zip data.  Useful if you need to create
342	 * multiple zips with different data.
343	 *
344	 * @access	public
345	 * @return	void
346	 */		
347	function clear_data()
348	{
349		$this->zipdata		= '';
350		$this->directory	= '';
351		$this->entries		= 0;
352		$this->file_num		= 0;
353		$this->offset		= 0;
354	}
355	
356}
357
358/* End of file Zip.php */
359/* Location: ./system/libraries/Zip.php */