vendor/symfony/web-profiler-bundle/EventListener/WebDebugToolbarListener.php line 61

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 $excludedAjaxPaths;
  39.     private $cspHandler;
  40.     public function __construct(Environment $twigbool $interceptRedirects falseint $mode self::ENABLEDUrlGeneratorInterface $urlGenerator nullstring $excludedAjaxPaths '^/bundles|^/_wdt'ContentSecurityPolicyHandler $cspHandler null)
  41.     {
  42.         $this->twig $twig;
  43.         $this->urlGenerator $urlGenerator;
  44.         $this->interceptRedirects $interceptRedirects;
  45.         $this->mode $mode;
  46.         $this->excludedAjaxPaths $excludedAjaxPaths;
  47.         $this->cspHandler $cspHandler;
  48.     }
  49.     public function isEnabled()
  50.     {
  51.         return self::DISABLED !== $this->mode;
  52.     }
  53.     public function onKernelResponse(FilterResponseEvent $event)
  54.     {
  55.         $response $event->getResponse();
  56.         $request $event->getRequest();
  57.         if ($response->headers->has('X-Debug-Token') && null !== $this->urlGenerator) {
  58.             try {
  59.                 $response->headers->set(
  60.                     'X-Debug-Token-Link',
  61.                     $this->urlGenerator->generate('_profiler', ['token' => $response->headers->get('X-Debug-Token')], UrlGeneratorInterface::ABSOLUTE_URL)
  62.                 );
  63.             } catch (\Exception $e) {
  64.                 $response->headers->set('X-Debug-Error', \get_class($e).': '.preg_replace('/\s+/'' '$e->getMessage()));
  65.             }
  66.         }
  67.         if (!$event->isMasterRequest()) {
  68.             return;
  69.         }
  70.         $nonces $this->cspHandler $this->cspHandler->updateResponseHeaders($request$response) : [];
  71.         // do not capture redirects or modify XML HTTP Requests
  72.         if ($request->isXmlHttpRequest()) {
  73.             return;
  74.         }
  75.         if ($response->headers->has('X-Debug-Token') && $response->isRedirect() && $this->interceptRedirects) {
  76.             $session $request->getSession();
  77.             if (null !== $session && $session->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
  78.                 // keep current flashes for one more request if using AutoExpireFlashBag
  79.                 $session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
  80.             }
  81.             $response->setContent($this->twig->render('@WebProfiler/Profiler/toolbar_redirect.html.twig', ['location' => $response->headers->get('Location')]));
  82.             $response->setStatusCode(200);
  83.             $response->headers->remove('Location');
  84.         }
  85.         if (self::DISABLED === $this->mode
  86.             || !$response->headers->has('X-Debug-Token')
  87.             || $response->isRedirection()
  88.             || ($response->headers->has('Content-Type') && false === strpos($response->headers->get('Content-Type'), 'html'))
  89.             || 'html' !== $request->getRequestFormat()
  90.             || false !== stripos($response->headers->get('Content-Disposition'), 'attachment;')
  91.         ) {
  92.             return;
  93.         }
  94.         $this->injectToolbar($response$request$nonces);
  95.     }
  96.     /**
  97.      * Injects the web debug toolbar into the given Response.
  98.      */
  99.     protected function injectToolbar(Response $responseRequest $request, array $nonces)
  100.     {
  101.         $content $response->getContent();
  102.         $pos strripos($content'</body>');
  103.         if (false !== $pos) {
  104.             $toolbar "\n".str_replace("\n"''$this->twig->render(
  105.                 '@WebProfiler/Profiler/toolbar_js.html.twig',
  106.                 [
  107.                     'excluded_ajax_paths' => $this->excludedAjaxPaths,
  108.                     'token' => $response->headers->get('X-Debug-Token'),
  109.                     'request' => $request,
  110.                     'csp_script_nonce' => isset($nonces['csp_script_nonce']) ? $nonces['csp_script_nonce'] : null,
  111.                     'csp_style_nonce' => isset($nonces['csp_style_nonce']) ? $nonces['csp_style_nonce'] : null,
  112.                 ]
  113.             ))."\n";
  114.             $content substr($content0$pos).$toolbar.substr($content$pos);
  115.             $response->setContent($content);
  116.         }
  117.     }
  118.     public static function getSubscribedEvents()
  119.     {
  120.         return [
  121.             KernelEvents::RESPONSE => ['onKernelResponse', -128],
  122.         ];
  123.     }
  124. }