Rollback.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. /**
  3. * Copyright © 2013-2017 Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Update;
  7. use Magento\Update\Backup\BackupInfo;
  8. use Magento\Update\ExcludeFilter;
  9. /**
  10. * Class for rollback capabilities
  11. */
  12. class Rollback
  13. {
  14. /**
  15. * @var string
  16. */
  17. protected $backupFileDir;
  18. /**
  19. * @var string
  20. */
  21. protected $restoreTargetDir;
  22. /**
  23. * @var Status
  24. */
  25. protected $status;
  26. /**
  27. * Initialize rollback.
  28. *
  29. * @param string|null $backupFileDir
  30. * @param string|null $restoreTargetDir
  31. * @param Status|null $status
  32. * @param BackupInfo|null $backupInfo
  33. */
  34. public function __construct(
  35. $backupFileDir = null,
  36. $restoreTargetDir = null,
  37. Status $status = null,
  38. BackupInfo $backupInfo = null
  39. ) {
  40. $this->backupFileDir = $backupFileDir ? $backupFileDir : BACKUP_DIR;
  41. $this->restoreTargetDir = $restoreTargetDir ? $restoreTargetDir : MAGENTO_BP;
  42. $this->status = $status ? $status : new Status();
  43. $this->backupInfo = $backupInfo ? $backupInfo : new BackupInfo();
  44. }
  45. /**
  46. * Restore Magento code from the backup archive.
  47. *
  48. * Rollback to the code/media version stored in the specified backup archive.
  49. *
  50. * @param string $backupFilePath
  51. * @return void
  52. */
  53. public function execute($backupFilePath)
  54. {
  55. $this->status->add(sprintf('Restoring archive from "%s" ...', $backupFilePath), \Psr\Log\LogLevel::INFO);
  56. $this->unzipArchive($backupFilePath);
  57. }
  58. /**
  59. * Unzip specified archive
  60. *
  61. * @param string $backupFilePath
  62. * @throws \RuntimeException
  63. * @return $this
  64. */
  65. private function unzipArchive($backupFilePath)
  66. {
  67. $phar = new \PharData($backupFilePath);
  68. $tarFile = str_replace('.tgz', '.tar', $backupFilePath);
  69. if (@file_exists($tarFile)) {
  70. @unlink($tarFile);
  71. }
  72. $phar->decompress();
  73. $tar = new \PharData($tarFile);
  74. if (strpos($backupFilePath, BackupInfo::BACKUP_MEDIA) > 0 ) {
  75. $this->deleteDirectory($this->restoreTargetDir . '/pub/media');
  76. } elseif (strpos($backupFilePath, BackupInfo::BACKUP_CODE) > 0 ) {
  77. $blackListFolders = $this->backupInfo->getBlacklist();
  78. $exclusions = [];
  79. foreach ($blackListFolders as $blackListFolder) {
  80. $exclusions[] = $this->restoreTargetDir . '/' . $blackListFolder;
  81. }
  82. try {
  83. $this->deleteDirectory($this->restoreTargetDir, $exclusions);
  84. } catch (\Exception $e) {
  85. $this->status->setUpdateError();
  86. $this->status->add('Error during rollback ' . $e->getMessage(), \Psr\Log\LogLevel::ERROR);
  87. }
  88. } else {
  89. $this->status->setUpdateError();
  90. $this->status->add('Invalid backup type', \Psr\Log\LogLevel::INFO);
  91. }
  92. $tar->extractTo($this->restoreTargetDir , null, true);
  93. @unlink($tarFile);
  94. //TODO Temporary solution, can be removed when MAGETWO-38589 is fixed.
  95. if (strpos($backupFilePath, BackupInfo::BACKUP_MEDIA) > 0 ) {
  96. $iterator = new \RecursiveIteratorIterator(
  97. new \RecursiveDirectoryIterator($this->restoreTargetDir . '/pub/media'),
  98. \RecursiveIteratorIterator::SELF_FIRST
  99. );
  100. foreach($iterator as $item) {
  101. @chmod($item, 0777);
  102. }
  103. } elseif (strpos($backupFilePath, BackupInfo::BACKUP_CODE) > 0 ) {
  104. $iterator = new \RecursiveIteratorIterator(
  105. new \RecursiveDirectoryIterator($this->restoreTargetDir),
  106. \RecursiveIteratorIterator::SELF_FIRST
  107. );
  108. foreach($iterator as $item) {
  109. @chmod($item, 0755);
  110. }
  111. $writeAccessFolders = ['/pub/media', '/pub/static', '/var'];
  112. foreach ($writeAccessFolders as $folder) {
  113. if (file_exists($this->restoreTargetDir . $folder)) {
  114. $iterator = new \RecursiveIteratorIterator(
  115. new \RecursiveDirectoryIterator($this->restoreTargetDir . $folder),
  116. \RecursiveIteratorIterator::SELF_FIRST
  117. );
  118. foreach($iterator as $item) {
  119. @chmod($item, 0777);
  120. }
  121. }
  122. }
  123. }
  124. //TODO Till here
  125. }
  126. /**
  127. * Recursively remove files and directories
  128. *
  129. * @param string $dir
  130. * @param array $exclude
  131. * @return bool
  132. */
  133. private function deleteDirectory($dir, $exclude = []) {
  134. $filesystemIterator = new \RecursiveIteratorIterator(
  135. new \RecursiveDirectoryIterator($dir),
  136. \RecursiveIteratorIterator::CHILD_FIRST
  137. );
  138. $iterator = new ExcludeFilter($filesystemIterator, $exclude);
  139. foreach ($iterator as $item) {
  140. $itemToBeDeleted = $item->__toString();
  141. if ($item->isDir()) {
  142. rmdir($itemToBeDeleted);
  143. } else {
  144. unlink($itemToBeDeleted);
  145. }
  146. }
  147. // If $dir is empty with no child items, iterator will not be valid.
  148. // See http://php.net/manual/en/directoryiterator.valid.php
  149. if (is_dir($dir) && !(new \FilesystemIterator($dir))->valid()) {
  150. rmdir($dir);
  151. }
  152. }
  153. }