30 session_register_shutdown();
31 if ($this->sessionHandler)
33 session_set_save_handler($this->sessionHandler,
false);
39 $this->lazyStartEnabled =
true;
46 $this->lazyStartEnabled =
false;
67 $this->ignoringSessionStartErrors =
true;
74 $this->ignoringSessionStartErrors =
false;
81 return session_status() === \PHP_SESSION_ACTIVE;
84 private function isHeadersSent(&$file, &$line): bool
86 return filter_var(ini_get(
'session.use_cookies'), FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line);
91 return !$this->isHeadersSent($file, $line);
99 public function setId($id): void
103 throw new \RuntimeException(
'Could not change the ID of an active session');
111 return session_name();
118 throw new \RuntimeException(
'Could not change the name of an active session');
126 return $this->sessionHandler;
138 throw new \RuntimeException(
'Could not start session by PHP because session is active.');
141 if ($this->isHeadersSent($file, $line))
143 throw new \RuntimeException(
144 "Could not start session because headers have already been sent. \"{$file}\":{$line}."
148 $this->
debug(
'Session tries to start at');
149 $this->detectFirstUsage();
154 if (!session_start() && !$this->ignoringSessionStartErrors)
156 throw new \RuntimeException(
'Could not start session by PHP.');
161 if ($this->shouldLogError(
$error))
163 $this->writeToLogError(
$error);
166 if (!$this->ignoringSessionStartErrors)
171 $this->
debug(
'Session started at');
173 $this->sessionData = &$_SESSION;
174 $this->started =
true;
176 if ($this->
has(
'destroyed'))
179 if ($this->
get(
'destroyed') < time() - 100)
185 $newSessionId = $this->
get(
'newSid');
188 $this->
setId($newSessionId);
190 return $this->
start();
199 $useStrictModeValue = $this->useStrictMode? 1 : 0;
205 'use_strict_mode' => $useStrictModeValue,
210 'cookie_httponly' => 1,
211 'use_strict_mode' => $useStrictModeValue,
214 $domain = Cookie::getCookieDomain();
217 $options[
'cookie_domain'] = $domain;
227 ini_set(
"session.{$name}", $value);
231 private function writeToLogError(\
Error $error): void
234 $exceptionHandler->writeToLog(
$error);
236 if (
$error->getPrevious())
238 $exceptionHandler->writeToLog(
$error->getPrevious());
242 private function shouldLogError(\Error
$error): bool
244 if (!
$error->getPrevious())
249 if (str_starts_with(
$error->getPrevious()->getMessage(), AbstractSessionHandler::LOCK_ERROR_MESSAGE))
264 $newSessionId = session_create_id();
266 $this->
set(
'newSid', $newSessionId);
267 $this->
set(
'destroyed', time());
269 $backup = $this->sessionData;
272 $this->disableStrictMode();
273 $this->
setId($newSessionId);
283 $this->enableStrictMode();
287 $this->
remove(
'newSid');
288 $this->
remove(
'destroyed');
298 $this->started =
false;
306 $this->sessionHandler->turnOffReleaseLockAfterCloseSession();
308 $this->sessionHandler->turnOnReleaseLockAfterCloseSession();
318 $session = $_SESSION;
320 $previousHandler = set_error_handler(
321 function(
$type, $msg, $file, $line) use (&$previousHandler) {
322 if (
$type === E_WARNING && str_starts_with($msg,
'session_write_close():'))
324 $handler = $this->sessionHandler;
326 "session_write_close(): Failed to write session data with \"%s\" handler",
327 $handler? \get_class($handler) :
''
331 return $previousHandler ? $previousHandler(
$type, $msg, $file, $line) :
false;
338 session_write_close();
342 restore_error_handler();
345 $_SESSION = $session;
349 $this->started =
false;
354 if (!$this->lazyStartEnabled)
363 return $this->
start();
369 $this->nullPointers = [];
374 return $this->started;
382 return $this->debugger;
392 $this->getDebugger()->logToFile(
$text);
395 private function detectFirstUsage(): void
402 $this->getDebugger()->detectFirstUsage();
405 private function enableStrictMode(): self
407 $this->useStrictMode =
true;
412 private function disableStrictMode(): self
414 ini_set(
'session.use_strict_mode', 0);
415 $this->useStrictMode =
false;
disableIgnoringSessionStartErrors()
bool $ignoringSessionStartErrors
__construct(\SessionHandlerInterface $sessionHandler=null)
enableIgnoringSessionStartErrors()
applySessionStartIniSettings(array $settings)
SessionHandlerInterface $sessionHandler
refineReferencesBeforeSave()
trait ArrayAccessWithReferences