Warning: Undefined global variable $_SESSION in /www/wwwroot/rubansoftwares.com/learn/tutorials/php/sessions.php on line 60
PHP Sessions & Cookies - session_start, $_SESSION, session_regenerate_id | RubanLearn

PHP Sessions & Cookies

Remember users across requests with sessions and cookies. Master session_start, $_SESSION, secure cookie flags, session fixation defense, and flash messages.

Intermediate 8 min read 9 examples

How Sessions Work

  1. You call session_start(). PHP looks for a PHPSESSID cookie.
  2. If missing, PHP generates a unique session ID and sets the cookie.
  3. PHP loads the session's stored data from disk into $_SESSION.
  4. You read/write $_SESSION freely during the request.
  5. At script end, PHP writes $_SESSION back to disk.

Starting a Session

PHP
<?php
// MUST come before any output (HTML, echo, even whitespace before <?php)
session_start();

// Or with options (PHP 7+)
session_start([
    "cookie_lifetime" => 0,         // until browser close
    "cookie_secure"   => true,      // HTTPS only
    "cookie_httponly" => true,      // not accessible to JavaScript
    "cookie_samesite" => "Lax",     // CSRF protection
    "use_strict_mode" => true,      // reject unknown session IDs
]);

Storing & Reading Data

PHP
<?php
session_start();

// Write
$_SESSION["user_id"] = 42;
$_SESSION["preferences"] = ["theme" => "dark", "lang" => "en"];

// Read (with safe defaults)
$userId = $_SESSION["user_id"] ?? null;
$theme  = $_SESSION["preferences"]["theme"] ?? "light";

// Check
if (isset($_SESSION["user_id"])) {
    echo "Logged in as $userId";
}

// Remove a single key
unset($_SESSION["preferences"]);

// Clear all data (but keep the session)
$_SESSION = [];

Login Example

PHPlogin.php
<?php
session_start();

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $email    = trim($_POST["email"] ?? "");
    $password = $_POST["password"] ?? "";

    $user = $db->fetchUserByEmail($email);
    if ($user && password_verify($password, $user["password_hash"])) {
        // PREVENT SESSION FIXATION - regenerate the ID
        session_regenerate_id(true);

        $_SESSION["user_id"]   = $user["id"];
        $_SESSION["user_name"] = $user["name"];
        $_SESSION["login_at"]  = time();

        header("Location: /dashboard");
        exit;
    }

    $error = "Invalid credentials";
}

Logout & Destroying Sessions

PHPlogout.php
<?php
session_start();

// 1. Empty the data
$_SESSION = [];

// 2. Tell the browser to forget the cookie
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(session_name(), "", time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]);
}

// 3. Destroy the server-side data
session_destroy();

header("Location: /login");
exit;

Cookies Direct

PHP
<?php
// Set a cookie - MUST be before any output
setcookie("theme", "dark", [
    "expires"  => time() + 86400 * 30,   // 30 days
    "path"     => "/",
    "domain"   => "example.com",
    "secure"   => true,                  // HTTPS only
    "httponly" => true,                  // no JS access (PHP 7.3+ options)
    "samesite" => "Strict",
]);

// Read (next request)
$theme = $_COOKIE["theme"] ?? "light";

// Delete
setcookie("theme", "", time() - 3600, "/");

Secure Session Config (php.ini)

INIphp.ini
; Don't accept session IDs from the URL
session.use_only_cookies = 1
session.use_trans_sid    = 0

; Use HTTPS-only cookies
session.cookie_secure    = 1
session.cookie_httponly  = 1
session.cookie_samesite  = "Lax"

; Reject unknown session IDs (prevents fixation)
session.use_strict_mode  = 1

; Use a stronger hash for session IDs
session.sid_length        = 48
session.sid_bits_per_character = 6

; Custom save path on fast disk
session.save_path = "/var/lib/php/sessions"
session.gc_maxlifetime = 1440
Always regenerate ID on privilege changes

Call session_regenerate_id(true) after login, logout, role change, or any sensitive action. Otherwise an attacker who learned the pre-login session ID can hijack the post-login session.

Flash Messages

One-time messages between requests (e.g., "Saved successfully" after a redirect):

PHP
<?php
session_start();

function flash(string $key, ?string $msg = null): ?string {
    if ($msg !== null) {
        $_SESSION["_flash"][$key] = $msg;
        return null;
    }
    $val = $_SESSION["_flash"][$key] ?? null;
    unset($_SESSION["_flash"][$key]);
    return $val;
}

// On save handler
flash("success", "Post saved!");
header("Location: /posts");

// On the destination page
if ($msg = flash("success")) {
    echo "<div class=\"alert\">" . htmlspecialchars($msg) . "</div>";
}

Next Steps

Frequently Asked Questions

A cookie stores data on the client (browser). A session stores data on the server, identified by a session ID that lives in one specific cookie (PHPSESSID). Sessions are safer for sensitive data because the actual values never leave your server.

Immediately after any privilege change - login, logout, password change. This prevents session fixation attacks where an attacker tricks the user into using a known session ID. Pass true to delete the old session file.

Common causes: (1) session_start() not called on every page; (2) output before session_start() (HTML, whitespace) - cookies need to be sent first; (3) different cookie paths/domains; (4) browser blocking cookies.

By default, in your system's temp directory (sys_get_temp_dir()). For production, use a custom path (session.save_path) on a fast filesystem, or switch to Redis/Memcached via session.save_handler.

Not with the default file handler - each server has its own session files. Use a shared store: Redis, Memcached, or a database. Symfony, Laravel, and CodeIgniter all provide drivers for this.