vendor/symfony/symfony/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php line 63

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Bundle\WebProfilerBundle\EventListener;
  11. use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag;
  16. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  17. use Symfony\Component\HttpKernel\KernelEvents;
  18. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  19. use Twig\Environment;
  20. /**
  21.  * WebDebugToolbarListener injects the Web Debug Toolbar.
  22.  *
  23.  * The onKernelResponse method must be connected to the kernel.response event.
  24.  *
  25.  * The WDT is only injected on well-formed HTML (with a proper </body> tag).
  26.  * This means that the WDT is never included in sub-requests or ESI requests.
  27.  *
  28.  * @author Fabien Potencier <fabien@symfony.com>
  29.  */
  30. class WebDebugToolbarListener implements EventSubscriberInterface
  31. {
  32.     const DISABLED 1;
  33.     const ENABLED 2;
  34.     protected $twig;
  35.     protected $urlGenerator;
  36.     protected $interceptRedirects;
  37.     protected $mode;
  38.     protected $position;
  39.     protected $excludedAjaxPaths;
  40.     private $cspHandler;
  41.     public function __construct(Environment $twig$interceptRedirects false$mode self::ENABLED$position 'bottom'UrlGeneratorInterface $urlGenerator null$excludedAjaxPaths '^/bundles|^/_wdt'ContentSecurityPolicyHandler $cspHandler null)
  42.     {
  43.         $this->twig $twig;
  44.         $this->urlGenerator $urlGenerator;
  45.         $this->interceptRedirects = (bool) $interceptRedirects;
  46.         $this->mode = (int) $mode;
  47.         $this->position $position;
  48.         $this->excludedAjaxPaths $excludedAjaxPaths;
  49.         $this->cspHandler $cspHandler;
  50.     }
  51.     public function isEnabled()
  52.     {
  53.         return self::DISABLED !== $this->mode;
  54.     }
  55.     public function onKernelResponse(FilterResponseEvent $event)
  56.     {
  57.         $response $event->getResponse();
  58.         $request $event->getRequest();
  59.         if ($response->headers->has('X-Debug-Token') && null !== $this->urlGenerator) {
  60.             try {
  61.                 $response->headers->set(
  62.                     'X-Debug-Token-Link',
  63.                     $this->urlGenerator->generate('_profiler', ['token' => $response->headers->get('X-Debug-Token')], UrlGeneratorInterface::ABSOLUTE_URL)
  64.                 );
  65.             } catch (\Exception $e) {
  66.                 $response->headers->set('X-Debug-Error', \get_class($e).': '.preg_replace('/\s+/'' '$e->getMessage()));
  67.             }
  68.         }
  69.         if (!$event->isMasterRequest()) {
  70.             return;
  71.         }
  72.         $nonces $this->cspHandler $this->cspHandler->updateResponseHeaders($request$response) : [];
  73.         // do not capture redirects or modify XML HTTP Requests
  74.         if ($request->isXmlHttpRequest()) {
  75.             return;
  76.         }
  77.         if ($response->headers->has('X-Debug-Token') && $response->isRedirect() && $this->interceptRedirects && 'html' === $request->getRequestFormat()) {
  78.             $session $request->getSession();
  79.             if (null !== $session && $session->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
  80.                 // keep current flashes for one more request if using AutoExpireFlashBag
  81.                 $session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
  82.             }
  83.             $response->setContent($this->twig->render('@WebProfiler/Profiler/toolbar_redirect.html.twig', ['location' => $response->headers->get('Location')]));
  84.             $response->setStatusCode(200);
  85.             $response->headers->remove('Location');
  86.         }
  87.         if (self::DISABLED === $this->mode
  88.             || !$response->headers->has('X-Debug-Token')
  89.             || $response->isRedirection()
  90.             || ($response->headers->has('Content-Type') && false === strpos($response->headers->get('Content-Type'), 'html'))
  91.             || 'html' !== $request->getRequestFormat()
  92.             || false !== stripos($response->headers->get('Content-Disposition'), 'attachment;')
  93.         ) {
  94.             return;
  95.         }
  96.         $this->injectToolbar($response$request$nonces);
  97.     }
  98.     /**
  99.      * Injects the web debug toolbar into the given Response.
  100.      */
  101.     protected function injectToolbar(Response $responseRequest $request, array $nonces)
  102.     {
  103.         $content $response->getContent();
  104.         $pos strripos($content'</body>');
  105.         if (false !== $pos) {
  106.             $toolbar "\n".str_replace("\n"''$this->twig->render(
  107.                 '@WebProfiler/Profiler/toolbar_js.html.twig',
  108.                 [
  109.                     'position' => $this->position,
  110.                     'excluded_ajax_paths' => $this->excludedAjaxPaths,
  111.                     'token' => $response->headers->get('X-Debug-Token'),
  112.                     'request' => $request,
  113.                     'csp_script_nonce' => isset($nonces['csp_script_nonce']) ? $nonces['csp_script_nonce'] : null,
  114.                     'csp_style_nonce' => isset($nonces['csp_style_nonce']) ? $nonces['csp_style_nonce'] : null,
  115.                 ]
  116.             ))."\n";
  117.             $content substr($content0$pos).$toolbar.substr($content$pos);
  118.             $response->setContent($content);
  119.         }
  120.     }
  121.     public static function getSubscribedEvents()
  122.     {
  123.         return [
  124.             KernelEvents::RESPONSE => ['onKernelResponse', -128],
  125.         ];
  126.     }
  127. }