forked from a64f7bb4-7358-4778-9fbe-3b882c34cc1d/v1
				
			
		
			
				
	
	
		
			112 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
| <?php
 | |
| 
 | |
| /*
 | |
|  * This file is part of the Symfony package.
 | |
|  *
 | |
|  * (c) Fabien Potencier <fabien@symfony.com>
 | |
|  *
 | |
|  * For the full copyright and license information, please view the LICENSE
 | |
|  * file that was distributed with this source code.
 | |
|  */
 | |
| 
 | |
| namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
 | |
| 
 | |
| use Symfony\Component\HttpFoundation\Session\SessionUtils;
 | |
| 
 | |
| /**
 | |
|  * This abstract session handler provides a generic implementation
 | |
|  * of the PHP 7.0 SessionUpdateTimestampHandlerInterface,
 | |
|  * enabling strict and lazy session handling.
 | |
|  *
 | |
|  * @author Nicolas Grekas <p@tchwork.com>
 | |
|  */
 | |
| abstract class AbstractSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
 | |
| {
 | |
|     private string $sessionName;
 | |
|     private string $prefetchId;
 | |
|     private string $prefetchData;
 | |
|     private ?string $newSessionId = null;
 | |
|     private string $igbinaryEmptyData;
 | |
| 
 | |
|     public function open(string $savePath, string $sessionName): bool
 | |
|     {
 | |
|         $this->sessionName = $sessionName;
 | |
|         if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) {
 | |
|             header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire')));
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     abstract protected function doRead(string $sessionId): string;
 | |
| 
 | |
|     abstract protected function doWrite(string $sessionId, string $data): bool;
 | |
| 
 | |
|     abstract protected function doDestroy(string $sessionId): bool;
 | |
| 
 | |
|     public function validateId(string $sessionId): bool
 | |
|     {
 | |
|         $this->prefetchData = $this->read($sessionId);
 | |
|         $this->prefetchId = $sessionId;
 | |
| 
 | |
|         return '' !== $this->prefetchData;
 | |
|     }
 | |
| 
 | |
|     public function read(string $sessionId): string
 | |
|     {
 | |
|         if (isset($this->prefetchId)) {
 | |
|             $prefetchId = $this->prefetchId;
 | |
|             $prefetchData = $this->prefetchData;
 | |
|             unset($this->prefetchId, $this->prefetchData);
 | |
| 
 | |
|             if ($prefetchId === $sessionId || '' === $prefetchData) {
 | |
|                 $this->newSessionId = '' === $prefetchData ? $sessionId : null;
 | |
| 
 | |
|                 return $prefetchData;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $data = $this->doRead($sessionId);
 | |
|         $this->newSessionId = '' === $data ? $sessionId : null;
 | |
| 
 | |
|         return $data;
 | |
|     }
 | |
| 
 | |
|     public function write(string $sessionId, string $data): bool
 | |
|     {
 | |
|         // see https://github.com/igbinary/igbinary/issues/146
 | |
|         $this->igbinaryEmptyData ??= \function_exists('igbinary_serialize') ? igbinary_serialize([]) : '';
 | |
|         if ('' === $data || $this->igbinaryEmptyData === $data) {
 | |
|             return $this->destroy($sessionId);
 | |
|         }
 | |
|         $this->newSessionId = null;
 | |
| 
 | |
|         return $this->doWrite($sessionId, $data);
 | |
|     }
 | |
| 
 | |
|     public function destroy(string $sessionId): bool
 | |
|     {
 | |
|         if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL)) {
 | |
|             if (!isset($this->sessionName)) {
 | |
|                 throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class));
 | |
|             }
 | |
|             $cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId);
 | |
| 
 | |
|             /*
 | |
|              * We send an invalidation Set-Cookie header (zero lifetime)
 | |
|              * when either the session was started or a cookie with
 | |
|              * the session name was sent by the client (in which case
 | |
|              * we know it's invalid as a valid session cookie would've
 | |
|              * started the session).
 | |
|              */
 | |
|             if (null === $cookie || isset($_COOKIE[$this->sessionName])) {
 | |
|                 $params = session_get_cookie_params();
 | |
|                 unset($params['lifetime']);
 | |
|                 setcookie($this->sessionName, '', $params);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return $this->newSessionId === $sessionId || $this->doDestroy($sessionId);
 | |
|     }
 | |
| }
 |