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

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