PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Zip.php

https://gitlab.com/RikaPM/manik
PHP | 424 lines | 221 code | 60 blank | 143 comment | 18 complexity | 64265ca9e6a504826f94f91d255146d7 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 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc.
  10. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  11. * @license http://codeigniter.com/user_guide/license.html
  12. * @link http://codeigniter.com
  13. * @since Version 1.0
  14. * @filesource
  15. */
  16. // ------------------------------------------------------------------------
  17. /**
  18. * Zip Compression Class
  19. *
  20. * This class is based on a library I found at Zend:
  21. * http://www.zend.com/codex.php?id=696&single=1
  22. *
  23. * The original library is a little rough around the edges so I
  24. * refactored it and added several additional methods -- Rick Ellis
  25. *
  26. * @package CodeIgniter
  27. * @subpackage Libraries
  28. * @category Encryption
  29. * @author EllisLab Dev Team
  30. * @link http://codeigniter.com/user_guide/libraries/zip.html
  31. */
  32. class CI_Zip {
  33. var $zipdata = '';
  34. var $directory = '';
  35. var $entries = 0;
  36. var $file_num = 0;
  37. var $offset = 0;
  38. var $now;
  39. /**
  40. * Constructor
  41. */
  42. public function __construct()
  43. {
  44. log_message('debug', "Zip Compression Class Initialized");
  45. $this->now = time();
  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. $dir_time = $this->_get_mod_time($dir);
  66. $this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']);
  67. }
  68. }
  69. // --------------------------------------------------------------------
  70. /**
  71. * Get file/directory modification time
  72. *
  73. * If this is a newly created file/dir, we will set the time to 'now'
  74. *
  75. * @param string path to file
  76. * @return array filemtime/filemdate
  77. */
  78. function _get_mod_time($dir)
  79. {
  80. // filemtime() will return false, but it does raise an error.
  81. $date = (@filemtime($dir)) ? filemtime($dir) : getdate($this->now);
  82. $time['file_mtime'] = ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2;
  83. $time['file_mdate'] = (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday'];
  84. return $time;
  85. }
  86. // --------------------------------------------------------------------
  87. /**
  88. * Add Directory
  89. *
  90. * @access private
  91. * @param string the directory name
  92. * @return void
  93. */
  94. function _add_dir($dir, $file_mtime, $file_mdate)
  95. {
  96. $dir = str_replace("\\", "/", $dir);
  97. $this->zipdata .=
  98. "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00"
  99. .pack('v', $file_mtime)
  100. .pack('v', $file_mdate)
  101. .pack('V', 0) // crc32
  102. .pack('V', 0) // compressed filesize
  103. .pack('V', 0) // uncompressed filesize
  104. .pack('v', strlen($dir)) // length of pathname
  105. .pack('v', 0) // extra field length
  106. .$dir
  107. // below is "data descriptor" segment
  108. .pack('V', 0) // crc32
  109. .pack('V', 0) // compressed filesize
  110. .pack('V', 0); // uncompressed filesize
  111. $this->directory .=
  112. "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00"
  113. .pack('v', $file_mtime)
  114. .pack('v', $file_mdate)
  115. .pack('V',0) // crc32
  116. .pack('V',0) // compressed filesize
  117. .pack('V',0) // uncompressed filesize
  118. .pack('v', strlen($dir)) // length of pathname
  119. .pack('v', 0) // extra field length
  120. .pack('v', 0) // file comment length
  121. .pack('v', 0) // disk number start
  122. .pack('v', 0) // internal file attributes
  123. .pack('V', 16) // external file attributes - 'directory' bit set
  124. .pack('V', $this->offset) // relative offset of local header
  125. .$dir;
  126. $this->offset = strlen($this->zipdata);
  127. $this->entries++;
  128. }
  129. // --------------------------------------------------------------------
  130. /**
  131. * Add Data to Zip
  132. *
  133. * Lets you add files to the archive. If the path is included
  134. * in the filename it will be placed within a directory. Make
  135. * sure you use add_dir() first to create the folder.
  136. *
  137. * @access public
  138. * @param mixed
  139. * @param string
  140. * @return void
  141. */
  142. function add_data($filepath, $data = NULL)
  143. {
  144. if (is_array($filepath))
  145. {
  146. foreach ($filepath as $path => $data)
  147. {
  148. $file_data = $this->_get_mod_time($path);
  149. $this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']);
  150. }
  151. }
  152. else
  153. {
  154. $file_data = $this->_get_mod_time($filepath);
  155. $this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']);
  156. }
  157. }
  158. // --------------------------------------------------------------------
  159. /**
  160. * Add Data to Zip
  161. *
  162. * @access private
  163. * @param string the file name/path
  164. * @param string the data to be encoded
  165. * @return void
  166. */
  167. function _add_data($filepath, $data, $file_mtime, $file_mdate)
  168. {
  169. $filepath = str_replace("\\", "/", $filepath);
  170. $uncompressed_size = strlen($data);
  171. $crc32 = crc32($data);
  172. $gzdata = gzcompress($data);
  173. $gzdata = substr($gzdata, 2, -4);
  174. $compressed_size = strlen($gzdata);
  175. $this->zipdata .=
  176. "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00"
  177. .pack('v', $file_mtime)
  178. .pack('v', $file_mdate)
  179. .pack('V', $crc32)
  180. .pack('V', $compressed_size)
  181. .pack('V', $uncompressed_size)
  182. .pack('v', strlen($filepath)) // length of filename
  183. .pack('v', 0) // extra field length
  184. .$filepath
  185. .$gzdata; // "file data" segment
  186. $this->directory .=
  187. "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00"
  188. .pack('v', $file_mtime)
  189. .pack('v', $file_mdate)
  190. .pack('V', $crc32)
  191. .pack('V', $compressed_size)
  192. .pack('V', $uncompressed_size)
  193. .pack('v', strlen($filepath)) // length of filename
  194. .pack('v', 0) // extra field length
  195. .pack('v', 0) // file comment length
  196. .pack('v', 0) // disk number start
  197. .pack('v', 0) // internal file attributes
  198. .pack('V', 32) // external file attributes - 'archive' bit set
  199. .pack('V', $this->offset) // relative offset of local header
  200. .$filepath;
  201. $this->offset = strlen($this->zipdata);
  202. $this->entries++;
  203. $this->file_num++;
  204. }
  205. // --------------------------------------------------------------------
  206. /**
  207. * Read the contents of a file and add it to the zip
  208. *
  209. * @access public
  210. * @return bool
  211. */
  212. function read_file($path, $preserve_filepath = FALSE)
  213. {
  214. if ( ! file_exists($path))
  215. {
  216. return FALSE;
  217. }
  218. if (FALSE !== ($data = file_get_contents($path)))
  219. {
  220. $name = str_replace("\\", "/", $path);
  221. if ($preserve_filepath === FALSE)
  222. {
  223. $name = preg_replace("|.*/(.+)|", "\\1", $name);
  224. }
  225. $this->add_data($name, $data);
  226. return TRUE;
  227. }
  228. return FALSE;
  229. }
  230. // ------------------------------------------------------------------------
  231. /**
  232. * Read a directory and add it to the zip.
  233. *
  234. * This function recursively reads a folder and everything it contains (including
  235. * sub-folders) and creates a zip based on it. Whatever directory structure
  236. * is in the original file path will be recreated in the zip file.
  237. *
  238. * @access public
  239. * @param string path to source
  240. * @return bool
  241. */
  242. function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL)
  243. {
  244. if ( ! $fp = @opendir($path))
  245. {
  246. return FALSE;
  247. }
  248. // Set the original directory root for child dir's to use as relative
  249. if ($root_path === NULL)
  250. {
  251. $root_path = dirname($path).'/';
  252. }
  253. while (FALSE !== ($file = readdir($fp)))
  254. {
  255. if (substr($file, 0, 1) == '.')
  256. {
  257. continue;
  258. }
  259. if (@is_dir($path.$file))
  260. {
  261. $this->read_dir($path.$file."/", $preserve_filepath, $root_path);
  262. }
  263. else
  264. {
  265. if (FALSE !== ($data = file_get_contents($path.$file)))
  266. {
  267. $name = str_replace("\\", "/", $path);
  268. if ($preserve_filepath === FALSE)
  269. {
  270. $name = str_replace($root_path, '', $name);
  271. }
  272. $this->add_data($name.$file, $data);
  273. }
  274. }
  275. }
  276. return TRUE;
  277. }
  278. // --------------------------------------------------------------------
  279. /**
  280. * Get the Zip file
  281. *
  282. * @access public
  283. * @return binary string
  284. */
  285. function get_zip()
  286. {
  287. // Is there any data to return?
  288. if ($this->entries == 0)
  289. {
  290. return FALSE;
  291. }
  292. $zip_data = $this->zipdata;
  293. $zip_data .= $this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00";
  294. $zip_data .= pack('v', $this->entries); // total # of entries "on this disk"
  295. $zip_data .= pack('v', $this->entries); // total # of entries overall
  296. $zip_data .= pack('V', strlen($this->directory)); // size of central dir
  297. $zip_data .= pack('V', strlen($this->zipdata)); // offset to start of central dir
  298. $zip_data .= "\x00\x00"; // .zip file comment length
  299. return $zip_data;
  300. }
  301. // --------------------------------------------------------------------
  302. /**
  303. * Write File to the specified directory
  304. *
  305. * Lets you write a file
  306. *
  307. * @access public
  308. * @param string the file name
  309. * @return bool
  310. */
  311. function archive($filepath)
  312. {
  313. if ( ! ($fp = @fopen($filepath, FOPEN_WRITE_CREATE_DESTRUCTIVE)))
  314. {
  315. return FALSE;
  316. }
  317. flock($fp, LOCK_EX);
  318. fwrite($fp, $this->get_zip());
  319. flock($fp, LOCK_UN);
  320. fclose($fp);
  321. return TRUE;
  322. }
  323. // --------------------------------------------------------------------
  324. /**
  325. * Download
  326. *
  327. * @access public
  328. * @param string the file name
  329. * @param string the data to be encoded
  330. * @return bool
  331. */
  332. function download($filename = 'backup.zip')
  333. {
  334. if ( ! preg_match("|.+?\.zip$|", $filename))
  335. {
  336. $filename .= '.zip';
  337. }
  338. $CI =& get_instance();
  339. $CI->load->helper('download');
  340. $get_zip = $this->get_zip();
  341. $zip_content =& $get_zip;
  342. force_download($filename, $zip_content);
  343. }
  344. // --------------------------------------------------------------------
  345. /**
  346. * Initialize Data
  347. *
  348. * Lets you clear current zip data. Useful if you need to create
  349. * multiple zips with different data.
  350. *
  351. * @access public
  352. * @return void
  353. */
  354. function clear_data()
  355. {
  356. $this->zipdata = '';
  357. $this->directory = '';
  358. $this->entries = 0;
  359. $this->file_num = 0;
  360. $this->offset = 0;
  361. }
  362. }
  363. /* End of file Zip.php */
  364. /* Location: ./system/libraries/Zip.php */