vendor/shopware/core/Framework/Update/Services/UpdateHtaccess.php line 41

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Update\Services;
  3. use Shopware\Core\Framework\Log\Package;
  4. use Shopware\Core\Framework\Update\Event\UpdatePostFinishEvent;
  5. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  6. /**
  7. * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  8. */
  9. #[Package('system-settings')]
  10. class UpdateHtaccess implements EventSubscriberInterface
  11. {
  12. private const MARKER_START = '# BEGIN Shopware';
  13. private const MARKER_STOP = '# END Shopware';
  14. private const INSTRUCTIONS = '# The directives (lines) between "# BEGIN Shopware" and "# END Shopware" are dynamically generated. Any changes to the directives between these markers will be overwritten.';
  15. private const OLD_FILES = [
  16. '9ab5be8c4bbff3490f3ae367af8a30d7', // https://github.com/shopware/production/commit/bebf9adc90bf5d7b0d53a149cc5bdba328696086
  17. 'ba812f2a64b337b032b10685ca6e2308', // https://github.com/shopware/production/commit/18ce6ffc904b8d2d237dc4ee6654c1fa9a6df719
  18. ];
  19. private string $htaccessPath;
  20. /**
  21. * @internal
  22. */
  23. public function __construct(string $htaccessPath)
  24. {
  25. $this->htaccessPath = $htaccessPath;
  26. }
  27. public static function getSubscribedEvents(): array
  28. {
  29. return [
  30. UpdatePostFinishEvent::class => 'update',
  31. ];
  32. }
  33. public function update(): void
  34. {
  35. if (!file_exists($this->htaccessPath) || !file_exists($this->htaccessPath . '.dist')) {
  36. return;
  37. }
  38. if (\in_array(md5_file($this->htaccessPath), self::OLD_FILES, true)) {
  39. $this->replaceFile($this->htaccessPath);
  40. return;
  41. }
  42. $content = file_get_contents($this->htaccessPath);
  43. // User has deleted the markers. So we will ignore the update process
  44. if (!$content || strpos($content, self::MARKER_START) === false || strpos($content, self::MARKER_STOP) === false) {
  45. return;
  46. }
  47. $this->updateByMarkers($this->htaccessPath);
  48. }
  49. /**
  50. * Replace entire .htaccess from dist
  51. */
  52. private function replaceFile(string $path): void
  53. {
  54. $dist = $path . '.dist';
  55. if (!file_exists($dist)) {
  56. return;
  57. }
  58. $perms = fileperms($dist);
  59. copy($dist, $path);
  60. if ($perms) {
  61. chmod($path, $perms | 0644);
  62. }
  63. }
  64. private function updateByMarkers(string $path): void
  65. {
  66. [$pre, $_, $post] = $this->getLinesFromMarkedFile($path);
  67. [$_, $existing, $_] = $this->getLinesFromMarkedFile($path . '.dist');
  68. if (!\in_array(self::INSTRUCTIONS, $existing, true)) {
  69. array_unshift($existing, self::INSTRUCTIONS);
  70. }
  71. array_unshift($existing, self::MARKER_START);
  72. $existing[] = self::MARKER_STOP;
  73. $newFile = implode("\n", array_merge($pre, $existing, $post));
  74. $perms = fileperms($path);
  75. file_put_contents($path, $newFile);
  76. if ($perms) {
  77. chmod($path, $perms | 0644);
  78. }
  79. }
  80. /**
  81. * @return array{0: list<string>, 1: list<string>, 2: list<string>}
  82. */
  83. private function getLinesFromMarkedFile(string $path): array
  84. {
  85. $fp = fopen($path, 'rb+');
  86. if (!$fp) {
  87. return [[], [], []];
  88. }
  89. $lines = [];
  90. while (!feof($fp)) {
  91. if ($line = fgets($fp)) {
  92. $lines[] = rtrim($line, "\r\n");
  93. }
  94. }
  95. $foundStart = false;
  96. $foundStop = false;
  97. $preLines = [];
  98. $postLines = [];
  99. $existingLines = [];
  100. foreach ($lines as $line) {
  101. if (!$foundStart && strpos($line, self::MARKER_START) === 0) {
  102. $foundStart = true;
  103. continue;
  104. }
  105. if (!$foundStop && strpos($line, self::MARKER_STOP) === 0) {
  106. $foundStop = true;
  107. continue;
  108. }
  109. if (!$foundStart) {
  110. $preLines[] = $line;
  111. } elseif ($foundStop) {
  112. $postLines[] = $line;
  113. } else {
  114. $existingLines[] = $line;
  115. }
  116. }
  117. return [$preLines, $existingLines, $postLines];
  118. }
  119. }