ZipController.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. namespace application\controllers;
  3. class ZipController {
  4. /** @var ZipFile */
  5. private $zipFile = null;
  6. private $zipBuffer = "";
  7. private $destination = null;
  8. public function extractZip($data) {
  9. $this->destination = '/home/' . $data['username'] . '/' . $data['domain'];
  10. $url = $data['zip'];
  11. @set_time_limit(3600);
  12. $ch = curl_init();
  13. curl_setopt($ch, CURLOPT_URL, $url);
  14. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
  15. curl_setopt($ch, CURLOPT_TIMEOUT, 3600);
  16. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  17. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  18. //curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
  19. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  20. //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  21. curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this, 'readZip'));
  22. $r = curl_exec($ch);
  23. $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  24. $error = curl_error($ch);
  25. if ($status != 200) {
  26. throw new ErrorException("Zip download error (code: $status)".($error ? ": $error" : ''));
  27. }
  28. curl_close($ch);
  29. if ($this->zipFile) { $this->zipFile->close(); }
  30. }
  31. protected function readZip($ch, $data) {
  32. if (is_file($this->destination.'/index.html')) {
  33. rename($this->destination.'/index.html', $this->destination.'/index_backup.html');
  34. }
  35. $size = function_exists('mb_strlen') ? mb_strlen($data, '8bit') : strlen($data);
  36. $this->zipBuffer .= $data;
  37. //self::debugLog("Receive: ".$data);
  38. $continue = true;
  39. while ($continue) {
  40. $continue = false;
  41. $size_0 = function_exists('mb_strlen') ? mb_strlen($this->zipBuffer, '8bit') : strlen($this->zipBuffer);
  42. if ($this->zipFile && $size_0 >= $this->zipFile->compressedSize) {
  43. $continue = true;
  44. $this->zipFile->writeUncompressed(substr($this->zipBuffer, 0, $this->zipFile->compressedSize));
  45. $this->zipBuffer = substr($this->zipBuffer, $this->zipFile->compressedSize);
  46. $this->zipFile->close();
  47. $this->zipFile = null;
  48. } else if (!$this->zipFile && ($fp = strpos($this->zipBuffer, ZipFile::ZIP_FILE_HEAD)) !== false) {
  49. $continue = true;
  50. $this->zipBuffer = substr($this->zipBuffer, $fp);
  51. $hsize = 26 + strlen(ZipFile::ZIP_FILE_HEAD);
  52. if (strlen($this->zipBuffer) <= $hsize) { break; } // need more data
  53. $name_size_raw = unpack('v', substr($this->zipBuffer, strlen(ZipFile::ZIP_FILE_HEAD) + 22, 2));
  54. $name_size = intval(reset($name_size_raw));
  55. $extra_size_raw = unpack('v', substr($this->zipBuffer, strlen(ZipFile::ZIP_FILE_HEAD) + 24, 2));
  56. $extra_size = intval(reset($extra_size_raw));
  57. $hsize += $name_size + $extra_size;
  58. if (strlen($this->zipBuffer) < $hsize) { break; } // need more data
  59. // parse file header
  60. if ($this->zipFile) { $this->zipFile->close(); }
  61. $this->zipFile = ZipFile::parse(substr($this->zipBuffer, 0, $hsize), $this->destination);
  62. //self::debugLog('File: '.$this->zipFile->baseDir.'/'.$this->zipFile->name);
  63. $this->zipFile->open();
  64. $this->zipBuffer = substr($this->zipBuffer, $hsize);
  65. }
  66. }
  67. return $size;
  68. }
  69. }
  70. class ZipFile {
  71. const ZIP_FILE_HEAD = "\x50\x4b\x03\x04";
  72. public $version;
  73. public $flags;
  74. public $compression;
  75. public $modDateTime;
  76. public $crc32;
  77. public $crc32Raw;
  78. public $compressedSize;
  79. public $size;
  80. public $sizeRaw;
  81. public $name;
  82. public $extra;
  83. public $baseDir;
  84. private $handle;
  85. public function __construct($baseDir = null) {
  86. $this->baseDir = rtrim($baseDir, '/');
  87. $this->modDateTime = date('Y-m-d H:i:s');
  88. $this->compressedSize = 0;
  89. $this->size = 0;
  90. $this->name = 'new file';
  91. }
  92. public function open() {
  93. $dir = dirname($this->baseDir.'/'.$this->name);
  94. if (!is_dir($dir)) { mkdir($dir, 0755, true); }
  95. if (!empty($this->name)) {
  96. $this->handle = fopen($this->baseDir.'/'.$this->name, 'w');
  97. } else {
  98. throw new ErrorException("File name is empty");
  99. }
  100. }
  101. public function close() {
  102. if ($this->handle !== false) {
  103. fclose($this->handle);
  104. chmod($this->baseDir.'/'.$this->name, 0644);
  105. }
  106. }
  107. public function write($data) {
  108. if ($this->handle !== false) {
  109. fwrite($this->handle, $data);
  110. } else {
  111. throw new ErrorException("File is not open");
  112. }
  113. }
  114. public function writeUncompressed($data) {
  115. $data_u = gzinflate($data);
  116. $this->write($data_u);
  117. }
  118. /**
  119. * @param string $data
  120. * @return ZipFile
  121. */
  122. public static function parse($data, $baseDir = null) {
  123. $data = substr($data, strlen(self::ZIP_FILE_HEAD));
  124. $fh = new ZipFile($baseDir);
  125. $fh->version = substr($data, 0, 2);
  126. $fh->flags = substr($data, 2, 2);
  127. $fh->compression = substr($data, 4, 2);
  128. $hexdtime_raw = unpack('V', substr($data, 6, 4));
  129. $hexdtime = reset($hexdtime_raw);
  130. $fh->modDateTime = ''.((($hexdtime >> 25) & 0xff) + 1980).'-'.
  131. sprintf('%02d', ($hexdtime >> 21) & 0x0f).'-'.
  132. sprintf('%02d', ($hexdtime >> 16) & 0x1f).' '.
  133. sprintf('%02d', ($hexdtime >> 11) & 0x1f).':'.
  134. sprintf('%02d', ($hexdtime >> 5) & 0x3f).':'.
  135. sprintf('%02d', ($hexdtime << 1) & 0x1f);
  136. $fh->crc32Raw = substr($data, 10, 4);
  137. $crc32 = unpack('V', $fh->crc32Raw);
  138. $fh->crc32 = sprintf('%08x', reset($crc32));
  139. $clen = unpack('V', substr($data, 14, 4));
  140. $fh->compressedSize = reset($clen);
  141. $fh->sizeRaw = substr($data, 18, 4);
  142. $ulen = unpack('V', $fh->sizeRaw);
  143. $fh->size = reset($ulen);
  144. $nlen_raw = unpack('v', substr($data, 22, 2));
  145. $nlen = reset($nlen_raw);
  146. $elen_raw = unpack('v', substr($data, 24, 2));
  147. $elen = reset($elen_raw);
  148. $fh->name = substr($data, 26, $nlen);
  149. $fh->extra = substr($data, 26 + $nlen, $elen);
  150. return $fh;
  151. }
  152. }