6ae1355816fdbb2d9fa45aaf7681b291b1b3ddd5
[yaffs-website] / vendor / symfony / http-foundation / Session / Storage / Handler / AbstractSessionHandler.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
13
14 /**
15  * This abstract session handler provides a generic implementation
16  * of the PHP 7.0 SessionUpdateTimestampHandlerInterface,
17  * enabling strict and lazy session handling.
18  *
19  * @author Nicolas Grekas <p@tchwork.com>
20  */
21 abstract class AbstractSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
22 {
23     private $sessionName;
24     private $prefetchId;
25     private $prefetchData;
26     private $newSessionId;
27     private $igbinaryEmptyData;
28
29     /**
30      * {@inheritdoc}
31      */
32     public function open($savePath, $sessionName)
33     {
34         $this->sessionName = $sessionName;
35         if (!headers_sent() && !ini_get('session.cache_limiter') && '0' !== ini_get('session.cache_limiter')) {
36             header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) ini_get('session.cache_expire')));
37         }
38
39         return true;
40     }
41
42     /**
43      * @param string $sessionId
44      *
45      * @return string
46      */
47     abstract protected function doRead($sessionId);
48
49     /**
50      * @param string $sessionId
51      * @param string $data
52      *
53      * @return bool
54      */
55     abstract protected function doWrite($sessionId, $data);
56
57     /**
58      * @param string $sessionId
59      *
60      * @return bool
61      */
62     abstract protected function doDestroy($sessionId);
63
64     /**
65      * {@inheritdoc}
66      */
67     public function validateId($sessionId)
68     {
69         $this->prefetchData = $this->read($sessionId);
70         $this->prefetchId = $sessionId;
71
72         return '' !== $this->prefetchData;
73     }
74
75     /**
76      * {@inheritdoc}
77      */
78     public function read($sessionId)
79     {
80         if (null !== $this->prefetchId) {
81             $prefetchId = $this->prefetchId;
82             $prefetchData = $this->prefetchData;
83             $this->prefetchId = $this->prefetchData = null;
84
85             if ($prefetchId === $sessionId || '' === $prefetchData) {
86                 $this->newSessionId = '' === $prefetchData ? $sessionId : null;
87
88                 return $prefetchData;
89             }
90         }
91
92         $data = $this->doRead($sessionId);
93         $this->newSessionId = '' === $data ? $sessionId : null;
94         if (\PHP_VERSION_ID < 70000) {
95             $this->prefetchData = $data;
96         }
97
98         return $data;
99     }
100
101     /**
102      * {@inheritdoc}
103      */
104     public function write($sessionId, $data)
105     {
106         if (\PHP_VERSION_ID < 70000 && $this->prefetchData) {
107             $readData = $this->prefetchData;
108             $this->prefetchData = null;
109
110             if ($readData === $data) {
111                 return $this->updateTimestamp($sessionId, $data);
112             }
113         }
114         if (null === $this->igbinaryEmptyData) {
115             // see https://github.com/igbinary/igbinary/issues/146
116             $this->igbinaryEmptyData = \function_exists('igbinary_serialize') ? igbinary_serialize(array()) : '';
117         }
118         if ('' === $data || $this->igbinaryEmptyData === $data) {
119             return $this->destroy($sessionId);
120         }
121         $this->newSessionId = null;
122
123         return $this->doWrite($sessionId, $data);
124     }
125
126     /**
127      * {@inheritdoc}
128      */
129     public function destroy($sessionId)
130     {
131         if (\PHP_VERSION_ID < 70000) {
132             $this->prefetchData = null;
133         }
134         if (!headers_sent() && ini_get('session.use_cookies')) {
135             if (!$this->sessionName) {
136                 throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', get_class($this)));
137             }
138             $sessionCookie = sprintf(' %s=', urlencode($this->sessionName));
139             $sessionCookieWithId = sprintf('%s%s;', $sessionCookie, urlencode($sessionId));
140             $sessionCookieFound = false;
141             $otherCookies = array();
142             foreach (headers_list() as $h) {
143                 if (0 !== stripos($h, 'Set-Cookie:')) {
144                     continue;
145                 }
146                 if (11 === strpos($h, $sessionCookie, 11)) {
147                     $sessionCookieFound = true;
148
149                     if (11 !== strpos($h, $sessionCookieWithId, 11)) {
150                         $otherCookies[] = $h;
151                     }
152                 } else {
153                     $otherCookies[] = $h;
154                 }
155             }
156             if ($sessionCookieFound) {
157                 header_remove('Set-Cookie');
158                 foreach ($otherCookies as $h) {
159                     header($h, false);
160                 }
161             } else {
162                 setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
163             }
164         }
165
166         return $this->newSessionId === $sessionId || $this->doDestroy($sessionId);
167     }
168 }