blob: e13c713fe973b1c3c443360355fa542cc2abf334 [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.
10 * @license http://www.codeignitor.com/user_guide/license.html
11 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
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 *
admin24dd7e72006-10-01 19:02:29 +000024 * The original library is a little rough around the edges so I
25 * refactored it and added several additional methods -- Rick Ellis
adminae58a5d2006-09-30 19:25:07 +000026 *
27 * @package CodeIgniter
28 * @subpackage Libraries
29 * @category Encryption
30 * @author Rick Ellis
31 * @link http://www.codeigniter.com/user_guide/general/encryption.html
32 */
admin24dd7e72006-10-01 19:02:29 +000033class CI_Zip {
34
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 */
56 function add_dir($directory)
57 {
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 */
admin24dd7e72006-10-01 19:02:29 +000078 function _add_dir($dir)
admin6ae57e02006-10-01 07:59:45 +000079 {
admin6ae57e02006-10-01 07:59:45 +000080 $dir = str_replace("\\", "/", $dir);
81
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)
91 .pack('V', 0);
92
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;
109 $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 {
153 $filepath = str_replace("\\", "/", $filepath);
admin6ae57e02006-10-01 07:59:45 +0000154
155 $oldlen = strlen($data);
156 $crc32 = crc32($data);
157
158 $gzdata = gzcompress($data);
159 $gzdata = substr(substr($gzdata, 0, strlen($gzdata) - 4), 2);
160 $newlen = strlen($gzdata);
161
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)
172 .pack('V', $oldlen);
173
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)
186 .pack('V', $this->offset);
187
188 $this->offset = $newoffset;
admin24dd7e72006-10-01 19:02:29 +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 /**
195 * Get the Zip file
196 *
197 * @access public
198 * @return binary string
199 */
200 function get_zip()
201 {
admin24dd7e72006-10-01 19:02:29 +0000202 // We cache the zip data so multiple calls
203 // do not require recompiling
admin6ae57e02006-10-01 07:59:45 +0000204 if ($this->zipfile != '')
205 {
206 return $this->zipfile;
207 }
208
admin24dd7e72006-10-01 19:02:29 +0000209 // Is there any data to return?
210 if (count($this->zipdata) == 0)
211 {
212 return FALSE;
213 }
214
admin6ae57e02006-10-01 07:59:45 +0000215 $data = implode('', $this->zipdata);
216 $dir = implode('', $this->directory);
217
218 $this->zipfile = $data.$dir."\x50\x4b\x05\x06\x00\x00\x00\x00"
219 .pack('v', sizeof($this->directory))
220 .pack('v', sizeof($this->directory))
221 .pack('V', strlen($dir))
222 .pack('V', strlen($data))
223 ."\x00\x00";
admin24dd7e72006-10-01 19:02:29 +0000224
admin6ae57e02006-10-01 07:59:45 +0000225 return $this->zipfile;
226 }
227
228 // --------------------------------------------------------------------
adminae58a5d2006-09-30 19:25:07 +0000229
admin6ae57e02006-10-01 07:59:45 +0000230 /**
admin0f8015f2006-10-01 22:08:34 +0000231 * Write File to the specified direcotry
admin6ae57e02006-10-01 07:59:45 +0000232 *
233 * Lets you write a file
234 *
235 * @access public
236 * @param string the file name
237 * @param string the data to be encoded
238 * @return bool
239 */
admin0f8015f2006-10-01 22:08:34 +0000240 function archive($filepath)
admin6ae57e02006-10-01 07:59:45 +0000241 {
admin0f8015f2006-10-01 22:08:34 +0000242 if ( ! ($fp = @fopen($filepath, "wb")))
admin6ae57e02006-10-01 07:59:45 +0000243 {
244 return FALSE;
245 }
246
247 flock($fp, LOCK_EX);
admin24dd7e72006-10-01 19:02:29 +0000248 fwrite($fp, $this->get_zip());
admin6ae57e02006-10-01 07:59:45 +0000249 flock($fp, LOCK_UN);
250 fclose($fp);
251
252 return TRUE;
253 }
254
255 // --------------------------------------------------------------------
256
257 /**
258 * Download
259 *
admin6ae57e02006-10-01 07:59:45 +0000260 * @access public
261 * @param string the file name
262 * @param string the data to be encoded
263 * @return bool
264 */
admin33dd95d2006-10-01 19:20:42 +0000265 function download($filename = 'backup.zip')
admin6ae57e02006-10-01 07:59:45 +0000266 {
admin33dd95d2006-10-01 19:20:42 +0000267 if ( ! preg_match("|.+?\.zip$|", $filename))
268 {
269 $filename .= '.zip';
270 }
271
admin6ae57e02006-10-01 07:59:45 +0000272 if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
273 {
274 header('Content-Type: application/x-zip');
275 header('Content-Disposition: inline; filename="'.$filename.'"');
276 header('Expires: 0');
277 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
278 header("Content-Transfer-Encoding: binary");
279 header('Pragma: public');
admin24dd7e72006-10-01 19:02:29 +0000280 header("Content-Length: ".strlen($this->get_zip()));
admin6ae57e02006-10-01 07:59:45 +0000281 }
282 else
283 {
284 header('Content-Type: application/x-zip');
285 header('Content-Disposition: attachment; filename="'.$filename.'"');
286 header("Content-Transfer-Encoding: binary");
287 header('Expires: 0');
288 header('Pragma: no-cache');
admin24dd7e72006-10-01 19:02:29 +0000289 header("Content-Length: ".strlen($this->get_zip()));
admin6ae57e02006-10-01 07:59:45 +0000290 }
291
admin24dd7e72006-10-01 19:02:29 +0000292 echo $this->get_zip();
293 }
294
295 // --------------------------------------------------------------------
296
297 /**
298 * Initialize Data
299 *
300 * Lets you clear current zip data. Useful if you need to create
301 * multiple zips with different data.
302 *
303 * @access public
304 * @return void
305 */
306 function clear_data()
307 {
308 $this->zipfile = '';
309 $this->zipdata = array();
310 $this->directory = array();
311 $this->offset = array();
admin6ae57e02006-10-01 07:59:45 +0000312 }
313
adminae58a5d2006-09-30 19:25:07 +0000314}
adminae58a5d2006-09-30 19:25:07 +0000315?>