^ null
^ null
^ null
^ null
Symfony Profiler

vendor/symfony/web-profiler-bundle/Controller/ProfilerController.php line 201

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\Controller;
  11. use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler;
  12. use Symfony\Bundle\WebProfilerBundle\Profiler\TemplateManager;
  13. use Symfony\Component\HttpFoundation\RedirectResponse;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag;
  17. use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
  18. use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
  19. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  20. use Symfony\Component\HttpKernel\Profiler\Profiler;
  21. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  22. use Twig\Environment;
  23. /**
  24.  * @author Fabien Potencier <fabien@symfony.com>
  25.  *
  26.  * @internal since Symfony 4.4
  27.  */
  28. class ProfilerController
  29. {
  30.     private $templateManager;
  31.     private $generator;
  32.     private $profiler;
  33.     private $twig;
  34.     private $templates;
  35.     private $cspHandler;
  36.     private $baseDir;
  37.     public function __construct(UrlGeneratorInterface $generatorProfiler $profiler nullEnvironment $twig, array $templatesContentSecurityPolicyHandler $cspHandler nullstring $baseDir null)
  38.     {
  39.         $this->generator $generator;
  40.         $this->profiler $profiler;
  41.         $this->twig $twig;
  42.         $this->templates $templates;
  43.         $this->cspHandler $cspHandler;
  44.         $this->baseDir $baseDir;
  45.     }
  46.     /**
  47.      * Redirects to the last profiles.
  48.      *
  49.      * @return RedirectResponse A RedirectResponse instance
  50.      *
  51.      * @throws NotFoundHttpException
  52.      */
  53.     public function homeAction()
  54.     {
  55.         $this->denyAccessIfProfilerDisabled();
  56.         return new RedirectResponse($this->generator->generate('_profiler_search_results', ['token' => 'empty''limit' => 10]), 302, ['Content-Type' => 'text/html']);
  57.     }
  58.     /**
  59.      * Renders a profiler panel for the given token.
  60.      *
  61.      * @param string $token The profiler token
  62.      *
  63.      * @return Response A Response instance
  64.      *
  65.      * @throws NotFoundHttpException
  66.      */
  67.     public function panelAction(Request $request$token)
  68.     {
  69.         $this->denyAccessIfProfilerDisabled();
  70.         if (null !== $this->cspHandler) {
  71.             $this->cspHandler->disableCsp();
  72.         }
  73.         $panel $request->query->get('panel');
  74.         $page $request->query->get('page''home');
  75.         if ('latest' === $token && $latest current($this->profiler->find(nullnull1nullnullnull))) {
  76.             $token $latest['token'];
  77.         }
  78.         if (!$profile $this->profiler->loadProfile($token)) {
  79.             return $this->renderWithCspNonces($request'@WebProfiler/Profiler/info.html.twig', ['about' => 'no_token''token' => $token'request' => $request]);
  80.         }
  81.         if (null === $panel) {
  82.             $panel 'request';
  83.             foreach ($profile->getCollectors() as $collector) {
  84.                 if ($collector instanceof ExceptionDataCollector && $collector->hasException()) {
  85.                     $panel $collector->getName();
  86.                     break;
  87.                 }
  88.                 if ($collector instanceof DumpDataCollector && $collector->getDumpsCount() > 0) {
  89.                     $panel $collector->getName();
  90.                 }
  91.             }
  92.         }
  93.         if (!$profile->hasCollector($panel)) {
  94.             throw new NotFoundHttpException(sprintf('Panel "%s" is not available for token "%s".'$panel$token));
  95.         }
  96.         return $this->renderWithCspNonces($request$this->getTemplateManager()->getName($profile$panel), [
  97.             'token' => $token,
  98.             'profile' => $profile,
  99.             'collector' => $profile->getCollector($panel),
  100.             'panel' => $panel,
  101.             'page' => $page,
  102.             'request' => $request,
  103.             'templates' => $this->getTemplateManager()->getNames($profile),
  104.             'is_ajax' => $request->isXmlHttpRequest(),
  105.             'profiler_markup_version' => 2// 1 = original profiler, 2 = Symfony 2.8+ profiler
  106.         ]);
  107.     }
  108.     /**
  109.      * Renders the Web Debug Toolbar.
  110.      *
  111.      * @param string $token The profiler token
  112.      *
  113.      * @return Response A Response instance
  114.      *
  115.      * @throws NotFoundHttpException
  116.      */
  117.     public function toolbarAction(Request $request$token)
  118.     {
  119.         if (null === $this->profiler) {
  120.             throw new NotFoundHttpException('The profiler must be enabled.');
  121.         }
  122.         if ($request->hasSession() && ($session $request->getSession())->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
  123.             // keep current flashes for one more request if using AutoExpireFlashBag
  124.             $session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
  125.         }
  126.         if ('empty' === $token || null === $token) {
  127.             return new Response(''200, ['Content-Type' => 'text/html']);
  128.         }
  129.         $this->profiler->disable();
  130.         if (!$profile $this->profiler->loadProfile($token)) {
  131.             return new Response(''404, ['Content-Type' => 'text/html']);
  132.         }
  133.         $url null;
  134.         try {
  135.             $url $this->generator->generate('_profiler', ['token' => $token], UrlGeneratorInterface::ABSOLUTE_URL);
  136.         } catch (\Exception $e) {
  137.             // the profiler is not enabled
  138.         }
  139.         return $this->renderWithCspNonces($request'@WebProfiler/Profiler/toolbar.html.twig', [
  140.             'request' => $request,
  141.             'profile' => $profile,
  142.             'templates' => $this->getTemplateManager()->getNames($profile),
  143.             'profiler_url' => $url,
  144.             'token' => $token,
  145.             'profiler_markup_version' => 2// 1 = original toolbar, 2 = Symfony 2.8+ toolbar
  146.         ]);
  147.     }
  148.     /**
  149.      * Renders the profiler search bar.
  150.      *
  151.      * @return Response A Response instance
  152.      *
  153.      * @throws NotFoundHttpException
  154.      */
  155.     public function searchBarAction(Request $request)
  156.     {
  157.         $this->denyAccessIfProfilerDisabled();
  158.         if (null !== $this->cspHandler) {
  159.             $this->cspHandler->disableCsp();
  160.         }
  161.         if (!$request->hasSession()) {
  162.             $ip =
  163.             $method =
  164.             $statusCode =
  165.             $url =
  166.             $start =
  167.             $end =
  168.             $limit =
  169.             $token null;
  170.         } else {
  171.             $session $request->getSession();
  172.             $ip $request->query->get('ip'$session->get('_profiler_search_ip'));
  173.             $method $request->query->get('method'$session->get('_profiler_search_method'));
  174.             $statusCode $request->query->get('status_code'$session->get('_profiler_search_status_code'));
  175.             $url $request->query->get('url'$session->get('_profiler_search_url'));
  176.             $start $request->query->get('start'$session->get('_profiler_search_start'));
  177.             $end $request->query->get('end'$session->get('_profiler_search_end'));
  178.             $limit $request->query->get('limit'$session->get('_profiler_search_limit'));
  179.             $token $request->query->get('token'$session->get('_profiler_search_token'));
  180.         }
  181.         return new Response(
  182.             $this->twig->render('@WebProfiler/Profiler/search.html.twig', [
  183.                 'token' => $token,
  184.                 'ip' => $ip,
  185.                 'method' => $method,
  186.                 'status_code' => $statusCode,
  187.                 'url' => $url,
  188.                 'start' => $start,
  189.                 'end' => $end,
  190.                 'limit' => $limit,
  191.                 'request' => $request,
  192.             ]),
  193.             200,
  194.             ['Content-Type' => 'text/html']
  195.         );
  196.     }
  197.     /**
  198.      * Renders the search results.
  199.      *
  200.      * @param string $token The token
  201.      *
  202.      * @return Response A Response instance
  203.      *
  204.      * @throws NotFoundHttpException
  205.      */
  206.     public function searchResultsAction(Request $request$token)
  207.     {
  208.         $this->denyAccessIfProfilerDisabled();
  209.         if (null !== $this->cspHandler) {
  210.             $this->cspHandler->disableCsp();
  211.         }
  212.         $profile $this->profiler->loadProfile($token);
  213.         $ip $request->query->get('ip');
  214.         $method $request->query->get('method');
  215.         $statusCode $request->query->get('status_code');
  216.         $url $request->query->get('url');
  217.         $start $request->query->get('start'null);
  218.         $end $request->query->get('end'null);
  219.         $limit $request->query->get('limit');
  220.         return $this->renderWithCspNonces($request'@WebProfiler/Profiler/results.html.twig', [
  221.             'request' => $request,
  222.             'token' => $token,
  223.             'profile' => $profile,
  224.             'tokens' => $this->profiler->find($ip$url$limit$method$start$end$statusCode),
  225.             'ip' => $ip,
  226.             'method' => $method,
  227.             'status_code' => $statusCode,
  228.             'url' => $url,
  229.             'start' => $start,
  230.             'end' => $end,
  231.             'limit' => $limit,
  232.             'panel' => null,
  233.         ]);
  234.     }
  235.     /**
  236.      * Narrows the search bar.
  237.      *
  238.      * @return Response A Response instance
  239.      *
  240.      * @throws NotFoundHttpException
  241.      */
  242.     public function searchAction(Request $request)
  243.     {
  244.         $this->denyAccessIfProfilerDisabled();
  245.         $ip $request->query->get('ip');
  246.         $method $request->query->get('method');
  247.         $statusCode $request->query->get('status_code');
  248.         $url $request->query->get('url');
  249.         $start $request->query->get('start'null);
  250.         $end $request->query->get('end'null);
  251.         $limit $request->query->get('limit');
  252.         $token $request->query->get('token');
  253.         if ($request->hasSession()) {
  254.             $session $request->getSession();
  255.             $session->set('_profiler_search_ip'$ip);
  256.             $session->set('_profiler_search_method'$method);
  257.             $session->set('_profiler_search_status_code'$statusCode);
  258.             $session->set('_profiler_search_url'$url);
  259.             $session->set('_profiler_search_start'$start);
  260.             $session->set('_profiler_search_end'$end);
  261.             $session->set('_profiler_search_limit'$limit);
  262.             $session->set('_profiler_search_token'$token);
  263.         }
  264.         if (!empty($token)) {
  265.             return new RedirectResponse($this->generator->generate('_profiler', ['token' => $token]), 302, ['Content-Type' => 'text/html']);
  266.         }
  267.         $tokens $this->profiler->find($ip$url$limit$method$start$end$statusCode);
  268.         return new RedirectResponse($this->generator->generate('_profiler_search_results', [
  269.             'token' => $tokens $tokens[0]['token'] : 'empty',
  270.             'ip' => $ip,
  271.             'method' => $method,
  272.             'status_code' => $statusCode,
  273.             'url' => $url,
  274.             'start' => $start,
  275.             'end' => $end,
  276.             'limit' => $limit,
  277.         ]), 302, ['Content-Type' => 'text/html']);
  278.     }
  279.     /**
  280.      * Displays the PHP info.
  281.      *
  282.      * @return Response A Response instance
  283.      *
  284.      * @throws NotFoundHttpException
  285.      */
  286.     public function phpinfoAction()
  287.     {
  288.         $this->denyAccessIfProfilerDisabled();
  289.         if (null !== $this->cspHandler) {
  290.             $this->cspHandler->disableCsp();
  291.         }
  292.         ob_start();
  293.         phpinfo();
  294.         $phpinfo ob_get_clean();
  295.         return new Response($phpinfo200, ['Content-Type' => 'text/html']);
  296.     }
  297.     /**
  298.      * Displays the source of a file.
  299.      *
  300.      * @return Response A Response instance
  301.      *
  302.      * @throws NotFoundHttpException
  303.      */
  304.     public function openAction(Request $request)
  305.     {
  306.         if (null === $this->baseDir) {
  307.             throw new NotFoundHttpException('The base dir should be set.');
  308.         }
  309.         if ($this->profiler) {
  310.             $this->profiler->disable();
  311.         }
  312.         $file $request->query->get('file');
  313.         $line $request->query->get('line');
  314.         $filename $this->baseDir.\DIRECTORY_SEPARATOR.$file;
  315.         if (preg_match("'(^|[/\\\\])\.'"$file) || !is_readable($filename)) {
  316.             throw new NotFoundHttpException(sprintf('The file "%s" cannot be opened.'$file));
  317.         }
  318.         return $this->renderWithCspNonces($request'@WebProfiler/Profiler/open.html.twig', [
  319.             'filename' => $filename,
  320.             'file' => $file,
  321.             'line' => $line,
  322.         ]);
  323.     }
  324.     /**
  325.      * Gets the Template Manager.
  326.      *
  327.      * @return TemplateManager The Template Manager
  328.      */
  329.     protected function getTemplateManager()
  330.     {
  331.         if (null === $this->templateManager) {
  332.             $this->templateManager = new TemplateManager($this->profiler$this->twig$this->templates);
  333.         }
  334.         return $this->templateManager;
  335.     }
  336.     private function denyAccessIfProfilerDisabled()
  337.     {
  338.         if (null === $this->profiler) {
  339.             throw new NotFoundHttpException('The profiler must be enabled.');
  340.         }
  341.         $this->profiler->disable();
  342.     }
  343.     private function renderWithCspNonces(Request $requeststring $template, array $variablesint $code 200, array $headers = ['Content-Type' => 'text/html']): Response
  344.     {
  345.         $response = new Response(''$code$headers);
  346.         $nonces $this->cspHandler $this->cspHandler->getNonces($request$response) : [];
  347.         $variables['csp_script_nonce'] = $nonces['csp_script_nonce'] ?? null;
  348.         $variables['csp_style_nonce'] = $nonces['csp_style_nonce'] ?? null;
  349.         $response->setContent($this->twig->render($template$variables));
  350.         return $response;
  351.     }
  352. }