Ftp.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Backup\Filesystem\Rollback;
  7. use Magento\Framework\Backup\Exception\CantLoadSnapshot;
  8. use Magento\Framework\Backup\Exception\FtpConnectionFailed;
  9. use Magento\Framework\Backup\Exception\FtpValidationFailed;
  10. use Magento\Framework\Backup\Filesystem\Helper;
  11. use Magento\Framework\Exception\LocalizedException;
  12. use Magento\Framework\Phrase;
  13. /**
  14. * Rollback worker for rolling back via ftp
  15. *
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. */
  18. class Ftp extends AbstractRollback
  19. {
  20. /**
  21. * Ftp client
  22. *
  23. * @var \Magento\Framework\System\Ftp
  24. */
  25. protected $_ftpClient;
  26. /**
  27. * Files rollback implementation via ftp
  28. *
  29. * @return void
  30. * @throws LocalizedException
  31. *
  32. * @see AbstractRollback::run()
  33. */
  34. public function run()
  35. {
  36. $snapshotPath = $this->_snapshot->getBackupPath();
  37. if (!is_file($snapshotPath) || !is_readable($snapshotPath)) {
  38. throw new CantLoadSnapshot(
  39. new Phrase('Can\'t load snapshot archive')
  40. );
  41. }
  42. $this->_initFtpClient();
  43. $this->_validateFtp();
  44. $tmpDir = $this->_createTmpDir();
  45. $this->_unpackSnapshot($tmpDir);
  46. $fsHelper = new Helper();
  47. $this->_cleanupFtp();
  48. $this->_uploadBackupToFtp($tmpDir);
  49. if ($this->_snapshot->keepSourceFile() === false) {
  50. $fsHelper->rm($tmpDir, [], true);
  51. $this->_ftpClient->delete($snapshotPath);
  52. }
  53. }
  54. /**
  55. * Initialize ftp client and connect to ftp
  56. *
  57. * @return void
  58. * @throws FtpConnectionFailed
  59. */
  60. protected function _initFtpClient()
  61. {
  62. try {
  63. $this->_ftpClient = new \Magento\Framework\System\Ftp();
  64. $this->_ftpClient->connect($this->_snapshot->getFtpConnectString());
  65. } catch (\Exception $e) {
  66. throw new FtpConnectionFailed(
  67. new Phrase($e->getMessage())
  68. );
  69. }
  70. }
  71. /**
  72. * Perform ftp validation. Check whether ftp account provided points to current magento installation
  73. *
  74. * @return void
  75. * @throws LocalizedException
  76. */
  77. protected function _validateFtp()
  78. {
  79. $validationFilename = '~validation-' . microtime(true) . '.tmp';
  80. $validationFilePath = $this->_snapshot->getBackupsDir() . '/' . $validationFilename;
  81. $fh = @fopen($validationFilePath, 'w');
  82. @fclose($fh);
  83. if (!is_file($validationFilePath)) {
  84. throw new LocalizedException(
  85. new Phrase('Unable to validate ftp account')
  86. );
  87. }
  88. $rootDir = $this->_snapshot->getRootDir();
  89. $ftpPath = $this->_snapshot->getFtpPath() . '/' . str_replace($rootDir, '', $validationFilePath);
  90. $fileExistsOnFtp = $this->_ftpClient->fileExists($ftpPath);
  91. @unlink($validationFilePath);
  92. if (!$fileExistsOnFtp) {
  93. throw new FtpValidationFailed(
  94. new Phrase('Failed to validate ftp account')
  95. );
  96. }
  97. }
  98. /**
  99. * Unpack snapshot
  100. *
  101. * @param string $tmpDir
  102. * @return void
  103. */
  104. protected function _unpackSnapshot($tmpDir)
  105. {
  106. $snapshotPath = $this->_snapshot->getBackupPath();
  107. $archiver = new \Magento\Framework\Archive();
  108. $archiver->unpack($snapshotPath, $tmpDir);
  109. }
  110. /**
  111. * @return string
  112. * @throws LocalizedException
  113. */
  114. protected function _createTmpDir()
  115. {
  116. $tmpDir = $this->_snapshot->getBackupsDir() . '/~tmp-' . microtime(true);
  117. $result = @mkdir($tmpDir);
  118. if (false === $result) {
  119. throw new \Magento\Framework\Backup\Exception\NotEnoughPermissions(
  120. new Phrase('Failed to create directory %1', [$tmpDir])
  121. );
  122. }
  123. return $tmpDir;
  124. }
  125. /**
  126. * Delete magento and all files from ftp
  127. *
  128. * @return void
  129. */
  130. protected function _cleanupFtp()
  131. {
  132. $rootDir = $this->_snapshot->getRootDir();
  133. $filesystemIterator = new \RecursiveIteratorIterator(
  134. new \RecursiveDirectoryIterator($rootDir),
  135. \RecursiveIteratorIterator::CHILD_FIRST
  136. );
  137. $iterator = new \Magento\Framework\Backup\Filesystem\Iterator\Filter(
  138. $filesystemIterator,
  139. $this->_snapshot->getIgnorePaths()
  140. );
  141. foreach ($iterator as $item) {
  142. $ftpPath = $this->_snapshot->getFtpPath() . '/' . str_replace($rootDir, '', $item->__toString());
  143. $ftpPath = str_replace('\\', '/', $ftpPath);
  144. $this->_ftpClient->delete($ftpPath);
  145. }
  146. }
  147. /**
  148. * Perform files rollback
  149. *
  150. * @param string $tmpDir
  151. * @return void
  152. * @throws LocalizedException
  153. * @SuppressWarnings(PHPMD.UnusedLocalVariable)
  154. */
  155. protected function _uploadBackupToFtp($tmpDir)
  156. {
  157. $filesystemIterator = new \RecursiveIteratorIterator(
  158. new \RecursiveDirectoryIterator($tmpDir),
  159. \RecursiveIteratorIterator::SELF_FIRST
  160. );
  161. $iterator = new \Magento\Framework\Backup\Filesystem\Iterator\Filter(
  162. $filesystemIterator,
  163. $this->_snapshot->getIgnorePaths()
  164. );
  165. foreach ($filesystemIterator as $item) {
  166. $ftpPath = $this->_snapshot->getFtpPath() . '/' . str_replace($tmpDir, '', $item->__toString());
  167. $ftpPath = str_replace('\\', '/', $ftpPath);
  168. if ($item->isLink()) {
  169. continue;
  170. }
  171. if ($item->isDir()) {
  172. $this->_ftpClient->mkdirRecursive($ftpPath);
  173. } else {
  174. $result = $this->_ftpClient->put($ftpPath, $item->__toString());
  175. if (false === $result) {
  176. throw new \Magento\Framework\Backup\Exception\NotEnoughPermissions(
  177. new Phrase('Failed to upload file %1 to ftp', [$item->__toString()])
  178. );
  179. }
  180. }
  181. }
  182. }
  183. }