vendor/pimcore/pimcore/bundles/AdminBundle/Session/Handler/AdminSessionHandler.php line 187

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Bundle\AdminBundle\Session\Handler;
  15. use Pimcore\Bundle\CoreBundle\EventListener\Traits\PimcoreContextAwareTrait;
  16. use Pimcore\Http\Request\Resolver\PimcoreContextResolver;
  17. use Pimcore\Http\RequestHelper;
  18. use Pimcore\Session\Attribute\LockableAttributeBagInterface;
  19. use Psr\Log\LoggerAwareInterface;
  20. use Psr\Log\LoggerAwareTrait;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  23. use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
  24. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  25. /**
  26.  * @internal
  27.  *
  28.  * @deprecated
  29.  */
  30. class AdminSessionHandler implements LoggerAwareInterfaceAdminSessionHandlerInterface
  31. {
  32.     use LoggerAwareTrait;
  33.     use PimcoreContextAwareTrait;
  34.     /**
  35.      * Contains how many sessions are currently open, this is important, because writeClose() must not be called if
  36.      * there is still an open session, this is especially important if something doesn't use the method use() but get()
  37.      * so the session isn't closed automatically after the action is done
  38.      */
  39.     private $openedSessions 0;
  40.     /**
  41.      * @deprecated
  42.      *
  43.      * @var SessionInterface
  44.      */
  45.     protected $session;
  46.     protected $readOnlySessionBagsCache = [];
  47.     /**
  48.      * @var bool|null
  49.      */
  50.     private $canWriteAndClose;
  51.     /**
  52.      * @var RequestHelper
  53.      */
  54.     protected $requestHelper;
  55.     public function __construct(RequestHelper $requestHelper)
  56.     {
  57.         $this->requestHelper $requestHelper;
  58.     }
  59.     /**
  60.      * {@inheritdoc}
  61.      */
  62.     public function getSessionId()
  63.     {
  64.         if (!$this->getSession()->isStarted()) {
  65.             // this is just to initialize the session :)
  66.             $this->useSession(static function (SessionInterface $session) {
  67.                 return $session->getId();
  68.             });
  69.         }
  70.         return $this->getSession()->getId();
  71.     }
  72.     /**
  73.      * @return SessionInterface
  74.      */
  75.     private function getSession()
  76.     {
  77.         try {
  78.             return $this->requestHelper->getSession();
  79.         } catch (\LogicException $e) {
  80.             $this->logger->debug('Error while getting the admin session: {exception}', ['exception' => $e->getMessage()]);
  81.         }
  82.         trigger_deprecation('pimcore/pimcore''10.5',
  83.             sprintf('Session used with non existing request stack in %s, that will not be possible in Pimcore 11.'__CLASS__));
  84.         return \Pimcore::getContainer()->get('session');
  85.     }
  86.     /**
  87.      * {@inheritdoc}
  88.      */
  89.     public function getSessionName()
  90.     {
  91.         return $this->getSession()->getName();
  92.     }
  93.     /**
  94.      * {@inheritdoc}
  95.      */
  96.     public function useSession(callable $callable)
  97.     {
  98.         $session $this->loadSession();
  99.         $result call_user_func_array($callable, [$session]);
  100.         $this->writeClose();
  101.         $this->readOnlySessionBagsCache = []; // clear cache if session was modified manually
  102.         return $result;
  103.     }
  104.     /**
  105.      * {@inheritdoc}
  106.      */
  107.     public function useSessionAttributeBag(callable $callablestring $name 'pimcore_admin')
  108.     {
  109.         $session $this->loadSession();
  110.         $attributeBag $this->loadAttributeBag($name$session);
  111.         $result call_user_func_array($callable, [$attributeBag$session]);
  112.         $this->writeClose();
  113.         return $result;
  114.     }
  115.     /**
  116.      * {@inheritdoc}
  117.      */
  118.     public function getReadOnlyAttributeBag(string $name 'pimcore_admin'): AttributeBagInterface
  119.     {
  120.         if (isset($this->readOnlySessionBagsCache[$name])) {
  121.             $bag $this->readOnlySessionBagsCache[$name];
  122.         } else {
  123.             $bag $this->useSessionAttributeBag(function (AttributeBagInterface $bag) {
  124.                 return $bag;
  125.             }, $name);
  126.         }
  127.         if ($bag instanceof LockableAttributeBagInterface) {
  128.             $bag->lock();
  129.         }
  130.         return $bag;
  131.     }
  132.     /**
  133.      * {@inheritdoc}
  134.      */
  135.     public function invalidate(int $lifetime null): bool
  136.     {
  137.         return $this->getSession()->invalidate($lifetime);
  138.     }
  139.     /**
  140.      * {@inheritdoc}
  141.      */
  142.     public function regenerateId(): bool
  143.     {
  144.         return $this->useSession(static function (SessionInterface $session) {
  145.             return $session->migrate(true);
  146.         });
  147.     }
  148.     /**
  149.      * {@inheritdoc}
  150.      */
  151.     public function loadAttributeBag(string $nameSessionInterface $session null): SessionBagInterface
  152.     {
  153.         if (null === $session) {
  154.             $session $this->loadSession();
  155.         }
  156.         $attributeBag $session->getBag($name);
  157.         if ($attributeBag instanceof LockableAttributeBagInterface) {
  158.             $attributeBag->unlock();
  159.         }
  160.         $this->readOnlySessionBagsCache[$name] = $attributeBag;
  161.         return $attributeBag;
  162.     }
  163.     /**
  164.      * {@inheritdoc}
  165.      */
  166.     public function requestHasSessionId(Request $requestbool $checkRequestParams false): bool
  167.     {
  168.         $sessionName $this->getSessionName();
  169.         if (empty($sessionName)) {
  170.             return false;
  171.         }
  172.         $properties = ['cookies'];
  173.         if ($checkRequestParams) {
  174.             $properties[] = 'request';
  175.             $properties[] = 'query';
  176.         }
  177.         foreach ($properties as $property) {
  178.             if ($request->$property->has($sessionName) && !empty($request->$property->get($sessionName))) {
  179.                 return true;
  180.             }
  181.         }
  182.         return false;
  183.     }
  184.     /**
  185.      * {@inheritdoc}
  186.      */
  187.     public function getSessionIdFromRequest(Request $requestbool $checkRequestParams false): string
  188.     {
  189.         if ($this->requestHasSessionId($request$checkRequestParams)) {
  190.             $sessionName $this->getSessionName();
  191.             if ($sessionId $request->cookies->get($sessionName)) {
  192.                 return $sessionId;
  193.             }
  194.             if ($checkRequestParams) {
  195.                 if ($sessionId $request->request->get($sessionName)) {
  196.                     return $sessionId;
  197.                 }
  198.                 if ($sessionId $request->query->get($sessionName)) {
  199.                     return $sessionId;
  200.                 }
  201.             }
  202.         }
  203.         throw new \RuntimeException('Failed to get session ID from request');
  204.     }
  205.     /**
  206.      * {@inheritdoc}
  207.      */
  208.     public function loadSession(): SessionInterface
  209.     {
  210.         $sessionName $this->getSessionName();
  211.         $this->logger->debug('Opening admin session {name}', ['name' => $sessionName]);
  212.         if (!$this->getSession()->isStarted()) {
  213.             $this->getSession()->start();
  214.         }
  215.         $this->openedSessions++;
  216.         $this->logger->debug('Admin session {name} was successfully opened. Open admin sessions: {count}', [
  217.             'name' => $sessionName,
  218.             'count' => $this->openedSessions,
  219.         ]);
  220.         return $this->getSession();
  221.     }
  222.     /**
  223.      * {@inheritdoc}
  224.      */
  225.     public function writeClose()
  226.     {
  227.         if (!$this->shouldWriteAndClose()) {
  228.             return;
  229.         }
  230.         $this->openedSessions--;
  231.         if (=== $this->openedSessions) {
  232.             $this->getSession()->save();
  233.             $this->logger->debug('Admin session {name} was written and closed', [
  234.                 'name' => $this->getSessionName(),
  235.             ]);
  236.         } else {
  237.             $this->logger->debug('Not writing/closing session admin session {name} as there are still {count} open sessions', [
  238.                 'name' => $this->getSessionName(),
  239.                 'count' => $this->openedSessions,
  240.             ]);
  241.         }
  242.     }
  243.     /**
  244.      * @return bool
  245.      */
  246.     private function shouldWriteAndClose(): bool
  247.     {
  248.         // main request is not available in CLI, so session should be written
  249.         // otherwise session should be written & closed in Admin context only.
  250.         return $this->canWriteAndClose ??= !$this->requestHelper->hasMainRequest()
  251.             || $this->isAdminRequest($this->requestHelper->getMainRequest());
  252.     }
  253.     /**
  254.      * @return bool
  255.      */
  256.     private function isAdminRequest(Request $request): bool
  257.     {
  258.         return $this->matchesPimcoreContext($requestPimcoreContextResolver::CONTEXT_ADMIN)
  259.             || $this->requestHelper->isFrontendRequestByAdmin($request);
  260.     }
  261. }