src/Eccube/Session/Storage/Handler/SameSiteNoneCompatSessionHandler.php line 37

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Session\Storage\Handler;
  13. use Skorp\Dissua\SameSite;
  14. use Symfony\Component\HttpFoundation\Cookie;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler;
  17. class SameSiteNoneCompatSessionHandler extends StrictSessionHandler
  18. {
  19.     /** @var \SessionHandlerInterface */
  20.     private $handler;
  21.     /** @var bool */
  22.     private $doDestroy;
  23.     /** @var string */
  24.     private $sessionName;
  25.     /** @var string|null */
  26.     private $prefetchData;
  27.     /** @var string */
  28.     private $newSessionId;
  29.     /**
  30.      *  {@inheritdoc}
  31.      */
  32.     public function __construct(\SessionHandlerInterface $handler)
  33.     {
  34.         $this->handler $handler;
  35.         ini_set('session.cookie_secure'$this->getCookieSecure());
  36.         ini_set('session.cookie_samesite'$this->getCookieSameSite());
  37.         ini_set('session.cookie_path'$this->getCookiePath());
  38.     }
  39.     /**
  40.      * {@inheritdoc}
  41.      */
  42.     public function open($savePath$sessionName)
  43.     {
  44.         $this->sessionName $sessionName;
  45.         // see https://github.com/symfony/symfony/blob/2adc85d49cbe14e346068fa7e9c2e1f08ab31de6/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php#L35-L37
  46.         if (!headers_sent() && !ini_get('session.cache_limiter') && '0' !== ini_get('session.cache_limiter')) {
  47.             header(sprintf('Cache-Control: max-age=%d, private, must-revalidate'60 * (int) ini_get('session.cache_expire')));
  48.         }
  49.         return $this->handler->open($savePath$sessionName);
  50.     }
  51.     /**
  52.      * {@inheritdoc}
  53.      */
  54.     protected function doRead($sessionId)
  55.     {
  56.         return $this->handler->read($sessionId);
  57.     }
  58.     /**
  59.      * {@inheritdoc}
  60.      */
  61.     public function updateTimestamp($sessionId$data)
  62.     {
  63.         return $this->write($sessionId$data);
  64.     }
  65.     /**
  66.      * {@inheritdoc}
  67.      */
  68.     protected function doWrite($sessionId$data)
  69.     {
  70.         return $this->handler->write($sessionId$data);
  71.     }
  72.     /**
  73.      * {@inheritdoc}
  74.      *
  75.      * @see https://github.com/symfony/symfony/blob/2adc85d49cbe14e346068fa7e9c2e1f08ab31de6/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php#L126-L167
  76.      */
  77.     public function destroy($sessionId)
  78.     {
  79.         if (\PHP_VERSION_ID 70000) {
  80.             $this->prefetchData null;
  81.         }
  82.         if (!headers_sent() && filter_var(ini_get('session.use_cookies'), FILTER_VALIDATE_BOOLEAN)) {
  83.             if (!$this->sessionName) {
  84.                 throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.'\get_class($this)));
  85.             }
  86.             $sessionCookie sprintf(' %s='urlencode($this->sessionName));
  87.             $sessionCookieWithId sprintf('%s%s;'$sessionCookieurlencode($sessionId));
  88.             $sessionCookieFound false;
  89.             $otherCookies = [];
  90.             foreach (headers_list() as $h) {
  91.                 if (!== stripos($h'Set-Cookie:')) {
  92.                     continue;
  93.                 }
  94.                 if (11 === strpos($h$sessionCookie11)) {
  95.                     $sessionCookieFound true;
  96.                     if (11 !== strpos($h$sessionCookieWithId11)) {
  97.                         $otherCookies[] = $h;
  98.                     }
  99.                 } else {
  100.                     $otherCookies[] = $h;
  101.                 }
  102.             }
  103.             if ($sessionCookieFound) {
  104.                 header_remove('Set-Cookie');
  105.                 foreach ($otherCookies as $h) {
  106.                     header($hfalse);
  107.                 }
  108.             } else {
  109.                 if (\PHP_VERSION_ID 70300) {
  110.                     setcookie($this->sessionName''0ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), FILTER_VALIDATE_BOOLEAN));
  111.                 } else {
  112.                     setcookie($this->sessionName'',
  113.                               [
  114.                                   'expires' => 0,
  115.                                   'path' => $this->getCookiePath(),
  116.                                   'domain' => ini_get('session.cookie_domain'),
  117.                                   'secure' => filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN),
  118.                                   'httponly' => filter_var(ini_get('session.cookie_httponly'), FILTER_VALIDATE_BOOLEAN),
  119.                                   'samesite' => $this->getCookieSameSite(),
  120.                               ]
  121.                     );
  122.                 }
  123.             }
  124.         }
  125.         return $this->newSessionId === $sessionId || $this->doDestroy($sessionId);
  126.     }
  127.     /**
  128.      * {@inheritdoc}
  129.      */
  130.     protected function doDestroy($sessionId)
  131.     {
  132.         $this->doDestroy false;
  133.         return $this->handler->destroy($sessionId);
  134.     }
  135.     /**
  136.      * {@inheritdoc}
  137.      */
  138.     public function close()
  139.     {
  140.         return $this->handler->close();
  141.     }
  142.     /**
  143.      * @return bool
  144.      */
  145.     public function gc($maxlifetime)
  146.     {
  147.         return $this->handler->gc($maxlifetime);
  148.     }
  149.     /**
  150.      * @return string
  151.      */
  152.     public function getCookieSameSite()
  153.     {
  154.         if ($this->shouldSendSameSiteNone() && \PHP_VERSION_ID >= 70300 && $this->getCookieSecure()) {
  155.             return Cookie::SAMESITE_NONE;
  156.         }
  157.         return '';
  158.     }
  159.     /**
  160.      * @return string
  161.      */
  162.     public function getCookiePath()
  163.     {
  164.         $cookiePath env('ECCUBE_COOKIE_PATH''/');
  165.         if ($this->shouldSendSameSiteNone() && \PHP_VERSION_ID 70300 && $this->getCookieSecure()) {
  166.             return $cookiePath.'; SameSite='.Cookie::SAMESITE_NONE;
  167.         }
  168.         return $cookiePath;
  169.     }
  170.     /**
  171.      * @return string
  172.      */
  173.     public function getCookieSecure()
  174.     {
  175.         $request Request::createFromGlobals();
  176.         return $request->isSecure() ? '1' '0';
  177.     }
  178.     /**
  179.      * @return bool
  180.      */
  181.     private function shouldSendSameSiteNone()
  182.     {
  183.         $userAgent array_key_exists('HTTP_USER_AGENT'$_SERVER) ? $_SERVER['HTTP_USER_AGENT'] : null;
  184.         return SameSite::handle($userAgent);
  185.     }
  186. }