国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

506 lines
19KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. /**
  4. * Zip压缩类
  5. *
  6. * @version $id:zip.class.php 15:21 2010年7月5日 tianya $
  7. * @package DedeBIZ.Libraries
  8. * @copyright Copyright (c) 2022 DedeBIZ.COM
  9. * @license https://www.dedebiz.com/license
  10. * @link https://www.dedebiz.com
  11. */
  12. class zip
  13. {
  14. var $datasec, $ctrl_dir = array();
  15. var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
  16. var $old_offset = 0;
  17. var $dirs = array(".");
  18. /**
  19. * 获取zip文件中的文件列表
  20. *
  21. * @access public
  22. * @param string $zip_name zip文件名
  23. * @return array
  24. */
  25. function get_List($zip_name)
  26. {
  27. $ret = '';
  28. $zip = @fopen($zip_name, 'rb');
  29. if (!$zip) {
  30. return (0);
  31. }
  32. $centd = $this->ReadCentralDir($zip, $zip_name);
  33. @rewind($zip);
  34. @fseek($zip, $centd['offset']);
  35. for ($i = 0; $i < $centd['entries']; $i++) {
  36. $header = $this->ReadCentralFileHeaders($zip);
  37. $header['index'] = $i;
  38. $info['filename'] = $header['filename'];
  39. $info['stored_filename'] = $header['stored_filename'];
  40. $info['size'] = $header['size'];
  41. $info['compressed_size'] = $header['compressed_size'];
  42. $info['crc'] = strtoupper(dechex($header['crc']));
  43. $info['mtime'] = $header['mtime'];
  44. $info['comment'] = $header['comment'];
  45. $info['folder'] = ($header['external'] == 0x41FF0010 || $header['external'] == 16) ? 1 : 0;
  46. $info['index'] = $header['index'];
  47. $info['status'] = $header['status'];
  48. $ret[] = $info;
  49. unset($header);
  50. }
  51. return $ret;
  52. }
  53. /**
  54. * 增加文件到压缩文件
  55. *
  56. * @access public
  57. * @param string $files 需要增加的文件列表,可以是字符串也可以是数组
  58. * @param string $compact 压缩文件名称
  59. * @return array 压缩文件信息
  60. */
  61. function Add($files, $compact)
  62. {
  63. if (!is_array($files[0])) {
  64. $files = array($files);
  65. }
  66. for ($i = 0; $files[$i]; $i++) {
  67. $fn = $files[$i];
  68. if (!in_Array(dirname($fn[0]), $this->dirs)) {
  69. $this->add_Dir(dirname($fn[0]));
  70. }
  71. if (basename($fn[0])) {
  72. $ret[basename($fn[0])] = $this->add_File($fn[1], $fn[0], $compact);
  73. }
  74. }
  75. return $ret;
  76. }
  77. /**
  78. * 获取文件,获取后可以让其进行下载
  79. *
  80. * @access public
  81. * @return void
  82. */
  83. function get_file()
  84. {
  85. $data = implode('', $this->datasec);
  86. $ctrldir = implode('', $this->ctrl_dir);
  87. return $data.$ctrldir.$this->eof_ctrl_dir .
  88. pack('v', sizeof($this->ctrl_dir)).pack('v', sizeof($this->ctrl_dir)) .
  89. pack('V', strlen($ctrldir)).pack('V', strlen($data))."\x00\x00";
  90. }
  91. /**
  92. * 增加文件目录
  93. *
  94. * @access public
  95. * @param string $name 目录名称
  96. * @return void
  97. */
  98. function add_dir($name)
  99. {
  100. $name = str_replace("\\", "/", $name);
  101. $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  102. $fr .= pack("V", 0).pack("V", 0).pack("V", 0).pack("v", strlen($name));
  103. $fr .= pack("v", 0).$name.pack("V", 0).pack("V", 0).pack("V", 0);
  104. $this->datasec[] = $fr;
  105. $new_offset = strlen(implode("", $this->datasec));
  106. $cdrec = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  107. $cdrec .= pack("V", 0).pack("V", 0).pack("V", 0).pack("v", strlen($name));
  108. $cdrec .= pack("v", 0).pack("v", 0).pack("v", 0).pack("v", 0);
  109. $ext = "\xff\xff\xff\xff";
  110. $cdrec .= pack("V", 16).pack("V", $this->old_offset).$name;
  111. $this->ctrl_dir[] = $cdrec;
  112. $this->old_offset = $new_offset;
  113. $this->dirs[] = $name;
  114. }
  115. /**
  116. * 编译指定的文件为zip文件(filename可以为文件数组array、目录dir或单个文件file)
  117. *
  118. * @access public
  119. * @param string $filename 文件名称
  120. * @param string $tozipfilename 压缩文件名称
  121. * @param string $ftype 压缩类型
  122. * @return int 影响文件数
  123. */
  124. function CompileZipFile($filename, $tozipfilename, $ftype = 'dir')
  125. {
  126. if (@function_exists('gzcompress')) {
  127. if ($ftype == 'dir') {
  128. $filelist = $this->ListDirFiles($filename);
  129. } else if ($ftype == 'file') {
  130. $filelist[] = $filename;
  131. } else {
  132. $filelist = $filename;
  133. }
  134. $i = 0;
  135. if (count($filelist) > 0) {
  136. foreach ($filelist as $filename) {
  137. if (is_file($filename)) {
  138. $i++;
  139. $fd = fopen($filename, "r");
  140. if (filesize($filename) > 0) {
  141. $content = fread($fd, filesize($filename));
  142. } else {
  143. $content = ' ';
  144. }
  145. fclose($fd);
  146. //if (is_array($dir)) $filename = basename($filename);
  147. $this->add_File($content, $filename);
  148. }
  149. }
  150. $out = $this->get_file();
  151. $fp = fopen($tozipfilename, "w");
  152. fwrite($fp, $out, strlen($out));
  153. fclose($fp);
  154. }
  155. return $i;
  156. } else {
  157. return 0;
  158. }
  159. }
  160. /**
  161. * 读取某文件夹的所有文件
  162. *
  163. * @access public
  164. * @param string $dirname 目录名称
  165. * @return mix 如果失败则返回false
  166. */
  167. function ListDirFiles($dirname)
  168. {
  169. $files = array();
  170. if (is_dir($dirname)) {
  171. $fh = opendir($dirname);
  172. while (($file = readdir($fh)) !== false) {
  173. if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) {
  174. continue;
  175. }
  176. $filepath = $dirname.'/'.$file;
  177. if (is_dir($filepath)) {
  178. $files = array_merge($files, $this->ListDirFiles($filepath));
  179. } else {
  180. array_push($files, $filepath);
  181. }
  182. }
  183. closedir($fh);
  184. } else {
  185. $files = false;
  186. }
  187. return $files;
  188. }
  189. /**
  190. * 增加文件
  191. *
  192. * @access public
  193. * @param string $data 数据
  194. * @param string $name 名称
  195. * @param string $compact 压缩
  196. * @return string
  197. */
  198. function add_File($data, $name, $compact = 1)
  199. {
  200. $name = str_replace('\\', '/', $name);
  201. $dtime = dechex($this->DosTime());
  202. $hexdtime = '\x'.$dtime[6].$dtime[7].'\x'.$dtime[4].$dtime[5]
  203. .'\x'.$dtime[2].$dtime[3].'\x'.$dtime[0].$dtime[1];
  204. eval('$hexdtime = "'.$hexdtime.'";');
  205. if ($compact)
  206. $fr = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$hexdtime;
  207. else {
  208. $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00".$hexdtime;
  209. }
  210. $unc_len = strlen($data);
  211. $crc = crc32($data);
  212. if ($compact) {
  213. $zdata = gzcompress($data);
  214. $c_len = strlen($zdata);
  215. $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
  216. } else {
  217. $zdata = $data;
  218. }
  219. $c_len = strlen($zdata);
  220. $fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len);
  221. $fr .= pack('v', strlen($name)).pack('v', 0).$name.$zdata;
  222. $fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len);
  223. $this->datasec[] = $fr;
  224. $new_offset = strlen(implode('', $this->datasec));
  225. if ($compact) {
  226. $cdrec = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00";
  227. } else {
  228. $cdrec = "\x50\x4b\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00";
  229. }
  230. $cdrec .= $hexdtime.pack('V', $crc).pack('V', $c_len).pack('V', $unc_len);
  231. $cdrec .= pack('v', strlen($name)).pack('v', 0).pack('v', 0);
  232. $cdrec .= pack('v', 0).pack('v', 0).pack('V', 32);
  233. $cdrec .= pack('V', $this->old_offset);
  234. $this->old_offset = $new_offset;
  235. $cdrec .= $name;
  236. $this->ctrl_dir[] = $cdrec;
  237. return true;
  238. }
  239. /**
  240. * 返回时间
  241. *
  242. * @access public
  243. * @return int
  244. */
  245. function DosTime()
  246. {
  247. $timearray = getdate();
  248. if ($timearray['year'] < 1980) {
  249. $timearray['year'] = 1980;
  250. $timearray['mon'] = 1;
  251. $timearray['mday'] = 1;
  252. $timearray['hours'] = 0;
  253. $timearray['minutes'] = 0;
  254. $timearray['seconds'] = 0;
  255. }
  256. return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) |
  257. ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
  258. }
  259. /**
  260. * 解压整个压缩包
  261. * 直接用 Extract 会有路径问题,本函数先从列表中获得文件信息并创建好所有目录然后才运行 Extract
  262. *
  263. * @access public
  264. * @param string $zn zip文件名称
  265. * @param string $to 解压到的目录地址
  266. * @return string
  267. */
  268. function ExtractAll($zn, $to)
  269. {
  270. if (substr($to, -1) != "/") {
  271. $to .= "/";
  272. }
  273. $files = $this->get_List($zn);
  274. $cn = count($files);
  275. if (is_array($files)) {
  276. for ($i = 0; $i < $cn; $i++) {
  277. if ($files[$i]['folder'] == 1) {
  278. @mkdir($to.$files[$i]['filename'], $GLOBALS['cfg_dir_purview']);
  279. @chmod($to.$files[$i]['filename'], $GLOBALS['cfg_dir_purview']);
  280. }
  281. }
  282. }
  283. $this->Extract($zn, $to);
  284. }
  285. /**
  286. * 解压单个文件
  287. *
  288. * @access public
  289. * @param string $zn zip文件名称
  290. * @param string $to 解压到的目录地址
  291. * @return string
  292. */
  293. function Extract($zn, $to, $index = array(-1))
  294. {
  295. $ok = 0;
  296. $zip = @fopen($zn, 'rb');
  297. if (!$zip) {
  298. return (-1);
  299. }
  300. $cdir = $this->ReadCentralDir($zip, $zn);
  301. $pos_entry = $cdir['offset'];
  302. if (!is_array($index)) {
  303. $index = array($index);
  304. }
  305. for ($i = 0; isset($index[$i]); $i++) {
  306. if (intval($index[$i]) != $index[$i] || $index[$i] > $cdir['entries']) {
  307. return (-1);
  308. }
  309. }
  310. for ($i = 0; $i < $cdir['entries']; $i++) {
  311. @fseek($zip, $pos_entry);
  312. $header = $this->ReadCentralFileHeaders($zip);
  313. $header['index'] = $i;
  314. $pos_entry = ftell($zip);
  315. @rewind($zip);
  316. fseek($zip, $header['offset']);
  317. if (in_array("-1", $index) || in_array($i, $index)) {
  318. $stat[$header['filename']] = $this->ExtractFile($header, $to, $zip);
  319. }
  320. }
  321. fclose($zip);
  322. return $stat;
  323. }
  324. function ReadFileHeader($zip)
  325. {
  326. $binary_data = fread($zip, 30);
  327. $data = unpack('vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $binary_data);
  328. $header['filename'] = fread($zip, $data['filename_len']);
  329. if ($data['extra_len'] != 0) {
  330. $header['extra'] = fread($zip, $data['extra_len']);
  331. } else {
  332. $header['extra'] = '';
  333. }
  334. $header['compression'] = $data['compression'];
  335. $header['size'] = $data['size'];
  336. $header['compressed_size'] = $data['compressed_size'];
  337. $header['crc'] = $data['crc'];
  338. $header['flag'] = $data['flag'];
  339. $header['mdate'] = $data['mdate'];
  340. $header['mtime'] = $data['mtime'];
  341. if ($header['mdate'] && $header['mtime']) {
  342. $hour = ($header['mtime'] & 0xF800) >> 11;
  343. $minute = ($header['mtime'] & 0x07E0) >> 5;
  344. $seconde = ($header['mtime'] & 0x001F) * 2;
  345. $year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
  346. $month = ($header['mdate'] & 0x01E0) >> 5;
  347. $day = $header['mdate'] & 0x001F;
  348. $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
  349. } else {
  350. $header['mtime'] = time();
  351. }
  352. $header['stored_filename'] = $header['filename'];
  353. $header['status'] = "ok";
  354. return $header;
  355. }
  356. function ReadCentralFileHeaders($zip)
  357. {
  358. $binary_data = fread($zip, 46);
  359. $header = unpack('vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $binary_data);
  360. if ($header['filename_len'] != 0) {
  361. $header['filename'] = fread($zip, $header['filename_len']);
  362. } else {
  363. $header['filename'] = '';
  364. }
  365. if ($header['extra_len'] != 0) {
  366. $header['extra'] = fread($zip, $header['extra_len']);
  367. } else {
  368. $header['extra'] = '';
  369. }
  370. if ($header['comment_len'] != 0) {
  371. $header['comment'] = fread($zip, $header['comment_len']);
  372. } else {
  373. $header['comment'] = '';
  374. }
  375. if ($header['mdate'] && $header['mtime']) {
  376. $hour = ($header['mtime'] & 0xF800) >> 11;
  377. $minute = ($header['mtime'] & 0x07E0) >> 5;
  378. $seconde = ($header['mtime'] & 0x001F) * 2;
  379. $year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
  380. $month = ($header['mdate'] & 0x01E0) >> 5;
  381. $day = $header['mdate'] & 0x001F;
  382. $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
  383. } else {
  384. $header['mtime'] = time();
  385. }
  386. $header['stored_filename'] = $header['filename'];
  387. $header['status'] = 'ok';
  388. if (substr($header['filename'], -1) == '/') {
  389. $header['external'] = 0x41FF0010;
  390. }
  391. return $header;
  392. }
  393. function ReadCentralDir($zip, $zip_name)
  394. {
  395. $size = filesize($zip_name);
  396. if ($size < 277) {
  397. $maximum_size = $size;
  398. } else {
  399. $maximum_size = 277;
  400. }
  401. @fseek($zip, $size - $maximum_size);
  402. $pos = ftell($zip);
  403. $bytes = 0x00000000;
  404. while ($pos < $size) {
  405. $byte = @fread($zip, 1);
  406. $bytes = ($bytes << 8) | Ord($byte);
  407. if ($bytes == 0x504b0506) {
  408. $pos++;
  409. break;
  410. }
  411. $pos++;
  412. }
  413. $data = @unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', fread($zip, 18));
  414. if ($data['comment_size'] != 0) {
  415. $centd['comment'] = fread($zip, $data['comment_size']);
  416. } else {
  417. $centd['comment'] = '';
  418. $centd['entries'] = $data['entries'];
  419. }
  420. $centd['disk_entries'] = $data['disk_entries'];
  421. $centd['offset'] = $data['offset'];
  422. $centd['disk_start'] = $data['disk_start'];
  423. $centd['size'] = $data['size'];
  424. $centd['disk'] = $data['disk'];
  425. return $centd;
  426. }
  427. function ExtractFile($header, $to, $zip)
  428. {
  429. $header = $this->readfileheader($zip);
  430. $header['external'] = (!isset($header['external']) ? 0 : $header['external']);
  431. if (substr($to, -1) != "/") {
  432. $to .= "/";
  433. }
  434. if (!@is_dir($to)) {
  435. @mkdir($to, $GLOBALS['cfg_dir_purview']);
  436. }
  437. if (!($header['external'] == 0x41FF0010) && !($header['external'] == 16)) {
  438. if ($header['compression'] == 0) {
  439. $fp = @fopen($to.$header['filename'], 'wb');
  440. if (!$fp) {
  441. return (-1);
  442. }
  443. $size = $header['compressed_size'];
  444. while ($size != 0) {
  445. $read_size = ($size < 2048 ? $size : 2048);
  446. $buffer = fread($zip, $read_size);
  447. $binary_data = pack('a'.$read_size, $buffer);
  448. @fwrite($fp, $binary_data, $read_size);
  449. $size -= $read_size;
  450. }
  451. fclose($fp);
  452. touch($to.$header['filename'], $header['mtime']);
  453. } else {
  454. $fp = @fopen($to.$header['filename'].'.gz', 'wb');
  455. if (!$fp) {
  456. return (-1);
  457. }
  458. $binary_data = pack(
  459. 'va1a1Va1a1',
  460. 0x8b1f,
  461. Chr($header['compression']),
  462. Chr(0x00),
  463. time(),
  464. Chr(0x00),
  465. Chr(3)
  466. );
  467. fwrite($fp, $binary_data, 10);
  468. $size = $header['compressed_size'];
  469. while ($size != 0) {
  470. $read_size = ($size < 1024 ? $size : 1024);
  471. $buffer = fread($zip, $read_size);
  472. $binary_data = pack('a'.$read_size, $buffer);
  473. @fwrite($fp, $binary_data, $read_size);
  474. $size -= $read_size;
  475. }
  476. $binary_data = pack('VV', $header['crc'], $header['size']);
  477. fwrite($fp, $binary_data, 8);
  478. fclose($fp);
  479. $gzp = @gzopen($to.$header['filename'].'.gz', 'rb') or die("Cette archive est compress");
  480. if (!$gzp) {
  481. return (-2);
  482. }
  483. $fp = @fopen($to.$header['filename'], 'wb');
  484. if (!$fp) {
  485. return (-1);
  486. }
  487. $size = $header['size'];
  488. while ($size != 0) {
  489. $read_size = ($size < 2048 ? $size : 2048);
  490. $buffer = gzread($gzp, $read_size);
  491. $binary_data = pack('a'.$read_size, $buffer);
  492. @fwrite($fp, $binary_data, $read_size);
  493. $size -= $read_size;
  494. }
  495. fclose($fp);
  496. gzclose($gzp);
  497. touch($to.$header['filename'], $header['mtime']);
  498. @unlink($to.$header['filename'].'.gz');
  499. }
  500. }
  501. return true;
  502. }
  503. }
  504. ?>