Archive.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework;
  7. use Magento\Framework\Archive\Bz;
  8. use Magento\Framework\Archive\Gz;
  9. use Magento\Framework\Archive\Tar;
  10. /**
  11. * Class to work with archives
  12. *
  13. * @author Magento Core Team <core@magentocommerce.com>
  14. */
  15. class Archive
  16. {
  17. /**
  18. * Archiver is used for compress.
  19. */
  20. const DEFAULT_ARCHIVER = 'gz';
  21. /**
  22. * Default packer for directory.
  23. */
  24. const TAPE_ARCHIVER = 'tar';
  25. /**
  26. * Current archiver is used for compress.
  27. *
  28. * @var \Magento\Framework\Archive\Tar|\Magento\Framework\Archive\Gz|\Magento\Framework\Archive\Bz
  29. */
  30. protected $_archiver = null;
  31. /**
  32. * Accessible formats for compress.
  33. *
  34. * @var array
  35. */
  36. protected $_formats = [
  37. 'tar' => 'tar',
  38. 'gz' => 'gz',
  39. 'gzip' => 'gz',
  40. 'tgz' => 'tar.gz',
  41. 'tgzip' => 'tar.gz',
  42. 'bz' => 'bz',
  43. 'bzip' => 'bz',
  44. 'bzip2' => 'bz',
  45. 'bz2' => 'bz',
  46. 'tbz' => 'tar.bz',
  47. 'tbzip' => 'tar.bz',
  48. 'tbz2' => 'tar.bz',
  49. 'tbzip2' => 'tar.bz',
  50. ];
  51. /**
  52. * Create object of current archiver by $extension.
  53. *
  54. * @param string $extension
  55. * @return Tar|Gz|Bz
  56. */
  57. protected function _getArchiver($extension)
  58. {
  59. $extension = strtolower($extension);
  60. $format = isset($this->_formats[$extension]) ? $this->_formats[$extension] : self::DEFAULT_ARCHIVER;
  61. $class = '\\Magento\Framework\Archive\\' . ucfirst($format);
  62. $this->_archiver = new $class();
  63. return $this->_archiver;
  64. }
  65. /**
  66. * Split current format to list of archivers.
  67. *
  68. * @param string $source
  69. * @return string[]|string
  70. */
  71. protected function _getArchivers($source)
  72. {
  73. $ext = pathinfo($source, PATHINFO_EXTENSION);
  74. if (!empty($this->_formats[$ext])) {
  75. return explode('.', $this->_formats[$ext]);
  76. }
  77. return [];
  78. }
  79. /**
  80. * Pack file or directory to archivers are parsed from extension.
  81. *
  82. * @param string $source
  83. * @param string $destination
  84. * @param boolean $skipRoot skip first level parent
  85. * @return string Path to file
  86. */
  87. public function pack($source, $destination = 'packed.tgz', $skipRoot = false)
  88. {
  89. $archivers = $this->_getArchivers($destination);
  90. $interimSource = '';
  91. for ($i = 0, $count = count($archivers); $i < $count; $i++) {
  92. if ($i == $count - 1) {
  93. $packed = $destination;
  94. } else {
  95. $packed = dirname($destination) . '/~tmp-' . microtime(true) . $archivers[$i] . '.' . $archivers[$i];
  96. }
  97. $source = $this->_getArchiver($archivers[$i])->pack($source, $packed, $skipRoot);
  98. if ($interimSource && $i < $count) {
  99. unlink($interimSource);
  100. }
  101. $interimSource = $source;
  102. }
  103. return $source;
  104. }
  105. /**
  106. * Unpack file from archivers are parsed from extension.
  107. * If $tillTar == true unpack file from archivers till
  108. * meet TAR archiver.
  109. *
  110. * @param string $source
  111. * @param string $destination
  112. * @param bool $tillTar
  113. * @param bool $clearInterm
  114. * @return string Path to file
  115. */
  116. public function unpack($source, $destination = '.', $tillTar = false, $clearInterm = true)
  117. {
  118. $archivers = $this->_getArchivers($source);
  119. $interimSource = '';
  120. for ($i = count($archivers) - 1; $i >= 0; $i--) {
  121. if ($tillTar && $archivers[$i] == self::TAPE_ARCHIVER) {
  122. break;
  123. }
  124. if ($i == 0) {
  125. $packed = rtrim($destination, '/') . '/';
  126. } else {
  127. $packed = rtrim(
  128. $destination,
  129. '/'
  130. ) . '/~tmp-' . microtime(
  131. true
  132. ) . $archivers[$i - 1] . '.' . $archivers[$i - 1];
  133. }
  134. $source = $this->_getArchiver($archivers[$i])->unpack($source, $packed);
  135. if ($clearInterm && $interimSource && $i >= 0) {
  136. unlink($interimSource);
  137. }
  138. $interimSource = $source;
  139. }
  140. return $source;
  141. }
  142. /**
  143. * Extract one file from TAR (Tape Archiver).
  144. *
  145. * @param string $file
  146. * @param string $source
  147. * @param string $destination
  148. * @return string Path to file
  149. */
  150. public function extract($file, $source, $destination = '.')
  151. {
  152. $tarFile = $this->unpack($source, $destination, true);
  153. $resFile = $this->_getArchiver(self::TAPE_ARCHIVER)->extract($file, $tarFile, $destination);
  154. if (!$this->isTar($source)) {
  155. unlink($tarFile);
  156. }
  157. return $resFile;
  158. }
  159. /**
  160. * Check file is archive.
  161. *
  162. * @param string $file
  163. * @return boolean
  164. */
  165. public function isArchive($file)
  166. {
  167. $archivers = $this->_getArchivers($file);
  168. if (count($archivers)) {
  169. return true;
  170. }
  171. return false;
  172. }
  173. /**
  174. * Check file is TAR.
  175. *
  176. * @param string $file
  177. * @return boolean
  178. */
  179. public function isTar($file)
  180. {
  181. $archivers = $this->_getArchivers($file);
  182. if (count($archivers) == 1 && $archivers[0] == self::TAPE_ARCHIVER) {
  183. return true;
  184. }
  185. return false;
  186. }
  187. }