26 public function __construct(\SessionHandlerInterface $sessionHandler =
null)
28 $this->sessionHandler = $sessionHandler;
31 session_register_shutdown();
32 if ($this->sessionHandler)
34 session_set_save_handler($this->sessionHandler,
false);
40 $this->lazyStartEnabled =
true;
47 $this->lazyStartEnabled =
false;
68 $this->ignoringSessionStartErrors =
true;
75 $this->ignoringSessionStartErrors =
false;
82 return session_status() === \PHP_SESSION_ACTIVE;
85 private function isHeadersSent(&$file, &$line): bool
87 return filter_var(ini_get(
'session.use_cookies'), FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line);
92 return !$this->isHeadersSent($file, $line);
104 throw new \RuntimeException(
'Could not change the ID of an active session');
112 return session_name();
119 throw new \RuntimeException(
'Could not change the name of an active session');
127 return $this->sessionHandler;
139 throw new \RuntimeException(
'Could not start session by PHP because session is active.');
142 if ($this->isHeadersSent($file, $line))
144 throw new \RuntimeException(
145 "Could not start session because headers have already been sent. \"{$file}\":{$line}."
149 $this->debug(
'Session tries to start at');
150 $this->detectFirstUsage();
155 if (!session_start() && !$this->ignoringSessionStartErrors)
157 throw new \RuntimeException(
'Could not start session by PHP.');
160 catch (\
Error $error)
162 if ($this->shouldLogError($error))
164 $this->writeToLogError($error);
167 if (!$this->ignoringSessionStartErrors)
169 throw $error->getPrevious() ?: $error;
172 $this->debug(
'Session started at');
174 $this->sessionData = &$_SESSION;
175 $this->started =
true;
177 if ($this->
has(
'destroyed'))
180 if ($this->
get(
'destroyed') < time() - 100)
186 $newSessionId = $this->
get(
'newSid');
189 $this->
setId($newSessionId);
191 return $this->
start();
200 $useStrictModeValue = $this->useStrictMode? 1 : 0;
206 'use_strict_mode' => $useStrictModeValue,
211 'cookie_httponly' => 1,
212 'use_strict_mode' => $useStrictModeValue,
218 $options[
'cookie_domain'] = $domain;
226 foreach ($settings as $name => $value)
228 ini_set(
"session.{$name}", $value);
232 private function writeToLogError(\
Error $error): void
235 $exceptionHandler->writeToLog($error);
237 if ($error->getPrevious())
239 $exceptionHandler->writeToLog($error->getPrevious());
243 private function shouldLogError(\Error $error): bool
245 if (!$error->getPrevious())
250 if (str_starts_with($error->getPrevious()->getMessage(), AbstractSessionHandler::LOCK_ERROR_MESSAGE))
265 $newSessionId = session_create_id();
267 $this->
set(
'newSid', $newSessionId);
268 $this->
set(
'destroyed', time());
270 $backup = $this->sessionData;
273 $this->disableStrictMode();
274 $this->
setId($newSessionId);
284 $this->enableStrictMode();
288 $this->
remove(
'newSid');
289 $this->
remove(
'destroyed');
299 $this->started =
false;
307 $this->sessionHandler->turnOffReleaseLockAfterCloseSession();
309 $this->sessionHandler->turnOnReleaseLockAfterCloseSession();
319 $session = $_SESSION;
321 $previousHandler = set_error_handler(
322 function($type, $msg, $file, $line) use (&$previousHandler) {
323 if ($type === E_WARNING && str_starts_with($msg,
'session_write_close():'))
325 $handler = $this->sessionHandler;
327 "session_write_close(): Failed to write session data with \"%s\" handler",
328 $handler? \get_class($handler) :
''
332 return $previousHandler ? $previousHandler($type, $msg, $file, $line) :
false;
339 session_write_close();
343 restore_error_handler();
346 $_SESSION = $session;
350 $this->started =
false;
355 if (!$this->lazyStartEnabled)
364 return $this->
start();
370 $this->nullPointers = [];
375 return $this->started;
383 return $this->debugger;
386 private function debug(
string $text): void
393 $this->getDebugger()->logToFile($text);
396 private function detectFirstUsage(): void
403 $this->getDebugger()->detectFirstUsage();
406 private function enableStrictMode(): self
408 $this->useStrictMode =
true;
413 private function disableStrictMode(): self
415 ini_set(
'session.use_strict_mode', 0);
416 $this->useStrictMode =
false;
disableIgnoringSessionStartErrors()
bool $ignoringSessionStartErrors
__construct(\SessionHandlerInterface $sessionHandler=null)
enableIgnoringSessionStartErrors()
applySessionStartIniSettings(array $settings)
SessionHandlerInterface $sessionHandler
refineReferencesBeforeSave()
trait ArrayAccessWithReferences