vendor/contao/core-bundle/src/Controller/InitializeController.php line 61

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Controller;
  11. use Contao\CoreBundle\Framework\ContaoFramework;
  12. use Contao\CoreBundle\Response\InitializeControllerResponse;
  13. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\RequestStack;
  16. use Symfony\Component\HttpFoundation\Response;
  17. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  18. use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
  19. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  20. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  21. use Symfony\Component\HttpKernel\HttpKernel;
  22. use Symfony\Component\HttpKernel\HttpKernelInterface;
  23. use Symfony\Component\HttpKernel\KernelEvents;
  24. use Symfony\Component\HttpKernel\KernelInterface;
  25. use Symfony\Component\HttpKernel\TerminableInterface;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. /**
  28.  * Custom controller to support legacy entry points.
  29.  *
  30.  * @internal
  31.  *
  32.  * @deprecated Deprecated in Contao 4.0, to be removed in Contao 5.0
  33.  *
  34.  * @Route("/_contao/initialize", name="contao_initialize")
  35.  */
  36. class InitializeController
  37. {
  38.     private ContaoFramework $framework;
  39.     private RequestStack $requestStack;
  40.     private EventDispatcherInterface $eventDispatcher;
  41.     private HttpKernelInterface $httpKernel;
  42.     private KernelInterface $kernel;
  43.     public function __construct(ContaoFramework $frameworkRequestStack $requestStackEventDispatcherInterface $eventDispatcherHttpKernelInterface $httpKernelKernelInterface $kernel)
  44.     {
  45.         $this->framework $framework;
  46.         $this->requestStack $requestStack;
  47.         $this->eventDispatcher $eventDispatcher;
  48.         $this->httpKernel $httpKernel;
  49.         $this->kernel $kernel;
  50.     }
  51.     /**
  52.      * Initializes the Contao framework.
  53.      */
  54.     public function __invoke(): InitializeControllerResponse
  55.     {
  56.         trigger_deprecation('contao/core-bundle''4.0''Using custom entry points has been deprecated and will no longer work in Contao 5.0.');
  57.         $mainRequest $this->requestStack->getMainRequest();
  58.         if (null === $mainRequest) {
  59.             throw new \RuntimeException('The request stack did not contain a main request.');
  60.         }
  61.         $realRequest Request::createFromGlobals();
  62.         $realRequest->setLocale($mainRequest->getLocale());
  63.         if ($mainRequest->hasSession()) {
  64.             $realRequest->setSession($mainRequest->getSession());
  65.         }
  66.         if (!\defined('TL_SCRIPT')) {
  67.             \define('TL_SCRIPT''');
  68.         }
  69.         // Necessary to generate the correct base path
  70.         foreach (['REQUEST_URI''SCRIPT_NAME''SCRIPT_FILENAME''PHP_SELF'] as $name) {
  71.             $realRequest->server->set($namestr_replace(TL_SCRIPT'index.php'$realRequest->server->get($name)));
  72.         }
  73.         $realRequest->attributes->replace($mainRequest->attributes->all());
  74.         // Empty the request stack to make our real request the main
  75.         do {
  76.             $pop $this->requestStack->pop();
  77.         } while ($pop);
  78.         // Initialize the framework with the real request
  79.         $this->requestStack->push($realRequest);
  80.         $this->framework->initialize();
  81.         // Add the main request again. When Kernel::handle() is finished,
  82.         // it will pop the current request, resulting in the real request being active.
  83.         $this->requestStack->push($mainRequest);
  84.         set_exception_handler(
  85.             function ($e) use ($realRequest): void {
  86.                 // Do not catch PHP7 Throwables
  87.                 if (!$e instanceof \Exception) {
  88.                     throw $e;
  89.                 }
  90.                 $this->handleException($e$realRequest);
  91.             }
  92.         );
  93.         // Collect all output into final response
  94.         $response = new Response();
  95.         ob_start(
  96.             static function ($buffer) use ($response) {
  97.                 $response->setContent($response->getContent().$buffer);
  98.                 return '';
  99.             },
  100.             0,
  101.             PHP_OUTPUT_HANDLER_REMOVABLE PHP_OUTPUT_HANDLER_CLEANABLE
  102.         );
  103.         // register_shutdown_function() somehow can't handle $this
  104.         $self $this;
  105.         register_shutdown_function(
  106.             static function () use ($self$realRequest$response): void {
  107.                 @ob_end_clean();
  108.                 $self->handleResponse($realRequest$response);
  109.             }
  110.         );
  111.         return new InitializeControllerResponse(''204);
  112.     }
  113.     /**
  114.      * Handles an exception by trying to convert it to a Response object.
  115.      *
  116.      * @see HttpKernel::handleException()
  117.      */
  118.     private function handleException(\Throwable $eRequest $request): void
  119.     {
  120.         $event = new ExceptionEvent($this->httpKernel$requestHttpKernelInterface::MAIN_REQUEST$e);
  121.         $this->eventDispatcher->dispatch($eventKernelEvents::EXCEPTION);
  122.         // A listener might have replaced the exception
  123.         $e $event->getThrowable();
  124.         if (!$response $event->getResponse()) {
  125.             throw $e;
  126.         }
  127.         // The developer asked for a specific status code
  128.         if (
  129.             !$event->isAllowingCustomResponseCode()
  130.             && !$response->isClientError()
  131.             && !$response->isServerError()
  132.             && !$response->isRedirect()
  133.         ) {
  134.             // Ensure that we actually have an error response
  135.             if ($e instanceof HttpExceptionInterface) {
  136.                 // Keep the HTTP status code and headers
  137.                 $response->setStatusCode($e->getStatusCode());
  138.                 $response->headers->add($e->getHeaders());
  139.             } else {
  140.                 $response->setStatusCode(500);
  141.             }
  142.         }
  143.         try {
  144.             $event = new ResponseEvent($this->httpKernel$requestHttpKernelInterface::MAIN_REQUEST$response);
  145.             $this->eventDispatcher->dispatch($eventKernelEvents::RESPONSE);
  146.             $response $event->getResponse();
  147.             $this->eventDispatcher->dispatch(
  148.                 new FinishRequestEvent($this->httpKernel$requestHttpKernelInterface::MAIN_REQUEST),
  149.                 KernelEvents::FINISH_REQUEST
  150.             );
  151.             $this->requestStack->pop();
  152.         } catch (\Exception $e) {
  153.             // ignore and continue with original response
  154.         }
  155.         $response->send();
  156.         if ($this->kernel instanceof TerminableInterface) {
  157.             $this->kernel->terminate($request$response);
  158.         }
  159.         exit;
  160.     }
  161.     /**
  162.      * Execute kernel.response and kernel.finish_request events.
  163.      */
  164.     private function handleResponse(Request $requestResponse $response): void
  165.     {
  166.         $event = new ResponseEvent($this->httpKernel$requestHttpKernelInterface::MAIN_REQUEST$response);
  167.         try {
  168.             $this->eventDispatcher->dispatch($eventKernelEvents::RESPONSE);
  169.         } catch (\Throwable $e) {
  170.             // Ignore any errors from events
  171.         }
  172.         $this->eventDispatcher->dispatch(
  173.             new FinishRequestEvent($this->httpKernel$requestHttpKernelInterface::MAIN_REQUEST),
  174.             KernelEvents::FINISH_REQUEST
  175.         );
  176.         $this->requestStack->pop();
  177.         $response $event->getResponse();
  178.         $response->send();
  179.         if ($this->kernel instanceof TerminableInterface) {
  180.             $this->kernel->terminate($request$response);
  181.         }
  182.     }
  183. }