PHPSessions ($_SESSION)

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
<?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
<?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 $_SESSION array and the browser cookie as they were until the next request.

A complete logout

PHP
<?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_destroy() alone does not clear the cookie
`session_destroy()` only removes the server-side data file. The browser will still send the old session cookie on its next request, at which point PHP simply creates a brand-new empty session under that id. If you want a real logout, also clear the cookie as shown above — this matters even more once you get to session security and login flows.
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
<?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();
Garbage collection is probabilistic, not scheduled
PHP does not run a background job to delete expired sessions on a timer. Instead, on a configurable percentage of requests (`session.gc_probability` / `session.gc_divisor`), PHP checks for and removes session files older than `gc_maxlifetime`. On low-traffic sites this means old session files can sit around longer than the configured lifetime suggests, though PHP still treats them as expired once accessed.
Tip
Call `session_start()` as the very first line of your entry script, before any other logic, even if you are not sure the current page needs a session. It costs almost nothing when there is no session cookie yet, and it avoids the entire class of "headers already sent" bugs that come from starting sessions late.