comparison vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents c2387f117808
children
comparison
equal deleted inserted replaced
16:c2387f117808 17:129ea1e6d783
24 class NativeSessionStorage implements SessionStorageInterface 24 class NativeSessionStorage implements SessionStorageInterface
25 { 25 {
26 /** 26 /**
27 * @var SessionBagInterface[] 27 * @var SessionBagInterface[]
28 */ 28 */
29 protected $bags = array(); 29 protected $bags = [];
30 30
31 /** 31 /**
32 * @var bool 32 * @var bool
33 */ 33 */
34 protected $started = false; 34 protected $started = false;
96 * 96 *
97 * @param array $options Session configuration options 97 * @param array $options Session configuration options
98 * @param \SessionHandlerInterface|null $handler 98 * @param \SessionHandlerInterface|null $handler
99 * @param MetadataBag $metaBag MetadataBag 99 * @param MetadataBag $metaBag MetadataBag
100 */ 100 */
101 public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null) 101 public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null)
102 { 102 {
103 $options += array( 103 $options += [
104 'cache_limiter' => '', 104 'cache_limiter' => '',
105 'cache_expire' => 0, 105 'cache_expire' => 0,
106 'use_cookies' => 1, 106 'use_cookies' => 1,
107 'lazy_write' => 1, 107 'lazy_write' => 1,
108 ); 108 ];
109 109
110 session_register_shutdown(); 110 session_register_shutdown();
111 111
112 $this->setMetadataBag($metaBag); 112 $this->setMetadataBag($metaBag);
113 $this->setOptions($options); 113 $this->setOptions($options);
135 135
136 if (\PHP_SESSION_ACTIVE === session_status()) { 136 if (\PHP_SESSION_ACTIVE === session_status()) {
137 throw new \RuntimeException('Failed to start the session: already started by PHP.'); 137 throw new \RuntimeException('Failed to start the session: already started by PHP.');
138 } 138 }
139 139
140 if (ini_get('session.use_cookies') && headers_sent($file, $line)) { 140 if (filter_var(ini_get('session.use_cookies'), FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
141 throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line)); 141 throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
142 } 142 }
143 143
144 // ok to try and start the session 144 // ok to try and start the session
145 if (!session_start()) { 145 if (!session_start()) {
224 foreach ($this->bags as $bag) { 224 foreach ($this->bags as $bag) {
225 if (empty($_SESSION[$key = $bag->getStorageKey()])) { 225 if (empty($_SESSION[$key = $bag->getStorageKey()])) {
226 unset($_SESSION[$key]); 226 unset($_SESSION[$key]);
227 } 227 }
228 } 228 }
229 if (array($key = $this->metadataBag->getStorageKey()) === array_keys($_SESSION)) { 229 if ([$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
230 unset($_SESSION[$key]); 230 unset($_SESSION[$key]);
231 } 231 }
232 232
233 // Register custom error handler to catch a possible failure warning during session write 233 // Register error handler to add information about the current save handler
234 set_error_handler(function ($errno, $errstr, $errfile, $errline) { 234 $previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) {
235 throw new \ErrorException($errstr, $errno, E_WARNING, $errfile, $errline); 235 if (E_WARNING === $type && 0 === strpos($msg, 'session_write_close():')) {
236 }, E_WARNING); 236 $handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler;
237 $msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', \get_class($handler));
238 }
239
240 return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false;
241 });
237 242
238 try { 243 try {
239 $e = null;
240 session_write_close(); 244 session_write_close();
241 } catch (\ErrorException $e) {
242 } finally { 245 } finally {
243 restore_error_handler(); 246 restore_error_handler();
244 $_SESSION = $session; 247 $_SESSION = $session;
245 } 248 }
246 if (null !== $e) {
247 // The default PHP error message is not very helpful, as it does not give any information on the current save handler.
248 // Therefore, we catch this error and trigger a warning with a better error message
249 $handler = $this->getSaveHandler();
250 if ($handler instanceof SessionHandlerProxy) {
251 $handler = $handler->getHandler();
252 }
253
254 trigger_error(sprintf('session_write_close(): Failed to write session data with %s handler', get_class($handler)), E_USER_WARNING);
255 }
256 249
257 $this->closed = true; 250 $this->closed = true;
258 $this->started = false; 251 $this->started = false;
259 } 252 }
260 253
267 foreach ($this->bags as $bag) { 260 foreach ($this->bags as $bag) {
268 $bag->clear(); 261 $bag->clear();
269 } 262 }
270 263
271 // clear out the session 264 // clear out the session
272 $_SESSION = array(); 265 $_SESSION = [];
273 266
274 // reconnect the bags to the session 267 // reconnect the bags to the session
275 $this->loadSession(); 268 $this->loadSession();
276 } 269 }
277 270
336 * Sets session.* ini variables. 329 * Sets session.* ini variables.
337 * 330 *
338 * For convenience we omit 'session.' from the beginning of the keys. 331 * For convenience we omit 'session.' from the beginning of the keys.
339 * Explicitly ignores other ini keys. 332 * Explicitly ignores other ini keys.
340 * 333 *
341 * @param array $options Session ini directives array(key => value) 334 * @param array $options Session ini directives [key => value]
342 * 335 *
343 * @see http://php.net/session.configuration 336 * @see http://php.net/session.configuration
344 */ 337 */
345 public function setOptions(array $options) 338 public function setOptions(array $options)
346 { 339 {
347 if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) { 340 if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) {
348 return; 341 return;
349 } 342 }
350 343
351 $validOptions = array_flip(array( 344 $validOptions = array_flip([
352 'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly', 345 'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly',
353 'cookie_lifetime', 'cookie_path', 'cookie_secure', 346 'cookie_lifetime', 'cookie_path', 'cookie_secure',
354 'entropy_file', 'entropy_length', 'gc_divisor', 347 'entropy_file', 'entropy_length', 'gc_divisor',
355 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', 348 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
356 'hash_function', 'lazy_write', 'name', 'referer_check', 349 'hash_function', 'lazy_write', 'name', 'referer_check',
357 'serialize_handler', 'use_strict_mode', 'use_cookies', 350 'serialize_handler', 'use_strict_mode', 'use_cookies',
358 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled', 351 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
359 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name', 352 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
360 'upload_progress.freq', 'upload_progress.min_freq', 'url_rewriter.tags', 353 'upload_progress.freq', 'upload_progress.min_freq', 'url_rewriter.tags',
361 'sid_length', 'sid_bits_per_character', 'trans_sid_hosts', 'trans_sid_tags', 354 'sid_length', 'sid_bits_per_character', 'trans_sid_hosts', 'trans_sid_tags',
362 )); 355 ]);
363 356
364 foreach ($options as $key => $value) { 357 foreach ($options as $key => $value) {
365 if (isset($validOptions[$key])) { 358 if (isset($validOptions[$key])) {
366 ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value); 359 ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value);
367 } 360 }
409 if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) { 402 if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) {
410 return; 403 return;
411 } 404 }
412 405
413 if ($this->saveHandler instanceof SessionHandlerProxy) { 406 if ($this->saveHandler instanceof SessionHandlerProxy) {
414 session_set_save_handler($this->saveHandler->getHandler(), false);
415 } elseif ($this->saveHandler instanceof \SessionHandlerInterface) {
416 session_set_save_handler($this->saveHandler, false); 407 session_set_save_handler($this->saveHandler, false);
417 } 408 }
418 } 409 }
419 410
420 /** 411 /**
429 { 420 {
430 if (null === $session) { 421 if (null === $session) {
431 $session = &$_SESSION; 422 $session = &$_SESSION;
432 } 423 }
433 424
434 $bags = array_merge($this->bags, array($this->metadataBag)); 425 $bags = array_merge($this->bags, [$this->metadataBag]);
435 426
436 foreach ($bags as $bag) { 427 foreach ($bags as $bag) {
437 $key = $bag->getStorageKey(); 428 $key = $bag->getStorageKey();
438 $session[$key] = isset($session[$key]) ? $session[$key] : array(); 429 $session[$key] = isset($session[$key]) ? $session[$key] : [];
439 $bag->initialize($session[$key]); 430 $bag->initialize($session[$key]);
440 } 431 }
441 432
442 $this->started = true; 433 $this->started = true;
443 $this->closed = false; 434 $this->closed = false;