Skip to content

PHP Sessions — Session Management, Security, and Best Practices

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will learn about PHP Sessions. We cover key concepts, practical examples, and best practices to help you master this topic.

PHP sessions provide a way to persist user data across multiple page requests using a server-side storage mechanism identified by a unique session ID sent via cookie, enabling login systems, shopping carts, and user preferences.

Why It Matters

HTTP is stateless. Each request knows nothing about previous requests. Session management is how applications remember who you are after you log in, what is in your shopping cart, or what language you prefer. Without sessions, you would need to authenticate on every page load. Understanding session security is critical because a stolen session ID lets an attacker impersonate any user.

Real-World Use

WordPress uses sessions (via cookies and transients) to keep users logged in. E-commerce platforms store cart contents in sessions before checkout. Laravel's session driver can use files, database, Redis, or encrypted cookies. Banking applications implement session timeouts and regenerate IDs after login. DodaTech's user portal uses sessions with Redis storage to maintain authenticated states across multiple servers.

What You Will Learn

  • Starting and using sessions with session_start()
  • Storing and retrieving session data
  • Session configuration: lifetime, path, domain, security flags
  • Session security: regeneration, hijacking prevention, fixation
  • Flash messages and temporary session data
  • Custom session handlers and alternatives

Learning Path

flowchart LR
  A[Forms] --> B[Sessions
You are here] B --> C[Cookies] C --> D[Headers] D --> E[File Upload] style B fill:#f90,color:#fff

How Sessions Work

When you call session_start(), PHP does the following:

  1. Checks if a session ID cookie exists in the request
  2. If yes, loads the corresponding session data from storage
  3. If no, generates a new session ID and sends it as a cookie
  4. Makes the $_SESSION superglobal available with the loaded data

The session ID is a random string stored in a cookie (usually named PHPSESSID). The actual data stays on the server. This is the key difference from cookies -- session data is not visible or modifiable by the client.

Basic Session Usage

<?php
// Start session (must be before any output)
session_start();

// Store data
$_SESSION['user_id'] = 42;
$_SESSION['username'] = 'alice';
$_SESSION['role'] = 'admin';
$_SESSION['last_activity'] = time();

// Read data
if (isset($_SESSION['username'])) {
    echo "Welcome back, " . $_SESSION['username'];
}

// Check login status
function isLoggedIn(): bool {
    return isset($_SESSION['user_id']);
}

// Destroy session (logout)
function logout(): void {
    $_SESSION = [];  // Clear all session variables
    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();
}

Session Configuration

PHP session behavior is controlled by php.ini settings or ini_set():

<?php
// Set secure session cookie flags
ini_set('session.cookie_httponly', 1);    // Not accessible via JavaScript
ini_set('session.cookie_secure', 1);      // Only over HTTPS
ini_set('session.cookie_samesite', 'Lax');// CSRF protection

// Set session lifetime (30 minutes)
ini_set('session.gc_maxlifetime', 1800);
ini_set('session.cookie_lifetime', 0);    // Until browser closes

// Use a more secure session name
ini_set('session.name', 'SECURE_SESSION_ID');

// Regenerate ID on each login
session_regenerate_id(true);

Key Session Directives

Directive Default Description
session.name PHPSESSID Name of the session cookie
session.cookie_lifetime 0 Cookie lifetime (0 = until browser closes)
session.cookie_path / Path where cookie is valid
session.cookie_domain (none) Domain for the cookie
session.cookie_secure Off Only send cookie over HTTPS
session.cookie_httponly Off Prevent JavaScript access
session.gc_maxlifetime 1440 Seconds before Garbage Collection
session.save_path /tmp Where session files are stored

Session Security

Session security prevents attackers from stealing or guessing session IDs.

Session Fixation Prevention

Session fixation is when an attacker sets a known session ID for a victim. Prevent this by regenerating the ID on privilege changes:

<?php
function login(string $username, string $password): bool {
    // Verify credentials
    if ($username === 'admin' && $password === 'secret') {
        session_regenerate_id(true);  // New ID, old one invalidated
        $_SESSION['user_id'] = 1;
        $_SESSION['username'] = $username;
        $_SESSION['role'] = 'admin';
        return true;
    }
    return false;
}

Session Hijacking Prevention

Session hijacking occurs when an attacker steals a session ID. Mitigate with:

<?php
// Bind session to user agent and IP
session_start();

if (!isset($_SESSION['initiated'])) {
    $_SESSION['initiated'] = true;
    $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    $_SESSION['remote_addr'] = $_SERVER['REMOTE_ADDR'];
} else {
    if ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
        session_destroy();
        die('Session hijacking detected');
    }
}

Note: IP checking can break for users behind load balancers or mobile networks. User agent checking is more reliable but not foolproof.

Session Timeout

Implement idle timeout to automatically log out inactive users:

<?php
session_start();
$timeout = 1800;  // 30 minutes

if (isset($_SESSION['last_activity']) &&
    (time() - $_SESSION['last_activity']) > $timeout) {
    session_unset();
    session_destroy();
    header('Location: login.php?timeout=1');
    exit;
}
$_SESSION['last_activity'] = time();

Flash Messages

Flash messages persist for exactly one request, useful for success/error notifications:

<?php
// Set flash message
function setFlash(string $key, string $message): void {
    $_SESSION['_flash'][$key] = $message;
}

// Get and clear flash message
function getFlash(string $key): ?string {
    if (isset($_SESSION['_flash'][$key])) {
        $message = $_SESSION['_flash'][$key];
        unset($_SESSION['_flash'][$key]);
        return $message;
    }
    return null;
}

// Usage
setFlash('success', 'Profile updated successfully');

// On next page load
$message = getFlash('success');
if ($message) {
    echo "<div class='success'>$message</div>";
}

Session Storage Handlers

PHP stores sessions as files by default. For production, use a faster backend:

<?php
// File-based (default): stored in /tmp or session.save_path
// Database storage (custom handler)
class DatabaseSessionHandler implements SessionHandlerInterface {
    private PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function open(string $path, string $name): bool {
        return true;
    }

    public function close(): bool {
        return true;
    }

    public function read(string $id): string|false {
        $stmt = $this->pdo->prepare(
            'SELECT data FROM sessions WHERE id = ? AND expires > ?'
        );
        $stmt->execute([$id, time()]);
        $row = $stmt->fetchColumn();
        return $row ?: '';
    }

    public function write(string $id, string $data): bool {
        $stmt = $this->pdo->prepare(
            'REPLACE INTO sessions (id, data, expires) VALUES (?, ?, ?)'
        );
        return $stmt->execute([$id, $data, time() + 1800]);
    }

    public function destroy(string $id): bool {
        $stmt = $this->pdo->prepare('DELETE FROM sessions WHERE id = ?');
        return $stmt->execute([$id]);
    }

    public function gc(int $max_lifetime): int|false {
        $stmt = $this->pdo->prepare('DELETE FROM sessions WHERE expires < ?');
        $stmt->execute([time()]);
        return $stmt->rowCount();
    }
}

// Register handler
$handler = new DatabaseSessionHandler($pdo);
session_set_save_handler($handler, true);
session_start();

Session Storage Options

Storage Pros Cons
Files Simple, no setup needed Slow for high traffic, not shareable across servers
Database Shareable, manageable Slower than memory
Redis/Memcached Fast, shareable Requires separate service
Encrypted cookies No server storage Size limit, exposes data

Common Mistakes

1. Calling session_start() After Output

echo "Hello";
session_start();  // Warning: headers already sent

Call session_start() at the very top of your script before any output.

2. Not Regenerating Session ID After Login

Without regeneration, an attacker who knows the pre-login session ID can still access the post-login session.

3. Storing Sensitive Data Unencrypted

$_SESSION['credit_card'] = '4111-1111-1111-1111';  // Bad

Store only identifiers and non-sensitive data. Encrypt sensitive information.

Without httponly and secure flags, session cookies are accessible via JavaScript and sent over unencrypted HTTP.

5. Using Default Session Name

The default PHPSESSID makes it obvious your site uses PHP sessions. Change the name to make automated attacks slightly harder.

Practice Questions

  1. What happens when you call session_start()? PHP checks for an existing session ID, loads data if found, or creates a new session. It makes $_SESSION available.

  2. Why should you regenerate the session ID after login? To prevent session fixation attacks. A new ID means the old one (possibly set by an attacker) is invalid.

  3. What is the difference between session_destroy() and session_unset()? session_destroy() deletes the session data on the server. session_unset() clears the $_SESSION array but keeps the session alive.

  4. How can you implement session timeout? Store a timestamp in $_SESSION['last_activity'] and check it on each request. Destroy the session if too much time passed.

  5. Challenge: Build a complete login system with session management including login, logout, session timeout, flash messages, and CSRF protection on all forms.

Mini Project: Login System with Session Management

Create a basic login system:

<?php
session_start();
ini_set('session.cookie_httponly', 1);
ini_set('session.use_strict_mode', 1);

$users = [
    'admin' => password_hash('secret123', PASSWORD_DEFAULT),
    'alice' => password_hash('pass456', PASSWORD_DEFAULT),
];

function login(string $username, string $password): bool {
    global $users;
    if (isset($users[$username]) &&
        password_verify($password, $users[$username])) {
        session_regenerate_id(true);
        $_SESSION['user_id'] = $username;
        $_SESSION['role'] = ($username === 'admin') ? 'admin' : 'user';
        $_SESSION['login_time'] = time();
        return true;
    }
    return false;
}

function requireLogin(): void {
    if (!isset($_SESSION['user_id'])) {
        header('Location: login.php');
        exit;
    }
    $timeout = 1800;
    if (time() - $_SESSION['login_time'] > $timeout) {
        session_destroy();
        header('Location: login.php?timeout=1');
        exit;
    }
    $_SESSION['login_time'] = time();
}

function logout(): void {
    $_SESSION = [];
    setcookie(session_name(), '', time() - 3600, '/');
    session_destroy();
}

// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $result = login($_POST['username'] ?? '', $_POST['password'] ?? '');
    if ($result) {
        header('Location: dashboard.php');
        exit;
    }
    $error = 'Invalid credentials';
}
?>

FAQ

Where are PHP sessions stored?

By default, sessions are stored as files in /tmp or session.save_path. You can change to database, Redis, or Memcached with custom handlers.

What happens to sessions when the browser closes?

Session cookies have a default lifetime of 0, meaning they are deleted when the browser closes. The server-side data persists until garbage collection runs.

How do I share sessions across multiple servers?

Use a shared storage like Redis, Memcached, or a database. File-based sessions do not work across servers without a shared filesystem like NFS.

Is it safe to store user roles in sessions?

Yes, but validate on each request if security is critical. A user could theoretically modify their session data if another vulnerability exists.

What is session.use_strict_mode?

When enabled, PHP rejects uninitialized session IDs. This prevents session injection attacks where an attacker sends a crafted session ID.

What is Next

Now that you understand sessions, proceed to Cookies to learn client-side data storage with cookies. Then read Headers to understand HTTP header manipulation for redirects and content types.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro