PageRenderTime 54ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/Zip.php

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