From e4f5faad0f3e85dc0c62e0df4b7ac61079928fa5 Mon Sep 17 00:00:00 2001 From: Torben Dannhauer Date: Tue, 16 Jun 2026 22:21:50 +0200 Subject: [PATCH] fix(session): guard session_destroy() when no active PHP session Horde_Session initializes $_SESSION to [] in its constructor before session_start() runs. SessionLifecycle::destroy() and the legacy Horde_Session::destroy() fallback used isset($_SESSION) as the guard, which is always true once the shim is constructed. That caused repeated PHP warnings: session_destroy(): Trying to destroy uninitialized session Replace the isset($_SESSION) check with session_status() === PHP_SESSION_ACTIVE. SessionLifecycle also consults $this->active so the normal lifecycle path remains covered when the local flag is authoritative. --- lib/Horde/Session.php | 2 +- src/Session/SessionLifecycle.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/Horde/Session.php b/lib/Horde/Session.php index 475d25ab..02159dec 100644 --- a/lib/Horde/Session.php +++ b/lib/Horde/Session.php @@ -555,7 +555,7 @@ public function destroy() } /* Fallback for legacy/test contexts without an injector. */ - if (isset($_SESSION)) { + if (session_status() === PHP_SESSION_ACTIVE) { session_destroy(); } $_SESSION = []; diff --git a/src/Session/SessionLifecycle.php b/src/Session/SessionLifecycle.php index e32176e3..702fee61 100644 --- a/src/Session/SessionLifecycle.php +++ b/src/Session/SessionLifecycle.php @@ -311,7 +311,10 @@ public function clean(): bool */ public function destroy(): void { - if (isset($_SESSION)) { + // $_SESSION may be initialised (Horde_Session constructor sets it to + // []) without an active PHP session. session_status() is the + // authoritative guard; $this->active mirrors it for the normal path. + if ($this->active || session_status() === PHP_SESSION_ACTIVE) { session_destroy(); } $_SESSION = [];