Session Handling in PHP
How PHP sessions actually work under the hood, how to configure them safely, and the most common session bugs.
By DevStudio Online Team · Published September 3, 2026
A PHP session lets you persist data for one visitor across multiple requests, without putting it in the URL or a client-side cookie directly. Here's the full lifecycle and where it commonly breaks.
The basic lifecycle
<?php
session_start(); // must run before ANY output — no whitespace, no echo, before this line
$_SESSION['user_id'] = 42;
echo $_SESSION['user_id']; // 42, on this request and every subsequent one
session_destroy(); // ends the session entirelysession_start() does two things: it reads the session ID from a cookie (PHPSESSID by default) sent by the browser, and it loads that session's data from disk (or wherever your session handler stores it) into $_SESSION. If no cookie exists yet, it generates a new ID and sends it back in the response.
The #1 cause of "session_start(): headers already sent"
Warning: session_start(): Cannot send session cookie - headers already sent
This means something — usually a stray blank line, a space before <?php, or an echo — was output before session_start() ran. Cookies are sent as HTTP headers, and headers can't be sent after the response body has already started. Fix: make sure session_start() is the very first thing that runs, and check for whitespace before your opening <?php tag (a classic culprit in files saved with a BOM).
Securing the session cookie
Set these before calling session_start(), ideally in php.ini or at the top of a bootstrap file:
ini_set('session.cookie_httponly', 1); // JS can't read the cookie — mitigates XSS session theft
ini_set('session.cookie_secure', 1); // cookie only sent over HTTPS
ini_set('session.use_strict_mode', 1); // rejects uninitialized session IDs from being adopted
session_start();cookie_httponly and cookie_secure cost nothing and close off two of the most common session-hijacking vectors — there's rarely a good reason to leave them off in production.
Regenerating the session ID after login
session_start();
// ... verify credentials ...
session_regenerate_id(true); // true = delete the old session data too
$_SESSION['user_id'] = $user->id;Always regenerate the session ID right after a successful login. Without this, an attacker who obtained a session ID before the user logged in (via session fixation) would suddenly have an authenticated session once that same ID logs in.
Where session data actually lives
By default, PHP stores session files on local disk (session.save_path). That's fine for a single server, but breaks the moment you run multiple app servers behind a load balancer without sticky sessions — each server only sees its own local session files. For anything beyond a single box, point session.save_handler at Redis or a database instead.