/lib/internal/Magento/Framework/Backup/Filesystem.php

https://gitlab.com/AlexandrSy/magento.xxx · PHP · 302 lines · 145 code · 41 blank · 116 comment · 13 complexity · 47cd5c9bb7170c5603b2eb7696ed940a MD5 · raw file

  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. // @codingStandardsIgnoreFile
  7. namespace Magento\Framework\Backup;
  8. use Magento\Framework\Filesystem\DriverInterface;
  9. /**
  10. * Class to work with filesystem backups
  11. *
  12. * @author Magento Core Team <core@magentocommerce.com>
  13. */
  14. class Filesystem extends AbstractBackup
  15. {
  16. /**
  17. * Paths that ignored when creating or rolling back snapshot
  18. *
  19. * @var array
  20. */
  21. protected $_ignorePaths = [];
  22. /**
  23. * Whether use ftp account for rollback procedure
  24. *
  25. * @var bool
  26. */
  27. protected $_useFtp = false;
  28. /**
  29. * Ftp host
  30. *
  31. * @var string
  32. */
  33. protected $_ftpHost;
  34. /**
  35. * Ftp username
  36. *
  37. * @var string
  38. */
  39. protected $_ftpUser;
  40. /**
  41. * Password to ftp account
  42. *
  43. * @var string
  44. */
  45. protected $_ftpPass;
  46. /**
  47. * Ftp path to Magento installation
  48. *
  49. * @var string
  50. */
  51. protected $_ftpPath;
  52. /**
  53. * Implementation Rollback functionality for Filesystem
  54. *
  55. * @throws \Magento\Framework\Exception\LocalizedException
  56. * @return bool
  57. */
  58. public function rollback()
  59. {
  60. $this->_lastOperationSucceed = false;
  61. set_time_limit(0);
  62. ignore_user_abort(true);
  63. $rollbackWorker = $this->_useFtp ? new \Magento\Framework\Backup\Filesystem\Rollback\Ftp(
  64. $this
  65. ) : new \Magento\Framework\Backup\Filesystem\Rollback\Fs(
  66. $this
  67. );
  68. $rollbackWorker->run();
  69. $this->_lastOperationSucceed = true;
  70. return $this->_lastOperationSucceed;
  71. }
  72. /**
  73. * Implementation Create Backup functionality for Filesystem
  74. *
  75. * @throws \Magento\Framework\Exception\LocalizedException
  76. * @return boolean
  77. */
  78. public function create()
  79. {
  80. set_time_limit(0);
  81. ignore_user_abort(true);
  82. $this->_lastOperationSucceed = false;
  83. $this->_checkBackupsDir();
  84. $fsHelper = new \Magento\Framework\Backup\Filesystem\Helper();
  85. $filesInfo = $fsHelper->getInfo(
  86. $this->getRootDir(),
  87. \Magento\Framework\Backup\Filesystem\Helper::INFO_READABLE | \Magento\Framework\Backup\Filesystem\Helper::INFO_SIZE,
  88. $this->getIgnorePaths()
  89. );
  90. if (!$filesInfo['readable']) {
  91. throw new \Magento\Framework\Backup\Exception\NotEnoughPermissions(
  92. new \Magento\Framework\Phrase('Not enough permissions to read files for backup')
  93. );
  94. }
  95. $this->validateAvailableDiscSpace($this->getBackupsDir(), $filesInfo['size']);
  96. $tarTmpPath = $this->_getTarTmpPath();
  97. $tarPacker = new \Magento\Framework\Backup\Archive\Tar();
  98. $tarPacker->setSkipFiles($this->getIgnorePaths())->pack($this->getRootDir(), $tarTmpPath, true);
  99. if (!is_file($tarTmpPath) || filesize($tarTmpPath) == 0) {
  100. throw new \Magento\Framework\Exception\LocalizedException(
  101. new \Magento\Framework\Phrase('Failed to create backup')
  102. );
  103. }
  104. $backupPath = $this->getBackupPath();
  105. $gzPacker = new \Magento\Framework\Archive\Gz();
  106. $gzPacker->pack($tarTmpPath, $backupPath);
  107. if (!is_file($backupPath) || filesize($backupPath) == 0) {
  108. throw new \Magento\Framework\Exception\LocalizedException(
  109. new \Magento\Framework\Phrase('Failed to create backup')
  110. );
  111. }
  112. @unlink($tarTmpPath);
  113. $this->_lastOperationSucceed = true;
  114. return $this->_lastOperationSucceed;
  115. }
  116. /**
  117. * Validate if disk space is available for creating backup
  118. *
  119. * @param string $backupDir
  120. * @param int $size
  121. * @return void
  122. * @throws \Magento\Framework\Exception\LocalizedException
  123. */
  124. public function validateAvailableDiscSpace($backupDir, $size)
  125. {
  126. $freeSpace = disk_free_space($backupDir);
  127. $requiredSpace = 2 * $size;
  128. if ($requiredSpace > $freeSpace) {
  129. throw new \Magento\Framework\Backup\Exception\NotEnoughFreeSpace(
  130. new \Magento\Framework\Phrase(
  131. 'Warning: necessary space for backup is ' . (ceil($requiredSpace)/1024)
  132. . 'MB, but your free disc space is ' . (ceil($freeSpace)/1024) . 'MB.'
  133. )
  134. );
  135. }
  136. }
  137. /**
  138. * Force class to use ftp for rollback procedure
  139. *
  140. * @param string $host
  141. * @param string $username
  142. * @param string $password
  143. * @param string $path
  144. * @return $this
  145. */
  146. public function setUseFtp($host, $username, $password, $path)
  147. {
  148. $this->_useFtp = true;
  149. $this->_ftpHost = $host;
  150. $this->_ftpUser = $username;
  151. $this->_ftpPass = $password;
  152. $this->_ftpPath = $path;
  153. return $this;
  154. }
  155. /**
  156. * Get backup type
  157. *
  158. * @return string
  159. *
  160. * @see BackupInterface::getType()
  161. */
  162. public function getType()
  163. {
  164. return 'filesystem';
  165. }
  166. /**
  167. * Add path that should be ignoring when creating or rolling back backup
  168. *
  169. * @param string|array $paths
  170. * @return $this
  171. */
  172. public function addIgnorePaths($paths)
  173. {
  174. if (is_string($paths)) {
  175. if (!in_array($paths, $this->_ignorePaths)) {
  176. $this->_ignorePaths[] = $paths;
  177. }
  178. } elseif (is_array($paths)) {
  179. foreach ($paths as $path) {
  180. $this->addIgnorePaths($path);
  181. }
  182. }
  183. return $this;
  184. }
  185. /**
  186. * Get paths that should be ignored while creating or rolling back backup procedure
  187. *
  188. * @return array
  189. */
  190. public function getIgnorePaths()
  191. {
  192. return $this->_ignorePaths;
  193. }
  194. /**
  195. * Set directory where backups saved and add it to ignore paths
  196. *
  197. * @param string $backupsDir
  198. * @return $this
  199. *
  200. * @see AbstractBackup::setBackupsDir()
  201. */
  202. public function setBackupsDir($backupsDir)
  203. {
  204. parent::setBackupsDir($backupsDir);
  205. $this->addIgnorePaths($backupsDir);
  206. return $this;
  207. }
  208. /**
  209. * Getter for $_ftpPath variable
  210. *
  211. * @return string
  212. */
  213. public function getFtpPath()
  214. {
  215. return $this->_ftpPath;
  216. }
  217. /**
  218. * Get ftp connection string
  219. *
  220. * @return string
  221. */
  222. public function getFtpConnectString()
  223. {
  224. return 'ftp://' . $this->_ftpUser . ':' . $this->_ftpPass . '@' . $this->_ftpHost . $this->_ftpPath;
  225. }
  226. /**
  227. * Check backups directory existence and whether it's writeable
  228. *
  229. * @return void
  230. * @throws \Magento\Framework\Exception\LocalizedException
  231. */
  232. protected function _checkBackupsDir()
  233. {
  234. $backupsDir = $this->getBackupsDir();
  235. if (!is_dir($backupsDir)) {
  236. $backupsDirParentDirectory = basename($backupsDir);
  237. if (!is_writeable($backupsDirParentDirectory)) {
  238. throw new \Magento\Framework\Backup\Exception\NotEnoughPermissions(
  239. new \Magento\Framework\Phrase('Cant create backups directory')
  240. );
  241. }
  242. mkdir($backupsDir);
  243. chmod($backupsDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
  244. }
  245. if (!is_writable($backupsDir)) {
  246. throw new \Magento\Framework\Backup\Exception\NotEnoughPermissions(
  247. new \Magento\Framework\Phrase('Backups directory is not writeable')
  248. );
  249. }
  250. }
  251. /**
  252. * Generate tmp name for tarball
  253. *
  254. * @return string
  255. */
  256. protected function _getTarTmpPath()
  257. {
  258. $tmpName = '~tmp-' . microtime(true) . '.tar';
  259. return $this->getBackupsDir() . '/' . $tmpName;
  260. }
  261. }