Course outline

PHP / Intermediate: objects, persistence, and tests / Lesson 11

Sessions, cookies, and state ownership

Understand a session as a server-side lifecycle associated with a client identifier. Separate authentication, authorization, cookie delivery, locking, and isolated session-storage evidence.

About 5 min readContent reviewed
On this page

Lesson goals

  • Explain session identity without treating it as permission.
  • Choose cookie and session security policies explicitly.
  • Limit lock duration and verify state lifecycle.

A session identifier refers to state; it is not the whole policy

PHP sessions associate a session identifier with stored state through a configured save handler. A browser commonly carries the identifier in a cookie, but cookie transport and server storage are separate mechanisms. Possessing an identifier must not be confused with permission for every object or action. Authentication establishes an account context, while authorization checks the requested operation against current server rules. Keep sensitive decisions authoritative on the server and minimize stored state. Do not put session identifiers in public URLs, logs, screenshots, or teaching outputs; this chapter uses only owned synthetic local state.

Cookie flags and fixation defenses solve different risks

Use an explicit cookie policy appropriate to HTTPS, script access, and cross-site behavior: Secure, HttpOnly, and SameSite address different properties. SameSite is not a universal replacement for CSRF defenses, and HttpOnly does not make an application immune to injected script effects. Strict session mode helps reject uninitialized identifiers under supported handlers. Identifier regeneration at relevant privilege transitions must follow a safe lifecycle that accounts for concurrent requests and storage behavior; do not copy a destructive rotation one-liner without understanding lost sessions. Review the current PHP security documentation and application threat model before deployment.

Test storage without a browser cookie or application session

The CLI demonstration creates a private temporary directory, disables cookie use, and selects its own file save handler and storage path. It writes one synthetic counter, closes the session, reopens the same local identity, and reads it back. The directory and session file are removed afterward. No configured application storage or authentication data is loaded. This verifies persistence for this local handler only; it does not test HTTPS, browser cookie acceptance, distributed storage, or a production login flow. Keep such environment assumptions in the caption rather than presenting a CLI result as complete session security.

php CLI-only synthetic session in owned temporary storage
<?php
declare(strict_types=1);
if (PHP_SAPI !== "cli") { throw new RuntimeException("CLI only"); }
$path = sys_get_temp_dir() . "/php-session-demo-" . bin2hex(random_bytes(6));
mkdir($path, 0700);
ini_set("session.save_handler", "files");
ini_set("session.save_path", $path);
ini_set("session.use_cookies", "0");
session_cache_limiter("");
try {
    session_start();
    $_SESSION["visits"] = 1;
    session_write_close();
    session_start();
    $visits = $_SESSION["visits"];
    session_destroy();
    echo $visits, PHP_EOL;
} finally {
    if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); }
    foreach (glob($path . "/*") ?: [] as $file) { unlink($file); }
    rmdir($path);
}
Expected output
1

The output proves the local counter survives close/reopen. Cookie delivery and authentication are intentionally outside this evidence.

Release the session when its state work is finished

Some session handlers lock state while a request owns it. A long request can therefore block another request for the same session, making an otherwise fast endpoint appear stuck. Read or update the required state, then close writing when the workflow no longer needs the lock. Do not continue assuming later $_SESSION edits will persist after session_write_close. Session state should not become a substitute database for durable business operations. The pure snapshot example illustrates an explicit local boundary: later mutations of a working copy do not change a saved snapshot in this model. Real locking behavior still needs handler-specific tests.

php A state snapshot model, not a live session handler
<?php
declare(strict_types=1);
$working = ["cartCount" => 1];
$savedSnapshot = $working;
$working["cartCount"] = 2;
echo $savedSnapshot["cartCount"], " ", $working["cartCount"], PHP_EOL;
Expected output
1 2

The example distinguishes a saved value from a later working change. It does not simulate session locking or cookie transport.

Expiration and logout require explicit semantics

Define idle timeout, absolute lifetime, privilege changes, logout, and recovery according to product risk. Server-side state invalidation and expiring a browser cookie are related but different actions; removing one client cookie does not necessarily revoke every server-side session. Avoid storing secrets or full private records merely for convenience. Test a synthetic lifecycle with independent clients where appropriate and verify that rejected or expired operations have no business side effects. Record browser origin, cookie scope, handler, and concurrency assumptions when diagnosing persistence. Never weaken flags or reuse real account sessions as a shortcut to make a test pass.

Common errors and fixes

CLI persistence is called browser-session proof

Why it happens
Storage and cookie transport are conflated.
How to fix it
Verify cookie delivery and server storage separately.
Prevent it next time
Label the handler, host, and tested lifecycle.

A long request blocks same-session work

Why it happens
A handler lock is retained during unrelated work.
How to fix it
Close session writing after required state changes.
Prevent it next time
Test concurrent synthetic clients against the intended handler.

A session field is treated as permanent permission

Why it happens
Stored identity context replaces current authorization checks.
How to fix it
Authorize sensitive operations against current trusted rules.
Prevent it next time
Review privilege changes and session invalidation together.

Check your understanding

1. Does HttpOnly eliminate the need for XSS prevention?

Show worked solution

No. It limits script access to that cookie, but injected script may still perform actions in the userโ€™s context or alter the page. Keep safe output handling, content policies where appropriate, CSRF strategy, and server authorization as separate defenses. Test the actual task rather than relying on one flag.

2. What does session_write_close change about later state edits?

Show worked solution

It writes and closes the current session; later ordinary changes to the in-memory $_SESSION array are not automatically saved through that closed session. Complete required state updates before closing, then avoid pretending later edits are durable. Verify behavior for the configured handler in an isolated test.

Key takeaways

  • Cookie policy, storage, identity, and authorization are distinct boundaries.
  • Own the session lifecycle and minimize its lock and retained state.

Official references