annotate vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php @ 12:7a779792577d

Update Drupal core to v8.4.5 (via Composer)
author Chris Cannam
date Fri, 23 Feb 2018 15:52:07 +0000
parents 4c8ae668cc8c
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\HttpFoundation\Session\Storage;
Chris@0 13
Chris@0 14 use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
Chris@0 15 use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
Chris@0 16 use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
Chris@0 17 use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
Chris@0 18
Chris@0 19 /**
Chris@0 20 * This provides a base class for session attribute storage.
Chris@0 21 *
Chris@0 22 * @author Drak <drak@zikula.org>
Chris@0 23 */
Chris@0 24 class NativeSessionStorage implements SessionStorageInterface
Chris@0 25 {
Chris@0 26 /**
Chris@0 27 * Array of SessionBagInterface.
Chris@0 28 *
Chris@0 29 * @var SessionBagInterface[]
Chris@0 30 */
Chris@0 31 protected $bags;
Chris@0 32
Chris@0 33 /**
Chris@0 34 * @var bool
Chris@0 35 */
Chris@0 36 protected $started = false;
Chris@0 37
Chris@0 38 /**
Chris@0 39 * @var bool
Chris@0 40 */
Chris@0 41 protected $closed = false;
Chris@0 42
Chris@0 43 /**
Chris@0 44 * @var AbstractProxy
Chris@0 45 */
Chris@0 46 protected $saveHandler;
Chris@0 47
Chris@0 48 /**
Chris@0 49 * @var MetadataBag
Chris@0 50 */
Chris@0 51 protected $metadataBag;
Chris@0 52
Chris@0 53 /**
Chris@0 54 * Constructor.
Chris@0 55 *
Chris@0 56 * Depending on how you want the storage driver to behave you probably
Chris@0 57 * want to override this constructor entirely.
Chris@0 58 *
Chris@0 59 * List of options for $options array with their defaults.
Chris@0 60 *
Chris@0 61 * @see http://php.net/session.configuration for options
Chris@0 62 * but we omit 'session.' from the beginning of the keys for convenience.
Chris@0 63 *
Chris@0 64 * ("auto_start", is not supported as it tells PHP to start a session before
Chris@0 65 * PHP starts to execute user-land code. Setting during runtime has no effect).
Chris@0 66 *
Chris@0 67 * cache_limiter, "" (use "0" to prevent headers from being sent entirely).
Chris@0 68 * cookie_domain, ""
Chris@0 69 * cookie_httponly, ""
Chris@0 70 * cookie_lifetime, "0"
Chris@0 71 * cookie_path, "/"
Chris@0 72 * cookie_secure, ""
Chris@0 73 * entropy_file, ""
Chris@0 74 * entropy_length, "0"
Chris@0 75 * gc_divisor, "100"
Chris@0 76 * gc_maxlifetime, "1440"
Chris@0 77 * gc_probability, "1"
Chris@0 78 * hash_bits_per_character, "4"
Chris@0 79 * hash_function, "0"
Chris@0 80 * name, "PHPSESSID"
Chris@0 81 * referer_check, ""
Chris@0 82 * serialize_handler, "php"
Chris@0 83 * use_strict_mode, "0"
Chris@0 84 * use_cookies, "1"
Chris@0 85 * use_only_cookies, "1"
Chris@0 86 * use_trans_sid, "0"
Chris@0 87 * upload_progress.enabled, "1"
Chris@0 88 * upload_progress.cleanup, "1"
Chris@0 89 * upload_progress.prefix, "upload_progress_"
Chris@0 90 * upload_progress.name, "PHP_SESSION_UPLOAD_PROGRESS"
Chris@0 91 * upload_progress.freq, "1%"
Chris@0 92 * upload_progress.min-freq, "1"
Chris@0 93 * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
Chris@12 94 * sid_length, "32"
Chris@12 95 * sid_bits_per_character, "5"
Chris@12 96 * trans_sid_hosts, $_SERVER['HTTP_HOST']
Chris@12 97 * trans_sid_tags, "a=href,area=href,frame=src,form="
Chris@0 98 *
Chris@0 99 * @param array $options Session configuration options
Chris@0 100 * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $handler
Chris@0 101 * @param MetadataBag $metaBag MetadataBag
Chris@0 102 */
Chris@0 103 public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null)
Chris@0 104 {
Chris@0 105 session_cache_limiter(''); // disable by default because it's managed by HeaderBag (if used)
Chris@0 106 ini_set('session.use_cookies', 1);
Chris@0 107
Chris@0 108 session_register_shutdown();
Chris@0 109
Chris@0 110 $this->setMetadataBag($metaBag);
Chris@0 111 $this->setOptions($options);
Chris@0 112 $this->setSaveHandler($handler);
Chris@0 113 }
Chris@0 114
Chris@0 115 /**
Chris@0 116 * Gets the save handler instance.
Chris@0 117 *
Chris@0 118 * @return AbstractProxy
Chris@0 119 */
Chris@0 120 public function getSaveHandler()
Chris@0 121 {
Chris@0 122 return $this->saveHandler;
Chris@0 123 }
Chris@0 124
Chris@0 125 /**
Chris@0 126 * {@inheritdoc}
Chris@0 127 */
Chris@0 128 public function start()
Chris@0 129 {
Chris@0 130 if ($this->started) {
Chris@0 131 return true;
Chris@0 132 }
Chris@0 133
Chris@0 134 if (\PHP_SESSION_ACTIVE === session_status()) {
Chris@0 135 throw new \RuntimeException('Failed to start the session: already started by PHP.');
Chris@0 136 }
Chris@0 137
Chris@0 138 if (ini_get('session.use_cookies') && headers_sent($file, $line)) {
Chris@0 139 throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
Chris@0 140 }
Chris@0 141
Chris@0 142 // ok to try and start the session
Chris@0 143 if (!session_start()) {
Chris@0 144 throw new \RuntimeException('Failed to start the session');
Chris@0 145 }
Chris@0 146
Chris@0 147 $this->loadSession();
Chris@0 148
Chris@0 149 return true;
Chris@0 150 }
Chris@0 151
Chris@0 152 /**
Chris@0 153 * {@inheritdoc}
Chris@0 154 */
Chris@0 155 public function getId()
Chris@0 156 {
Chris@0 157 return $this->saveHandler->getId();
Chris@0 158 }
Chris@0 159
Chris@0 160 /**
Chris@0 161 * {@inheritdoc}
Chris@0 162 */
Chris@0 163 public function setId($id)
Chris@0 164 {
Chris@0 165 $this->saveHandler->setId($id);
Chris@0 166 }
Chris@0 167
Chris@0 168 /**
Chris@0 169 * {@inheritdoc}
Chris@0 170 */
Chris@0 171 public function getName()
Chris@0 172 {
Chris@0 173 return $this->saveHandler->getName();
Chris@0 174 }
Chris@0 175
Chris@0 176 /**
Chris@0 177 * {@inheritdoc}
Chris@0 178 */
Chris@0 179 public function setName($name)
Chris@0 180 {
Chris@0 181 $this->saveHandler->setName($name);
Chris@0 182 }
Chris@0 183
Chris@0 184 /**
Chris@0 185 * {@inheritdoc}
Chris@0 186 */
Chris@0 187 public function regenerate($destroy = false, $lifetime = null)
Chris@0 188 {
Chris@0 189 // Cannot regenerate the session ID for non-active sessions.
Chris@0 190 if (\PHP_SESSION_ACTIVE !== session_status()) {
Chris@0 191 return false;
Chris@0 192 }
Chris@0 193
Chris@0 194 if (null !== $lifetime) {
Chris@0 195 ini_set('session.cookie_lifetime', $lifetime);
Chris@0 196 }
Chris@0 197
Chris@0 198 if ($destroy) {
Chris@0 199 $this->metadataBag->stampNew();
Chris@0 200 }
Chris@0 201
Chris@0 202 $isRegenerated = session_regenerate_id($destroy);
Chris@0 203
Chris@0 204 // The reference to $_SESSION in session bags is lost in PHP7 and we need to re-create it.
Chris@0 205 // @see https://bugs.php.net/bug.php?id=70013
Chris@0 206 $this->loadSession();
Chris@0 207
Chris@0 208 return $isRegenerated;
Chris@0 209 }
Chris@0 210
Chris@0 211 /**
Chris@0 212 * {@inheritdoc}
Chris@0 213 */
Chris@0 214 public function save()
Chris@0 215 {
Chris@0 216 session_write_close();
Chris@0 217
Chris@0 218 $this->closed = true;
Chris@0 219 $this->started = false;
Chris@0 220 }
Chris@0 221
Chris@0 222 /**
Chris@0 223 * {@inheritdoc}
Chris@0 224 */
Chris@0 225 public function clear()
Chris@0 226 {
Chris@0 227 // clear out the bags
Chris@0 228 foreach ($this->bags as $bag) {
Chris@0 229 $bag->clear();
Chris@0 230 }
Chris@0 231
Chris@0 232 // clear out the session
Chris@0 233 $_SESSION = array();
Chris@0 234
Chris@0 235 // reconnect the bags to the session
Chris@0 236 $this->loadSession();
Chris@0 237 }
Chris@0 238
Chris@0 239 /**
Chris@0 240 * {@inheritdoc}
Chris@0 241 */
Chris@0 242 public function registerBag(SessionBagInterface $bag)
Chris@0 243 {
Chris@0 244 if ($this->started) {
Chris@0 245 throw new \LogicException('Cannot register a bag when the session is already started.');
Chris@0 246 }
Chris@0 247
Chris@0 248 $this->bags[$bag->getName()] = $bag;
Chris@0 249 }
Chris@0 250
Chris@0 251 /**
Chris@0 252 * {@inheritdoc}
Chris@0 253 */
Chris@0 254 public function getBag($name)
Chris@0 255 {
Chris@0 256 if (!isset($this->bags[$name])) {
Chris@0 257 throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
Chris@0 258 }
Chris@0 259
Chris@0 260 if ($this->saveHandler->isActive() && !$this->started) {
Chris@0 261 $this->loadSession();
Chris@0 262 } elseif (!$this->started) {
Chris@0 263 $this->start();
Chris@0 264 }
Chris@0 265
Chris@0 266 return $this->bags[$name];
Chris@0 267 }
Chris@0 268
Chris@0 269 /**
Chris@0 270 * Sets the MetadataBag.
Chris@0 271 *
Chris@0 272 * @param MetadataBag $metaBag
Chris@0 273 */
Chris@0 274 public function setMetadataBag(MetadataBag $metaBag = null)
Chris@0 275 {
Chris@0 276 if (null === $metaBag) {
Chris@0 277 $metaBag = new MetadataBag();
Chris@0 278 }
Chris@0 279
Chris@0 280 $this->metadataBag = $metaBag;
Chris@0 281 }
Chris@0 282
Chris@0 283 /**
Chris@0 284 * Gets the MetadataBag.
Chris@0 285 *
Chris@0 286 * @return MetadataBag
Chris@0 287 */
Chris@0 288 public function getMetadataBag()
Chris@0 289 {
Chris@0 290 return $this->metadataBag;
Chris@0 291 }
Chris@0 292
Chris@0 293 /**
Chris@0 294 * {@inheritdoc}
Chris@0 295 */
Chris@0 296 public function isStarted()
Chris@0 297 {
Chris@0 298 return $this->started;
Chris@0 299 }
Chris@0 300
Chris@0 301 /**
Chris@0 302 * Sets session.* ini variables.
Chris@0 303 *
Chris@0 304 * For convenience we omit 'session.' from the beginning of the keys.
Chris@0 305 * Explicitly ignores other ini keys.
Chris@0 306 *
Chris@0 307 * @param array $options Session ini directives array(key => value)
Chris@0 308 *
Chris@0 309 * @see http://php.net/session.configuration
Chris@0 310 */
Chris@0 311 public function setOptions(array $options)
Chris@0 312 {
Chris@0 313 $validOptions = array_flip(array(
Chris@0 314 'cache_limiter', 'cookie_domain', 'cookie_httponly',
Chris@0 315 'cookie_lifetime', 'cookie_path', 'cookie_secure',
Chris@0 316 'entropy_file', 'entropy_length', 'gc_divisor',
Chris@0 317 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
Chris@0 318 'hash_function', 'name', 'referer_check',
Chris@0 319 'serialize_handler', 'use_strict_mode', 'use_cookies',
Chris@0 320 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
Chris@0 321 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
Chris@0 322 'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags',
Chris@12 323 'sid_length', 'sid_bits_per_character', 'trans_sid_hosts', 'trans_sid_tags',
Chris@0 324 ));
Chris@0 325
Chris@0 326 foreach ($options as $key => $value) {
Chris@0 327 if (isset($validOptions[$key])) {
Chris@0 328 ini_set('session.'.$key, $value);
Chris@0 329 }
Chris@0 330 }
Chris@0 331 }
Chris@0 332
Chris@0 333 /**
Chris@0 334 * Registers session save handler as a PHP session handler.
Chris@0 335 *
Chris@0 336 * To use internal PHP session save handlers, override this method using ini_set with
Chris@0 337 * session.save_handler and session.save_path e.g.
Chris@0 338 *
Chris@0 339 * ini_set('session.save_handler', 'files');
Chris@0 340 * ini_set('session.save_path', '/tmp');
Chris@0 341 *
Chris@0 342 * or pass in a NativeSessionHandler instance which configures session.save_handler in the
Chris@0 343 * constructor, for a template see NativeFileSessionHandler or use handlers in
Chris@0 344 * composer package drak/native-session
Chris@0 345 *
Chris@0 346 * @see http://php.net/session-set-save-handler
Chris@0 347 * @see http://php.net/sessionhandlerinterface
Chris@0 348 * @see http://php.net/sessionhandler
Chris@0 349 * @see http://github.com/drak/NativeSession
Chris@0 350 *
Chris@0 351 * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $saveHandler
Chris@0 352 *
Chris@0 353 * @throws \InvalidArgumentException
Chris@0 354 */
Chris@0 355 public function setSaveHandler($saveHandler = null)
Chris@0 356 {
Chris@0 357 if (!$saveHandler instanceof AbstractProxy &&
Chris@0 358 !$saveHandler instanceof NativeSessionHandler &&
Chris@0 359 !$saveHandler instanceof \SessionHandlerInterface &&
Chris@0 360 null !== $saveHandler) {
Chris@0 361 throw new \InvalidArgumentException('Must be instance of AbstractProxy or NativeSessionHandler; implement \SessionHandlerInterface; or be null.');
Chris@0 362 }
Chris@0 363
Chris@0 364 // Wrap $saveHandler in proxy and prevent double wrapping of proxy
Chris@0 365 if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
Chris@0 366 $saveHandler = new SessionHandlerProxy($saveHandler);
Chris@0 367 } elseif (!$saveHandler instanceof AbstractProxy) {
Chris@0 368 $saveHandler = new SessionHandlerProxy(new \SessionHandler());
Chris@0 369 }
Chris@0 370 $this->saveHandler = $saveHandler;
Chris@0 371
Chris@0 372 if ($this->saveHandler instanceof \SessionHandlerInterface) {
Chris@0 373 session_set_save_handler($this->saveHandler, false);
Chris@0 374 }
Chris@0 375 }
Chris@0 376
Chris@0 377 /**
Chris@0 378 * Load the session with attributes.
Chris@0 379 *
Chris@0 380 * After starting the session, PHP retrieves the session from whatever handlers
Chris@0 381 * are set to (either PHP's internal, or a custom save handler set with session_set_save_handler()).
Chris@0 382 * PHP takes the return value from the read() handler, unserializes it
Chris@0 383 * and populates $_SESSION with the result automatically.
Chris@0 384 *
Chris@0 385 * @param array|null $session
Chris@0 386 */
Chris@0 387 protected function loadSession(array &$session = null)
Chris@0 388 {
Chris@0 389 if (null === $session) {
Chris@0 390 $session = &$_SESSION;
Chris@0 391 }
Chris@0 392
Chris@0 393 $bags = array_merge($this->bags, array($this->metadataBag));
Chris@0 394
Chris@0 395 foreach ($bags as $bag) {
Chris@0 396 $key = $bag->getStorageKey();
Chris@0 397 $session[$key] = isset($session[$key]) ? $session[$key] : array();
Chris@0 398 $bag->initialize($session[$key]);
Chris@0 399 }
Chris@0 400
Chris@0 401 $this->started = true;
Chris@0 402 $this->closed = false;
Chris@0 403 }
Chris@0 404 }