Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2005 Aurelien 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, 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
 */
33
class 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 */