PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Zip.php

https://gitlab.com/betanurlaila/UI_onlineshop
PHP | 484 lines | 264 code | 46 blank | 174 comment | 12 complexity | 9a5a2ed85084ed71cb6ffdef24fee03d MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * Zip Compression Class
  41. *
  42. * This class is based on a library I found at Zend:
  43. * http://www.zend.com/codex.php?id=696&single=1
  44. *
  45. * The original library is a little rough around the edges so I
  46. * refactored it and added several additional methods -- Rick Ellis
  47. *
  48. * @package CodeIgniter
  49. * @subpackage Libraries
  50. * @category Encryption
  51. * @author EllisLab Dev Team
  52. * @link https://codeigniter.com/user_guide/libraries/zip.html
  53. */
  54. class CI_Zip {
  55. /**
  56. * Zip data in string form
  57. *
  58. * @var string
  59. */
  60. public $zipdata = '';
  61. /**
  62. * Zip data for a directory in string form
  63. *
  64. * @var string
  65. */
  66. public $directory = '';
  67. /**
  68. * Number of files/folder in zip file
  69. *
  70. * @var int
  71. */
  72. public $entries = 0;
  73. /**
  74. * Number of files in zip
  75. *
  76. * @var int
  77. */
  78. public $file_num = 0;
  79. /**
  80. * relative offset of local header
  81. *
  82. * @var int
  83. */
  84. public $offset = 0;
  85. /**
  86. * Reference to time at init
  87. *
  88. * @var int
  89. */
  90. public $now;
  91. /**
  92. * The level of compression
  93. *
  94. * Ranges from 0 to 9, with 9 being the highest level.
  95. *
  96. * @var int
  97. */
  98. public $compression_level = 2;
  99. /**
  100. * Initialize zip compression class
  101. *
  102. * @return void
  103. */
  104. public function __construct()
  105. {
  106. $this->now = time();
  107. log_message('info', 'Zip Compression Class Initialized');
  108. }
  109. // --------------------------------------------------------------------
  110. /**
  111. * Add Directory
  112. *
  113. * Lets you add a virtual directory into which you can place files.
  114. *
  115. * @param mixed $directory the directory name. Can be string or array
  116. * @return void
  117. */
  118. public function add_dir($directory)
  119. {
  120. foreach ((array) $directory as $dir)
  121. {
  122. if ( ! preg_match('|.+/$|', $dir))
  123. {
  124. $dir .= '/';
  125. }
  126. $dir_time = $this->_get_mod_time($dir);
  127. $this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']);
  128. }
  129. }
  130. // --------------------------------------------------------------------
  131. /**
  132. * Get file/directory modification time
  133. *
  134. * If this is a newly created file/dir, we will set the time to 'now'
  135. *
  136. * @param string $dir path to file
  137. * @return array filemtime/filemdate
  138. */
  139. protected function _get_mod_time($dir)
  140. {
  141. // filemtime() may return false, but raises an error for non-existing files
  142. $date = file_exists($dir) ? getdate(filemtime($dir)) : getdate($this->now);
  143. return array(
  144. 'file_mtime' => ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2,
  145. 'file_mdate' => (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday']
  146. );
  147. }
  148. // --------------------------------------------------------------------
  149. /**
  150. * Add Directory
  151. *
  152. * @param string $dir the directory name
  153. * @param int $file_mtime
  154. * @param int $file_mdate
  155. * @return void
  156. */
  157. protected function _add_dir($dir, $file_mtime, $file_mdate)
  158. {
  159. $dir = str_replace('\\', '/', $dir);
  160. $this->zipdata .=
  161. "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00"
  162. .pack('v', $file_mtime)
  163. .pack('v', $file_mdate)
  164. .pack('V', 0) // crc32
  165. .pack('V', 0) // compressed filesize
  166. .pack('V', 0) // uncompressed filesize
  167. .pack('v', strlen($dir)) // length of pathname
  168. .pack('v', 0) // extra field length
  169. .$dir
  170. // below is "data descriptor" segment
  171. .pack('V', 0) // crc32
  172. .pack('V', 0) // compressed filesize
  173. .pack('V', 0); // uncompressed filesize
  174. $this->directory .=
  175. "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00"
  176. .pack('v', $file_mtime)
  177. .pack('v', $file_mdate)
  178. .pack('V',0) // crc32
  179. .pack('V',0) // compressed filesize
  180. .pack('V',0) // uncompressed filesize
  181. .pack('v', strlen($dir)) // length of pathname
  182. .pack('v', 0) // extra field length
  183. .pack('v', 0) // file comment length
  184. .pack('v', 0) // disk number start
  185. .pack('v', 0) // internal file attributes
  186. .pack('V', 16) // external file attributes - 'directory' bit set
  187. .pack('V', $this->offset) // relative offset of local header
  188. .$dir;
  189. $this->offset = strlen($this->zipdata);
  190. $this->entries++;
  191. }
  192. // --------------------------------------------------------------------
  193. /**
  194. * Add Data to Zip
  195. *
  196. * Lets you add files to the archive. If the path is included
  197. * in the filename it will be placed within a directory. Make
  198. * sure you use add_dir() first to create the folder.
  199. *
  200. * @param mixed $filepath A single filepath or an array of file => data pairs
  201. * @param string $data Single file contents
  202. * @return void
  203. */
  204. public function add_data($filepath, $data = NULL)
  205. {
  206. if (is_array($filepath))
  207. {
  208. foreach ($filepath as $path => $data)
  209. {
  210. $file_data = $this->_get_mod_time($path);
  211. $this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']);
  212. }
  213. }
  214. else
  215. {
  216. $file_data = $this->_get_mod_time($filepath);
  217. $this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']);
  218. }
  219. }
  220. // --------------------------------------------------------------------
  221. /**
  222. * Add Data to Zip
  223. *
  224. * @param string $filepath the file name/path
  225. * @param string $data the data to be encoded
  226. * @param int $file_mtime
  227. * @param int $file_mdate
  228. * @return void
  229. */
  230. protected function _add_data($filepath, $data, $file_mtime, $file_mdate)
  231. {
  232. $filepath = str_replace('\\', '/', $filepath);
  233. $uncompressed_size = strlen($data);
  234. $crc32 = crc32($data);
  235. $gzdata = substr(gzcompress($data, $this->compression_level), 2, -4);
  236. $compressed_size = strlen($gzdata);
  237. $this->zipdata .=
  238. "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00"
  239. .pack('v', $file_mtime)
  240. .pack('v', $file_mdate)
  241. .pack('V', $crc32)
  242. .pack('V', $compressed_size)
  243. .pack('V', $uncompressed_size)
  244. .pack('v', strlen($filepath)) // length of filename
  245. .pack('v', 0) // extra field length
  246. .$filepath
  247. .$gzdata; // "file data" segment
  248. $this->directory .=
  249. "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00"
  250. .pack('v', $file_mtime)
  251. .pack('v', $file_mdate)
  252. .pack('V', $crc32)
  253. .pack('V', $compressed_size)
  254. .pack('V', $uncompressed_size)
  255. .pack('v', strlen($filepath)) // length of filename
  256. .pack('v', 0) // extra field length
  257. .pack('v', 0) // file comment length
  258. .pack('v', 0) // disk number start
  259. .pack('v', 0) // internal file attributes
  260. .pack('V', 32) // external file attributes - 'archive' bit set
  261. .pack('V', $this->offset) // relative offset of local header
  262. .$filepath;
  263. $this->offset = strlen($this->zipdata);
  264. $this->entries++;
  265. $this->file_num++;
  266. }
  267. // --------------------------------------------------------------------
  268. /**
  269. * Read the contents of a file and add it to the zip
  270. *
  271. * @param string $path
  272. * @param bool $archive_filepath
  273. * @return bool
  274. */
  275. public function read_file($path, $archive_filepath = FALSE)
  276. {
  277. if (file_exists($path) && FALSE !== ($data = file_get_contents($path)))
  278. {
  279. if (is_string($archive_filepath))
  280. {
  281. $name = str_replace('\\', '/', $archive_filepath);
  282. }
  283. else
  284. {
  285. $name = str_replace('\\', '/', $path);
  286. if ($archive_filepath === FALSE)
  287. {
  288. $name = preg_replace('|.*/(.+)|', '\\1', $name);
  289. }
  290. }
  291. $this->add_data($name, $data);
  292. return TRUE;
  293. }
  294. return FALSE;
  295. }
  296. // ------------------------------------------------------------------------
  297. /**
  298. * Read a directory and add it to the zip.
  299. *
  300. * This function recursively reads a folder and everything it contains (including
  301. * sub-folders) and creates a zip based on it. Whatever directory structure
  302. * is in the original file path will be recreated in the zip file.
  303. *
  304. * @param string $path path to source directory
  305. * @param bool $preserve_filepath
  306. * @param string $root_path
  307. * @return bool
  308. */
  309. public function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL)
  310. {
  311. $path = rtrim($path, '/\\').DIRECTORY_SEPARATOR;
  312. if ( ! $fp = @opendir($path))
  313. {
  314. return FALSE;
  315. }
  316. // Set the original directory root for child dir's to use as relative
  317. if ($root_path === NULL)
  318. {
  319. $root_path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, dirname($path)).DIRECTORY_SEPARATOR;
  320. }
  321. while (FALSE !== ($file = readdir($fp)))
  322. {
  323. if ($file[0] === '.')
  324. {
  325. continue;
  326. }
  327. if (is_dir($path.$file))
  328. {
  329. $this->read_dir($path.$file.DIRECTORY_SEPARATOR, $preserve_filepath, $root_path);
  330. }
  331. elseif (FALSE !== ($data = file_get_contents($path.$file)))
  332. {
  333. $name = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path);
  334. if ($preserve_filepath === FALSE)
  335. {
  336. $name = str_replace($root_path, '', $name);
  337. }
  338. $this->add_data($name.$file, $data);
  339. }
  340. }
  341. closedir($fp);
  342. return TRUE;
  343. }
  344. // --------------------------------------------------------------------
  345. /**
  346. * Get the Zip file
  347. *
  348. * @return string (binary encoded)
  349. */
  350. public function get_zip()
  351. {
  352. // Is there any data to return?
  353. if ($this->entries === 0)
  354. {
  355. return FALSE;
  356. }
  357. return $this->zipdata
  358. .$this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00"
  359. .pack('v', $this->entries) // total # of entries "on this disk"
  360. .pack('v', $this->entries) // total # of entries overall
  361. .pack('V', strlen($this->directory)) // size of central dir
  362. .pack('V', strlen($this->zipdata)) // offset to start of central dir
  363. ."\x00\x00"; // .zip file comment length
  364. }
  365. // --------------------------------------------------------------------
  366. /**
  367. * Write File to the specified directory
  368. *
  369. * Lets you write a file
  370. *
  371. * @param string $filepath the file name
  372. * @return bool
  373. */
  374. public function archive($filepath)
  375. {
  376. if ( ! ($fp = @fopen($filepath, 'w+b')))
  377. {
  378. return FALSE;
  379. }
  380. flock($fp, LOCK_EX);
  381. for ($result = $written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result)
  382. {
  383. if (($result = fwrite($fp, substr($data, $written))) === FALSE)
  384. {
  385. break;
  386. }
  387. }
  388. flock($fp, LOCK_UN);
  389. fclose($fp);
  390. return is_int($result);
  391. }
  392. // --------------------------------------------------------------------
  393. /**
  394. * Download
  395. *
  396. * @param string $filename the file name
  397. * @return void
  398. */
  399. public function download($filename = 'backup.zip')
  400. {
  401. if ( ! preg_match('|.+?\.zip$|', $filename))
  402. {
  403. $filename .= '.zip';
  404. }
  405. get_instance()->load->helper('download');
  406. $get_zip = $this->get_zip();
  407. $zip_content =& $get_zip;
  408. force_download($filename, $zip_content);
  409. }
  410. // --------------------------------------------------------------------
  411. /**
  412. * Initialize Data
  413. *
  414. * Lets you clear current zip data. Useful if you need to create
  415. * multiple zips with different data.
  416. *
  417. * @return CI_Zip
  418. */
  419. public function clear_data()
  420. {
  421. $this->zipdata = '';
  422. $this->directory = '';
  423. $this->entries = 0;
  424. $this->file_num = 0;
  425. $this->offset = 0;
  426. return $this;
  427. }
  428. }