blob: 1ff175fe244385e16023ce210e5d61a9e777f783 [file] [log] [blame]
adminae58a5d2006-09-30 19:25:07 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * Code Igniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, pMachine, Inc.
admine334c472006-10-21 19:44:22 +000010 * @license http://www.codeignitor.com/user_guide/license.html
adminae58a5d2006-09-30 19:25:07 +000011 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
admine334c472006-10-21 19:44:22 +000015
adminae58a5d2006-09-30 19:25:07 +000016// ------------------------------------------------------------------------
17
18/**
19 * Zip Compression Class
20 *
admin24dd7e72006-10-01 19:02:29 +000021 * This class is based on a library I found at Zend:
adminae58a5d2006-09-30 19:25:07 +000022 * http://www.zend.com/codex.php?id=696&single=1
23 *
admine334c472006-10-21 19:44:22 +000024 * The original library is a little rough around the edges so I
admin24dd7e72006-10-01 19:02:29 +000025 * refactored it and added several additional methods -- Rick Ellis
admine334c472006-10-21 19:44:22 +000026 *
adminae58a5d2006-09-30 19:25:07 +000027 * @package CodeIgniter
28 * @subpackage Libraries
29 * @category Encryption
30 * @author Rick Ellis
adminebfa6862006-11-05 21:31:00 +000031 * @link http://www.codeigniter.com/user_guide/libraries/zip.html
adminae58a5d2006-09-30 19:25:07 +000032 */
admine334c472006-10-21 19:44:22 +000033class CI_Zip {
admin24dd7e72006-10-01 19:02:29 +000034
35 var $zipfile = '';
admin6ae57e02006-10-01 07:59:45 +000036 var $zipdata = array();
37 var $directory = array();
38 var $offset = 0;
admin24dd7e72006-10-01 19:02:29 +000039
40 function CI_Zip()
41 {
42 log_message('debug', "Zip Compression Class Initialized");
43 }
admin10c3f412006-10-08 07:21:12 +000044
45 // --------------------------------------------------------------------
adminae58a5d2006-09-30 19:25:07 +000046
47 /**
admin6ae57e02006-10-01 07:59:45 +000048 * Add Directory
49 *
50 * Lets you add a virtual directory into which you can place files.
adminae58a5d2006-09-30 19:25:07 +000051 *
52 * @access public
admin24dd7e72006-10-01 19:02:29 +000053 * @param mixed the directory name. Can be string or array
54 * @return void
55 */
admine334c472006-10-21 19:44:22 +000056 function add_dir($directory)
admin24dd7e72006-10-01 19:02:29 +000057 {
58 foreach ((array)$directory as $dir)
59 {
60 if ( ! preg_match("|.+/$|", $dir))
61 {
62 $dir .= '/';
63 }
64
65 $this->_add_dir($dir);
66 }
67 }
68
69 // --------------------------------------------------------------------
70
71 /**
72 * Add Directory
73 *
74 * @access private
admin6ae57e02006-10-01 07:59:45 +000075 * @param string the directory name
adminae58a5d2006-09-30 19:25:07 +000076 * @return void
admin6ae57e02006-10-01 07:59:45 +000077 */
admine334c472006-10-21 19:44:22 +000078 function _add_dir($dir)
admin6ae57e02006-10-01 07:59:45 +000079 {
admine334c472006-10-21 19:44:22 +000080 $dir = str_replace("\\", "/", $dir);
admin6ae57e02006-10-01 07:59:45 +000081
82 $this->zipdata[] = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
83 .pack('V', 0)
84 .pack('V', 0)
85 .pack('V', 0)
86 .pack('v', strlen($dir))
87 .pack('v', 0)
88 .$dir
89 .pack('V', 0)
90 .pack('V', 0)
admine334c472006-10-21 19:44:22 +000091 .pack('V', 0);
admin6ae57e02006-10-01 07:59:45 +000092
93 $newoffset = strlen(implode('', $this->zipdata));
94
95 $record = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
96 .pack('V',0)
97 .pack('V',0)
98 .pack('V',0)
99 .pack('v', strlen($dir))
100 .pack('v', 0)
101 .pack('v', 0)
102 .pack('v', 0)
103 .pack('v', 0)
104 .pack('V', 16)
105 .pack('V', $this->offset)
106 .$dir;
107
108 $this->offset = $newoffset;
admine334c472006-10-21 19:44:22 +0000109 $this->directory[] = $record;
admin24dd7e72006-10-01 19:02:29 +0000110 }
111
adminae58a5d2006-09-30 19:25:07 +0000112 // --------------------------------------------------------------------
113
114 /**
admin24dd7e72006-10-01 19:02:29 +0000115 * Add Data to Zip
admin6ae57e02006-10-01 07:59:45 +0000116 *
117 * Lets you add files to the archive. If the path is included
118 * in the filename it will be placed within a directory. Make
119 * sure you use add_dir() first to create the folder.
adminae58a5d2006-09-30 19:25:07 +0000120 *
121 * @access public
admin24dd7e72006-10-01 19:02:29 +0000122 * @param mixed
123 * @param string
124 * @return void
125 */
126 function add_data($filepath, $data = NULL)
127 {
128 if (is_array($filepath))
129 {
130 foreach ($filepath as $path => $data)
131 {
132 $this->_add_data($path, $data);
133 }
134 }
135 else
136 {
137 $this->_add_data($filepath, $data);
138 }
139 }
140
141 // --------------------------------------------------------------------
142
143 /**
144 * Add Data to Zip
145 *
146 * @access private
147 * @param string the file name/path
admin6ae57e02006-10-01 07:59:45 +0000148 * @param string the data to be encoded
adminae58a5d2006-09-30 19:25:07 +0000149 * @return void
150 */
admin24dd7e72006-10-01 19:02:29 +0000151 function _add_data($filepath, $data)
152 {
admine334c472006-10-21 19:44:22 +0000153 $filepath = str_replace("\\", "/", $filepath);
admin6ae57e02006-10-01 07:59:45 +0000154
admine334c472006-10-21 19:44:22 +0000155 $oldlen = strlen($data);
156 $crc32 = crc32($data);
admin6ae57e02006-10-01 07:59:45 +0000157
158 $gzdata = gzcompress($data);
159 $gzdata = substr(substr($gzdata, 0, strlen($gzdata) - 4), 2);
admine334c472006-10-21 19:44:22 +0000160 $newlen = strlen($gzdata);
admin6ae57e02006-10-01 07:59:45 +0000161
162 $this->zipdata[] = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
163 .pack('V', $crc32)
164 .pack('V', $newlen)
165 .pack('V', $oldlen)
admin24dd7e72006-10-01 19:02:29 +0000166 .pack('v', strlen($filepath))
admin6ae57e02006-10-01 07:59:45 +0000167 .pack('v', 0)
admin24dd7e72006-10-01 19:02:29 +0000168 .$filepath
admin6ae57e02006-10-01 07:59:45 +0000169 .$gzdata
170 .pack('V', $crc32)
171 .pack('V', $newlen)
admine334c472006-10-21 19:44:22 +0000172 .pack('V', $oldlen);
admin6ae57e02006-10-01 07:59:45 +0000173
174 $newoffset = strlen(implode("", $this->zipdata));
175
176 $record = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
177 .pack('V', $crc32)
178 .pack('V', $newlen)
179 .pack('V', $oldlen)
admin24dd7e72006-10-01 19:02:29 +0000180 .pack('v', strlen($filepath))
admin6ae57e02006-10-01 07:59:45 +0000181 .pack('v', 0)
182 .pack('v', 0)
183 .pack('v', 0)
184 .pack('v', 0)
185 .pack('V', 32)
admine334c472006-10-21 19:44:22 +0000186 .pack('V', $this->offset);
admin6ae57e02006-10-01 07:59:45 +0000187
188 $this->offset = $newoffset;
admine334c472006-10-21 19:44:22 +0000189 $this->directory[] = $record.$filepath;
admin6ae57e02006-10-01 07:59:45 +0000190 }
191
192 // --------------------------------------------------------------------
adminae58a5d2006-09-30 19:25:07 +0000193
admin6ae57e02006-10-01 07:59:45 +0000194 /**
admin5725a402006-10-23 20:02:04 +0000195 * Read the contents of a file and add it to the zip
196 *
197 * @access public
198 * @return bool
199 */
200 function read_file($path, $preserve_filepath = FALSE)
201 {
202 if ( ! file_exists($path))
203 {
204 return FALSE;
205 }
206
207 if (FALSE !== ($data = file_get_contents($path)))
208 {
209 $name = str_replace("\\", "/", $path);
210
211 if ($preserve_filepath === FALSE)
212 {
213 $name = preg_replace("|.*/(.+)|", "\\1", $name);
214 }
215
216 $this->add_data($name, $data);
217 return TRUE;
218 }
219 return FALSE;
220 }
221
222 // ------------------------------------------------------------------------
223
224 /**
225 * Read a directory and add it to the zip.
226 *
227 * This function recursively reads a folder and everything it contains (including
228 * sub-folders) and creates a zip based on it. Whatever directory structure
229 * is in the original file path will be recreated in the zip file.
230 *
231 * @access public
232 * @param string path to source
233 * @return bool
234 */
235 function read_dir($path)
236 {
237 if ($fp = @opendir($path))
238 {
239 while (FALSE !== ($file = readdir($fp)))
240 {
241 if (@is_dir($path.$file) && substr($file, 0, 1) != '.')
242 {
243 $this->read_dir($path.$file."/");
244 }
245 elseif (substr($file, 0, 1) != ".")
246 {
247 if (FALSE !== ($data = file_get_contents($path.$file)))
248 {
249 $this->add_data(str_replace("\\", "/", $path).$file, $data);
250 }
251 }
252 }
253 return TRUE;
254 }
255 }
256
257 // --------------------------------------------------------------------
258
259 /**
admin6ae57e02006-10-01 07:59:45 +0000260 * Get the Zip file
261 *
262 * @access public
263 * @return binary string
264 */
265 function get_zip()
admine334c472006-10-21 19:44:22 +0000266 {
admin24dd7e72006-10-01 19:02:29 +0000267 // We cache the zip data so multiple calls
268 // do not require recompiling
admin6ae57e02006-10-01 07:59:45 +0000269 if ($this->zipfile != '')
270 {
271 return $this->zipfile;
272 }
273
admin24dd7e72006-10-01 19:02:29 +0000274 // Is there any data to return?
275 if (count($this->zipdata) == 0)
276 {
277 return FALSE;
278 }
279
admine334c472006-10-21 19:44:22 +0000280 $data = implode('', $this->zipdata);
281 $dir = implode('', $this->directory);
admin6ae57e02006-10-01 07:59:45 +0000282
283 $this->zipfile = $data.$dir."\x50\x4b\x05\x06\x00\x00\x00\x00"
284 .pack('v', sizeof($this->directory))
285 .pack('v', sizeof($this->directory))
286 .pack('V', strlen($dir))
287 .pack('V', strlen($data))
288 ."\x00\x00";
admin24dd7e72006-10-01 19:02:29 +0000289
admin6ae57e02006-10-01 07:59:45 +0000290 return $this->zipfile;
291 }
292
293 // --------------------------------------------------------------------
adminae58a5d2006-09-30 19:25:07 +0000294
admin6ae57e02006-10-01 07:59:45 +0000295 /**
admine7e1dcd2006-10-21 18:04:01 +0000296 * Write File to the specified directory
admin6ae57e02006-10-01 07:59:45 +0000297 *
298 * Lets you write a file
299 *
300 * @access public
301 * @param string the file name
302 * @param string the data to be encoded
303 * @return bool
304 */
admin0f8015f2006-10-01 22:08:34 +0000305 function archive($filepath)
admin6ae57e02006-10-01 07:59:45 +0000306 {
admin0f8015f2006-10-01 22:08:34 +0000307 if ( ! ($fp = @fopen($filepath, "wb")))
admin6ae57e02006-10-01 07:59:45 +0000308 {
309 return FALSE;
310 }
311
312 flock($fp, LOCK_EX);
admin24dd7e72006-10-01 19:02:29 +0000313 fwrite($fp, $this->get_zip());
admin6ae57e02006-10-01 07:59:45 +0000314 flock($fp, LOCK_UN);
315 fclose($fp);
316
317 return TRUE;
318 }
319
320 // --------------------------------------------------------------------
321
322 /**
323 * Download
324 *
admin6ae57e02006-10-01 07:59:45 +0000325 * @access public
326 * @param string the file name
327 * @param string the data to be encoded
328 * @return bool
329 */
admin33dd95d2006-10-01 19:20:42 +0000330 function download($filename = 'backup.zip')
admin6ae57e02006-10-01 07:59:45 +0000331 {
admin33dd95d2006-10-01 19:20:42 +0000332 if ( ! preg_match("|.+?\.zip$|", $filename))
333 {
334 $filename .= '.zip';
335 }
336
admin6ae57e02006-10-01 07:59:45 +0000337 if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
338 {
339 header('Content-Type: application/x-zip');
340 header('Content-Disposition: inline; filename="'.$filename.'"');
341 header('Expires: 0');
342 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
343 header("Content-Transfer-Encoding: binary");
344 header('Pragma: public');
admin24dd7e72006-10-01 19:02:29 +0000345 header("Content-Length: ".strlen($this->get_zip()));
admine334c472006-10-21 19:44:22 +0000346 }
347 else
admin6ae57e02006-10-01 07:59:45 +0000348 {
349 header('Content-Type: application/x-zip');
350 header('Content-Disposition: attachment; filename="'.$filename.'"');
351 header("Content-Transfer-Encoding: binary");
352 header('Expires: 0');
353 header('Pragma: no-cache');
admin24dd7e72006-10-01 19:02:29 +0000354 header("Content-Length: ".strlen($this->get_zip()));
admin6ae57e02006-10-01 07:59:45 +0000355 }
356
admin24dd7e72006-10-01 19:02:29 +0000357 echo $this->get_zip();
358 }
359
360 // --------------------------------------------------------------------
361
362 /**
363 * Initialize Data
364 *
admine334c472006-10-21 19:44:22 +0000365 * Lets you clear current zip data. Useful if you need to create
admin24dd7e72006-10-01 19:02:29 +0000366 * multiple zips with different data.
367 *
368 * @access public
369 * @return void
370 */
371 function clear_data()
372 {
373 $this->zipfile = '';
374 $this->zipdata = array();
375 $this->directory = array();
376 $this->offset = array();
admin6ae57e02006-10-01 07:59:45 +0000377 }
378
adminae58a5d2006-09-30 19:25:07 +0000379}
adminae58a5d2006-09-30 19:25:07 +0000380?>