vendor/nelmio/security-bundle/src/EventListener/ClickjackingListener.php line 47

  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the Nelmio SecurityBundle.
  5.  *
  6.  * (c) Nelmio <hello@nelm.io>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Nelmio\SecurityBundle\EventListener;
  12. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. final class ClickjackingListener extends AbstractContentTypeRestrictableListener
  15. {
  16.     use KernelEventForwardCompatibilityTrait;
  17.     /**
  18.      * @var array<string, array<string, string>>
  19.      */
  20.     private array $paths;
  21.     private ?string $hosts;
  22.     /**
  23.      * @param array<string, array<string, string>> $paths
  24.      * @param list<string>                         $contentTypes
  25.      * @param list<string>                         $hosts
  26.      */
  27.     public function __construct(array $paths, array $contentTypes = [], array $hosts = [])
  28.     {
  29.         parent::__construct($contentTypes);
  30.         $this->paths $paths;
  31.         $this->hosts = [] !== $hosts '('.implode('|'$hosts).')' null;
  32.     }
  33.     public static function getSubscribedEvents(): array
  34.     {
  35.         return [KernelEvents::RESPONSE => 'onKernelResponse'];
  36.     }
  37.     public function onKernelResponse(ResponseEvent $e): void
  38.     {
  39.         if (!$this->isMainRequest($e)) {
  40.             return;
  41.         }
  42.         if (!$this->isContentTypeValid($e->getResponse())) {
  43.             return;
  44.         }
  45.         $response $e->getResponse();
  46.         if ($response->isRedirection()) {
  47.             return;
  48.         }
  49.         if ($response->headers->has('X-Frame-Options')) {
  50.             // Do not overwrite an existing header
  51.             return;
  52.         }
  53.         $request $e->getRequest();
  54.         $host '' === $request->getHost() ? '/' $request->getHost();
  55.         // skip non-listed hosts
  56.         if (null !== $this->hosts && !== preg_match('{'.$this->hosts.'}i'$host)) {
  57.             return;
  58.         }
  59.         $currentPath '' === $request->getRequestUri() ? '/' $request->getRequestUri();
  60.         foreach ($this->paths as $path => $options) {
  61.             if (=== preg_match('{'.$path.'}i'$currentPath)) {
  62.                 if ('ALLOW' === $options['header']) {
  63.                     $response->headers->remove('X-Frame-Options');
  64.                 } else {
  65.                     $response->headers->set('X-Frame-Options'$options['header']);
  66.                 }
  67.                 return;
  68.             }
  69.         }
  70.     }
  71. }