Sessions ($_SESSION)
Cookies are useful, but stuffing meaningful data straight into a cookie means shipping it to the browser and back on every single request — and trusting the browser not to tamper with it. Sessions solve that by keeping the actual data on the server and giving the browser only a short, random identifier. PHP's session support ties that identifier to a store of arbitrary values through the $_SESSION superglobal, so you can, for example, remember that a visitor is logged in as user #482 without ever sending "482" to their browser.
Starting a session
Nothing session-related happens automatically — you have to call session_start() yourself, and it has to run before any output at all, including a stray blank line before <?php or an echo earlier in the script. session_start() works by sending a Set-Cookie header (for the session id cookie), and headers can only be sent before any body content. Call it late and PHP raises a "headers already sent" warning and the session silently fails to work as expected.
session_start() must come first
<?php
session_start(); // must run before any HTML/output
$_SESSION['visits'] = ($_SESSION['visits'] ?? 0) + 1;
?>
<!DOCTYPE html>
<html>
<body>
<p>You have visited this page <?= (int) $_SESSION['visits'] ?> time(s).</p>
</body>
</html>You have visited this page 3 time(s).
How PHP sessions work under the hood
session_start() looks for a cookie — named PHPSESSID by default — on the incoming request. If it finds one, it uses that value as the session id and loads the matching stored data. If it does not find one (a brand-new visitor), it generates a fresh random id, sends it back as a cookie, and starts an empty session. On a typical installation, the actual data behind $_SESSION lives in a plain file on the server, usually named sess_<sessionid> inside the directory configured by session.save_path. Every time you read or write $_SESSION in a request, PHP is really reading and rewriting that file (or whatever storage handler is configured — some setups use Redis or a database instead of the filesystem). The cookie itself never contains the visitor's data, only the key needed to look it up server-side.
Storing and reading values
Once a session is started, $_SESSION behaves like a normal associative array for the rest of the request — and for every following request from the same browser, until the session ends.
Reading and writing $_SESSION
<?php
session_start();
// Writing values
$_SESSION['username'] = 'aisha';
$_SESSION['cart'] = ['sku-1', 'sku-9'];
// Reading values on a later request
$username = $_SESSION['username'] ?? null;
if ($username !== null) {
echo "Welcome back, " . htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
} else {
echo 'You are not logged in.';
}Ending a session
PHP gives you two related but different tools for clearing session state, and mixing them up is a common source of bugs.
session_unset()empties all the values currently in$_SESSION, but keeps the session itself (and its id) active.session_destroy()deletes the server-side session data entirely, but leaves the$_SESSIONarray and the browser cookie as they were until the next request.
A complete logout
<?php
session_start();
$_SESSION = []; // clear the in-memory array
session_unset(); // and the session variables
session_destroy(); // remove the server-side storage
// also expire the session cookie itself
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}Session lifetime
By default, PHP's session cookie has no explicit expiration, which browsers treat as "delete when the browser closes." Independently, the server has a garbage-collection setting, session.gc_maxlifetime, which controls how long an unused session file is allowed to sit on disk (in seconds) before PHP is permitted to clean it up. These two settings are easy to confuse: one is about the browser's cookie, the other is about how long the server keeps the data around.
Configuring session lifetime at runtime
<?php
// Must be set before session_start()
ini_set('session.gc_maxlifetime', 1800); // server keeps idle data 30 min
session_set_cookie_params(['lifetime' => 0]); // cookie dies with the browser
session_start();