session-state-zombies

Session-State Zombies

December 29, 2025

Debugging PHP Session Bugs that Break Login, Logout, and Navigation

When a PHP application behaves like it’s logged in when it isn’t — or logged out when it shouldn’t be — you may be dealing with a session-state bug.

In this TFOL dev log, I ran into a particularly nasty version of that problem: Session-State Zombies — sessions that appear to be destroyed but keep coming back to life.

The result? Broken logout behavior, inconsistent navigation, failed admin pages, and “Page Not Found” errors that made no sense.


What Is a Session-State Zombie?

A session-state zombie occurs when:

  • A PHP session is destroyed correctly

  • But later code recreates or mutates the session unintentionally

  • Often during page rendering instead of authentication

The session looks valid — but it’s no longer trustworthy.

This creates subtle, cascading bugs that are hard to trace.


Common Symptoms of PHP Session Bugs

These are the warning signs I saw in TFOL:

  • Logout behaves like Refresh

  • Guest users can’t truly log out

  • Admin login succeeds but redirects to Page Not Found

  • Navigation menus change unpredictably

  • Splash screen briefly flashes Page Not Found

  • Story pages fail inconsistently

  • Role-based permissions behave incorrectly

If you’re seeing two or more of these, suspect your session lifecycle.


Root Cause: Session Creation in the Wrong Places

The real problem wasn’t routing or templates — it was session misuse.

Over time, TFOL accumulated many calls to:

$cms->getSession()->create(...)

These calls appeared in:

  • index.php

  • _include.php

  • login.php

  • settings.php

  • sort.php

  • story.php

  • Admin pages

  • Legacy “temporary fixes”

Each was added defensively to avoid undefined session variables.

The Critical Mistake

Sessions were being created during normal page loads.

That meant:

  • Logout destroyed the session

  • The next request quietly recreated it

  • Often with default or partial data

The session was never truly gone.


Correct PHP Session Lifecycle (The Fix)

The fix required one firm rule:

✅ Create sessions only during authentication

  • Successful login

  • Explicit guest initialization (once)

✅ Destroy sessions only during logout

  • One place

  • One responsibility

❌ Never create sessions during:

  • Page rendering

  • Navigation building

  • Template loading

  • “Just in case” checks

After cleanup, all pages simply read the session — they never rebuild it.


Why Session Bugs Are So Hard to Debug

Session bugs are dangerous because:

  • They don’t always trigger fatal errors

  • They survive redirects

  • They look like routing issues

  • They create false confidence

The application keeps running — but logic slowly unravels.

That’s why session bugs often get misdiagnosed as:

  • Twig problems

  • Controller bugs

  • Rewrite rule errors

  • Database issues


Key Lessons for PHP Developers

If you remember nothing else, remember this:

  1. PHP sessions are global state

  2. Global state must have a single owner

  3. Defensive session creation causes real bugs

  4. If Logout doesn’t log out, stop everything

  5. Routing problems often start with session problems


Final Result

After removing the session-state zombies:

  • Guest sessions behave correctly

  • Logout actually logs out

  • Admin login works again

  • Navigation is consistent

  • Story pages load reliably

  • Development velocity returned

The application finally reflects reality.


Final Thought

If your PHP app feels haunted, don’t start with routing.

Don’t blame templates.
Don’t blame JavaScript.

Audit your session lifecycle first.

Because session-state zombies — dead sessions that won’t stay dead —
are the hardest bugs to kill.


 

Posted in ghost-stories by TFOL BLOG

Comments