blob: a11699956d947bc05eb4e33cd11601c3c0227fbf [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 }
44
adminae58a5d2006-09-30 19:25:07 +000045
46 /**
admin6ae57e02006-10-01 07:59:45 +000047 * Add Directory
48 *
49 * Lets you add a virtual directory into which you can place files.
adminae58a5d2006-09-30 19:25:07 +000050 *
51 * @access public
admin24dd7e72006-10-01 19:02:29 +000052 * @param mixed the directory name. Can be string or array
53 * @return void
54 */
55 function add_dir($directory)
56 {
57 foreach ((array)$directory as $dir)
58 {
59 if ( ! preg_match("|.+/$|", $dir))
60 {
61 $dir .= '/';
62 }
63
64 $this->_add_dir($dir);
65 }
66 }
67
68 // --------------------------------------------------------------------
69
70 /**
71 * Add Directory
72 *
73 * @access private
admin6ae57e02006-10-01 07:59:45 +000074 * @param string the directory name
adminae58a5d2006-09-30 19:25:07 +000075 * @return void
admin6ae57e02006-10-01 07:59:45 +000076 */
admin24dd7e72006-10-01 19:02:29 +000077 function _add_dir($dir)
admin6ae57e02006-10-01 07:59:45 +000078 {
admin6ae57e02006-10-01 07:59:45 +000079 $dir = str_replace("\\", "/", $dir);
80
81 $this->zipdata[] = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
82 .pack('V', 0)
83 .pack('V', 0)
84 .pack('V', 0)
85 .pack('v', strlen($dir))
86 .pack('v', 0)
87 .$dir
88 .pack('V', 0)
89 .pack('V', 0)
90 .pack('V', 0);
91
92 $newoffset = strlen(implode('', $this->zipdata));
93
94 $record = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"
95 .pack('V',0)
96 .pack('V',0)
97 .pack('V',0)
98 .pack('v', strlen($dir))
99 .pack('v', 0)
100 .pack('v', 0)
101 .pack('v', 0)
102 .pack('v', 0)
103 .pack('V', 16)
104 .pack('V', $this->offset)
105 .$dir;
106
107 $this->offset = $newoffset;
108 $this->directory[] = $record;
admin24dd7e72006-10-01 19:02:29 +0000109 }
110
adminae58a5d2006-09-30 19:25:07 +0000111 // --------------------------------------------------------------------
112
113 /**
admin24dd7e72006-10-01 19:02:29 +0000114 * Add Data to Zip
admin6ae57e02006-10-01 07:59:45 +0000115 *
116 * Lets you add files to the archive. If the path is included
117 * in the filename it will be placed within a directory. Make
118 * sure you use add_dir() first to create the folder.
adminae58a5d2006-09-30 19:25:07 +0000119 *
120 * @access public
admin24dd7e72006-10-01 19:02:29 +0000121 * @param mixed
122 * @param string
123 * @return void
124 */
125 function add_data($filepath, $data = NULL)
126 {
127 if (is_array($filepath))
128 {
129 foreach ($filepath as $path => $data)
130 {
131 $this->_add_data($path, $data);
132 }
133 }
134 else
135 {
136 $this->_add_data($filepath, $data);
137 }
138 }
139
140 // --------------------------------------------------------------------
141
142 /**
143 * Add Data to Zip
144 *
145 * @access private
146 * @param string the file name/path
admin6ae57e02006-10-01 07:59:45 +0000147 * @param string the data to be encoded
adminae58a5d2006-09-30 19:25:07 +0000148 * @return void
149 */
admin24dd7e72006-10-01 19:02:29 +0000150 function _add_data($filepath, $data)
151 {
152 $filepath = str_replace("\\", "/", $filepath);
admin6ae57e02006-10-01 07:59:45 +0000153
154 $oldlen = strlen($data);
155 $crc32 = crc32($data);
156
157 $gzdata = gzcompress($data);
158 $gzdata = substr(substr($gzdata, 0, strlen($gzdata) - 4), 2);
159 $newlen = strlen($gzdata);
160
161 $this->zipdata[] = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
162 .pack('V', $crc32)
163 .pack('V', $newlen)
164 .pack('V', $oldlen)
admin24dd7e72006-10-01 19:02:29 +0000165 .pack('v', strlen($filepath))
admin6ae57e02006-10-01 07:59:45 +0000166 .pack('v', 0)
admin24dd7e72006-10-01 19:02:29 +0000167 .$filepath
admin6ae57e02006-10-01 07:59:45 +0000168 .$gzdata
169 .pack('V', $crc32)
170 .pack('V', $newlen)
171 .pack('V', $oldlen);
172
173 $newoffset = strlen(implode("", $this->zipdata));
174
175 $record = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"
176 .pack('V', $crc32)
177 .pack('V', $newlen)
178 .pack('V', $oldlen)
admin24dd7e72006-10-01 19:02:29 +0000179 .pack('v', strlen($filepath))
admin6ae57e02006-10-01 07:59:45 +0000180 .pack('v', 0)
181 .pack('v', 0)
182 .pack('v', 0)
183 .pack('v', 0)
184 .pack('V', 32)
185 .pack('V', $this->offset);
186
187 $this->offset = $newoffset;
admin24dd7e72006-10-01 19:02:29 +0000188 $this->directory[] = $record.$filepath;
admin6ae57e02006-10-01 07:59:45 +0000189 }
190
191 // --------------------------------------------------------------------
adminae58a5d2006-09-30 19:25:07 +0000192
admin6ae57e02006-10-01 07:59:45 +0000193 /**
194 * Get the Zip file
195 *
196 * @access public
197 * @return binary string
198 */
199 function get_zip()
200 {
admin24dd7e72006-10-01 19:02:29 +0000201 // We cache the zip data so multiple calls
202 // do not require recompiling
admin6ae57e02006-10-01 07:59:45 +0000203 if ($this->zipfile != '')
204 {
205 return $this->zipfile;
206 }
207
admin24dd7e72006-10-01 19:02:29 +0000208 // Is there any data to return?
209 if (count($this->zipdata) == 0)
210 {
211 return FALSE;
212 }
213
admin6ae57e02006-10-01 07:59:45 +0000214 $data = implode('', $this->zipdata);
215 $dir = implode('', $this->directory);
216
217 $this->zipfile = $data.$dir."\x50\x4b\x05\x06\x00\x00\x00\x00"
218 .pack('v', sizeof($this->directory))
219 .pack('v', sizeof($this->directory))
220 .pack('V', strlen($dir))
221 .pack('V', strlen($data))
222 ."\x00\x00";
admin24dd7e72006-10-01 19:02:29 +0000223
admin6ae57e02006-10-01 07:59:45 +0000224 return $this->zipfile;
225 }
226
227 // --------------------------------------------------------------------
adminae58a5d2006-09-30 19:25:07 +0000228
admin6ae57e02006-10-01 07:59:45 +0000229 /**
230 * Write File
231 *
232 * Lets you write a file
233 *
234 * @access public
235 * @param string the file name
236 * @param string the data to be encoded
237 * @return bool
238 */
admin24dd7e72006-10-01 19:02:29 +0000239 function write_zip($filepath)
admin6ae57e02006-10-01 07:59:45 +0000240 {
admin24dd7e72006-10-01 19:02:29 +0000241 if ( ! ($fp = fopen($filepath, "wb")))
admin6ae57e02006-10-01 07:59:45 +0000242 {
243 return FALSE;
244 }
245
246 flock($fp, LOCK_EX);
admin24dd7e72006-10-01 19:02:29 +0000247 fwrite($fp, $this->get_zip());
admin6ae57e02006-10-01 07:59:45 +0000248 flock($fp, LOCK_UN);
249 fclose($fp);
250
251 return TRUE;
252 }
253
254 // --------------------------------------------------------------------
255
256 /**
257 * Download
258 *
admin6ae57e02006-10-01 07:59:45 +0000259 * @access public
260 * @param string the file name
261 * @param string the data to be encoded
262 * @return bool
263 */
admin33dd95d2006-10-01 19:20:42 +0000264 function download($filename = 'backup.zip')
admin6ae57e02006-10-01 07:59:45 +0000265 {
admin33dd95d2006-10-01 19:20:42 +0000266 if ( ! preg_match("|.+?\.zip$|", $filename))
267 {
268 $filename .= '.zip';
269 }
270
admin6ae57e02006-10-01 07:59:45 +0000271 if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
272 {
273 header('Content-Type: application/x-zip');
274 header('Content-Disposition: inline; filename="'.$filename.'"');
275 header('Expires: 0');
276 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
277 header("Content-Transfer-Encoding: binary");
278 header('Pragma: public');
admin24dd7e72006-10-01 19:02:29 +0000279 header("Content-Length: ".strlen($this->get_zip()));
admin6ae57e02006-10-01 07:59:45 +0000280 }
281 else
282 {
283 header('Content-Type: application/x-zip');
284 header('Content-Disposition: attachment; filename="'.$filename.'"');
285 header("Content-Transfer-Encoding: binary");
286 header('Expires: 0');
287 header('Pragma: no-cache');
admin24dd7e72006-10-01 19:02:29 +0000288 header("Content-Length: ".strlen($this->get_zip()));
admin6ae57e02006-10-01 07:59:45 +0000289 }
290
admin24dd7e72006-10-01 19:02:29 +0000291 echo $this->get_zip();
292 }
293
294 // --------------------------------------------------------------------
295
296 /**
297 * Initialize Data
298 *
299 * Lets you clear current zip data. Useful if you need to create
300 * multiple zips with different data.
301 *
302 * @access public
303 * @return void
304 */
305 function clear_data()
306 {
307 $this->zipfile = '';
308 $this->zipdata = array();
309 $this->directory = array();
310 $this->offset = array();
admin6ae57e02006-10-01 07:59:45 +0000311 }
312
adminae58a5d2006-09-30 19:25:07 +0000313}
adminae58a5d2006-09-30 19:25:07 +0000314?>