Sessions Advanced

By the end of this lesson you'll move sessions out of single-server files and into shared storage with a custom handler, tune and secure the session cookie, avoid the locking trap that slows AJAX pages, defend against fixation and hijacking, and weigh stateless JWTs against server-side sessions.

Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.

Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Custom Session Handlers (scaling across servers)

PHP's default sessions are files saved on the one server that handled the request. The moment you run a second server behind a load balancer — a router that spreads traffic across machines — the next request can hit a different box where that file doesn't exist, and the user looks logged out. The fix is to store sessions somewhere every server can reach. You do that by implementing SessionHandlerInterface : a class with six methods PHP calls for you ( open , close , read , write , destroy , gc ), then registering it with session_set_save_handler() before session_start() .

From your code's point of view nothing changes — you still read and write $_SESSION exactly as before. PHP simply routes the storage through your handler. The gc() method is your cleanup: PHP calls it occasionally to delete expired rows so the table doesn't grow forever.

2️⃣ Redis Sessions & Configuration

Redis is an in-memory data store, which makes it the fastest session backend. The best part: PHP ships with a Redis session handler, so you usually write no code at all — you just point session.save_handler and session.save_path at your Redis server. Beyond the backend, a handful of session.* settings control how long data lives ( gc_maxlifetime ) and how the cookie behaves ( cookie_lifetime , cookie_httponly , cookie_secure , cookie_samesite ). Set them before session_start() .

3️⃣ Session Locking & the Read-then-Write-Close Pattern

Here's a trap that surprises everyone. While a request holds the session open, PHP locks it so two requests can't clobber the data by writing at once. Any other request from the same user waits until the first one finishes or calls session_write_close() . On a page firing several AJAX calls together, they quietly run one-after-another instead of in parallel — and it just feels slow. The cure is the read-then-write-close pattern: do all your $_SESSION writes up front, call session_write_close() to release the lock, then do the slow work.

After session_write_close() you can still read $_SESSION from memory — you just can't save changes to storage. So write first, close, then read freely while the heavy lifting happens unblocked.

4️⃣ Session Security: Fixation & Hijacking

Two attacks target sessions directly. In fixation , an attacker plants a session id they already know on a victim (say, via a link); when the victim logs in, the attacker shares that authenticated session. The single defence is to issue a fresh id the moment privileges change — session_regenerate_id(true) right after login, where true deletes the old session. In hijacking , an attacker steals a valid session id (often via XSS or an insecure cookie). You raise the bar by binding the session to a fingerprint — the client's IP and user-agent — and dropping it if that fingerprint suddenly changes.

Pair this with the secure cookie flags from Section 2 ( HttpOnly stops JavaScript reading the cookie, Secure keeps it on HTTPS, SameSite blunts CSRF) and most session attacks lose their footing.

5️⃣ Stateless Alternatives (JWT) & Trade-offs

There's a different model entirely: store nothing on the server. A JWT (JSON Web Token) is a small signed token the client carries in a cookie or header. Because it's signed with a secret using hash_hmac , the server can verify it wasn't tampered with — no database lookup needed. That scales effortlessly and suits APIs. The catch is real: you can't instantly revoke a JWT (it's valid until it expires), and stuffing data into it bloats every request. Server-side sessions are the mirror image — easy to revoke (delete the row), tiny cookie — but they need shared storage. Verify signatures with hash_equals() , which is timing-safe; never use === .

Now you try. The login below is almost complete — fill in each ___ using the 👉 hint, then run it and check it against the Output panel.

One more — the locking pattern in practice. Add the call that releases the lock before the slow work, following the 👉 hint.

📋 Quick Reference — Advanced Sessions

No code is filled in this time — just a brief and an outline. Build a minimal stateless token from scratch, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments. This is the same sign-then-verify loop every JWT library does under the hood.

Practice quiz

Why do file-based sessions break behind a load balancer?

  • Files are too slow to read
  • PHP disables sessions on multiple servers
  • Each session file lives on one server, so another server can't find it
  • Load balancers delete session files

Answer: Each session file lives on one server, so another server can't find it. Default sessions are files on the machine that handled the request; a different server won't have that file, so the user looks logged out.

What do you implement to store sessions in a database or Redis?

  • SessionHandlerInterface
  • SessionStorageTrait
  • PDOSessionAdapter
  • SaveHandlerAbstract

Answer: SessionHandlerInterface. A custom save handler is a class implementing SessionHandlerInterface (open, close, read, write, destroy, gc).

When must session_set_save_handler() be called?

  • After session_start()
  • Inside the write() method
  • Only on logout
  • Before session_start()

Answer: Before session_start(). Register the handler first; then session_start() routes all $_SESSION reads and writes through it.

For Redis-backed sessions, how do you usually configure PHP?

  • Write a full custom handler class
  • Set session.save_handler = redis and session.save_path to the Redis URL
  • Call redis_session_start()
  • Redis cannot store PHP sessions

Answer: Set session.save_handler = redis and session.save_path to the Redis URL. PHP ships with a Redis session handler, so you point session.save_handler and session.save_path at Redis - no code needed.

Why can AJAX-heavy pages feel slow due to sessions?

  • Session locking serialises requests from the same user until the lock releases
  • Sessions encrypt every request
  • AJAX disables caching
  • Each request creates a new session id

Answer: Session locking serialises requests from the same user until the lock releases. PHP locks an open session, so concurrent requests from the same user wait in line until session_write_close() or the request ends.

Which call releases the session lock early so other requests proceed?

  • session_destroy()
  • session_unset()
  • session_write_close()
  • session_abort()

Answer: session_write_close(). Do your $_SESSION writes up front, then session_write_close() to free the lock before slow work; you can still read $_SESSION from memory.

What is session fixation?

  • Storing too much data in the session
  • An attacker plants a known session id on a victim who then logs in with it
  • The session id never changing across requests by design
  • A corrupted session file

Answer: An attacker plants a known session id on a victim who then logs in with it. If the victim authenticates using an id the attacker already knows, the attacker rides that authenticated session.

How do you defeat session fixation on login?

  • Call session_destroy() before login
  • Set a longer cookie lifetime
  • Store the password in the session
  • Call session_regenerate_id(true) so the old session is replaced and deleted

Answer: Call session_regenerate_id(true) so the old session is replaced and deleted. Regenerating the id the moment privileges change issues a fresh id and deletes the old one, so a planted id is useless.

What is a key trade-off of stateless JWTs versus server-side sessions?

  • JWTs are always more secure
  • You cannot instantly revoke a JWT; it stays valid until it expires
  • JWTs require a shared database to scale
  • Sessions cannot be revoked at all

Answer: You cannot instantly revoke a JWT; it stays valid until it expires. JWTs scale without server storage but can't be revoked on demand; sessions are easy to revoke (delete the row) but need shared storage.

Which function safely compares a token signature against the expected one?

  • ===
  • strcmp()
  • hash_equals($expected, $sig)
  • md5_compare()

Answer: hash_equals($expected, $sig). hash_equals() is timing-safe, so it doesn't leak information about the secret the way === can.