Session 4.2 – PHP Sessions

Module 4: PHP Filters and Handlers | Duration: 1 hr

Learning Objectives

By the end of this session, students will be able to:

  • Understand what PHP sessions are and how they differ from cookies
  • Start and manage PHP sessions using session_start()
  • Store and retrieve data in session variables
  • Properly destroy sessions and clean up session data
  • Implement secure session practices to prevent hijacking and fixation
  • Build complete authentication systems using sessions

Introduction to PHP Sessions

A session is a way to preserve data across subsequent page requests. Unlike cookies which are stored on the client's browser, session data is stored on the server, making it more secure for sensitive information.

Key Insight

Sessions allow you to store user information on the server for later use across multiple pages. The server creates a unique session ID for each visitor, which is typically stored as a cookie on the client side or passed through URLs.

How Sessions Work
  1. When a session is started, PHP generates a unique Session ID (PHPSESSID)
  2. The Session ID is sent to the client (usually as a cookie)
  3. Session data is stored on the server with the Session ID as the key
  4. On subsequent requests, the client sends the Session ID back to the server
  5. PHP retrieves the session data using the Session ID

Sessions vs Cookies

Understanding the differences between sessions and cookies helps you choose the right tool for your application:

Aspect Sessions Cookies
Storage Location Server-side Client-side (browser)
Security More secure (data not visible to client) Less secure (visible in browser)
Storage Capacity Limited by server memory 4KB per cookie
Expiration Ends when browser closes or manual destruction Can be set to any time
Data Types Can store any PHP data type Only strings
Performance Uses server resources No server resource usage
Use Case Sensitive data, user authentication User preferences, tracking

Starting and Managing Sessions

To use sessions in PHP, you must first start a session using the session_start() function. This must be called before any output is sent to the browser.

Basic Session Start:
<?php
// Start a new session or resume existing session
session_start();

echo "Session started successfully!";
echo "<br>Session ID: " . session_id();
?>
Important Note

Like setcookie(), the session_start() function must be called before any HTML output, whitespace, or echo statements. Otherwise, you'll receive a "headers already sent" error.

Session Configuration:
<?php
// Configure session settings before starting
ini_set('session.cookie_lifetime', 3600); // 1 hour
ini_set('session.cookie_secure', 1);      // HTTPS only
ini_set('session.cookie_httponly', 1);    // No JavaScript access
ini_set('session.use_strict_mode', 1);    // Prevent session fixation

session_start();
?>
Session Status Check:
<?php
// Check if session is already started
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// Alternative check
if (!isset($_SESSION)) {
    session_start();
}

echo "Session is active!";
?>

Storing Data in Sessions

Session data is stored in the $_SESSION superglobal array. You can store any type of PHP data in sessions.

Storing Different Data Types:
<?php
session_start();

// Store string
$_SESSION["username"] = "JohnDoe";

// Store integer
$_SESSION["user_id"] = 12345;

// Store array
$_SESSION["user_data"] = [
    "name" => "John Doe",
    "email" => "john@example.com",
    "role" => "admin"
];

// Store object
class User {
    public $name;
    public $email;

    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
    }
}

$_SESSION["user_object"] = new User("John", "john@example.com");

// Store boolean
$_SESSION["is_logged_in"] = true;

echo "Data stored in session successfully!";
?>
Session Counter Example:
<?php
session_start();

// Initialize counter if it doesn't exist
if (!isset($_SESSION["page_views"])) {
    $_SESSION["page_views"] = 0;
}

// Increment counter
$_SESSION["page_views"]++;

echo "You have viewed this page " . $_SESSION["page_views"] . " times.";
?>

Retrieving Session Data

Accessing session data is straightforward using the $_SESSION array. Always check if a session variable exists before using it.

Safe Data Retrieval:
<?php
session_start();

// Check if session variable exists
if (isset($_SESSION["username"])) {
    echo "Welcome back, " . $_SESSION["username"] . "!";
} else {
    echo "Please log in.";
}

// Using default values
$username = $_SESSION["username"] ?? "Guest";
echo "Hello, " . $username;

// Using isset with multiple variables
if (isset($_SESSION["user_id"], $_SESSION["username"])) {
    echo "User ID: " . $_SESSION["user_id"];
    echo "<br>Username: " . $_SESSION["username"];
}
?>
Retrieving Complex Data:
<?php
session_start();

// Retrieve array data
if (isset($_SESSION["user_data"])) {
    $userData = $_SESSION["user_data"];
    echo "Name: " . $userData["name"] . "<br>";
    echo "Email: " . $userData["email"] . "<br>";
    echo "Role: " . $userData["role"];
}

// Retrieve object data
if (isset($_SESSION["user_object"])) {
    $user = $_SESSION["user_object"];
    echo "User: " . $user->name . " (" . $user->email . ")";
}
?>
Display All Session Data:
<?php
session_start();

echo "<h3>Current Session Data:</h3>";
echo "<pre>";
print_r($_SESSION);
echo "</pre>";

// Or use var_dump for more details
echo "<h3>Detailed Session Data:</h3>";
echo "<pre>";
var_dump($_SESSION);
echo "</pre>";
?>

Destroying Sessions and Session Data

Properly destroying sessions is crucial for security, especially for logout functionality.

Removing Individual Session Variables:
<?php
session_start();

// Remove a specific session variable
unset($_SESSION["username"]);

// Remove multiple variables
unset($_SESSION["user_id"], $_SESSION["email"]);

echo "Session variables removed.";
?>
Complete Session Destruction:
<?php
session_start();

// Step 1: Unset all session variables
$_SESSION = array();

// Step 2: Delete the session cookie
if (isset($_COOKIE[session_name()])) {
    setcookie(session_name(), '', time() - 3600, '/');
}

// Step 3: Destroy the session
session_destroy();

echo "Session completely destroyed!";
?>
Proper Logout Function:
<?php
// logout.php
function logout() {
    // Start session if not already started
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }

    // Unset all session variables
    $_SESSION = array();

    // Delete session 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"]
        );
    }

    // Destroy session
    session_destroy();

    // Redirect to login page
    header("Location: login.php");
    exit();
}

// Call logout function
logout();
?>
Session Regeneration (Prevent Fixation):
<?php
session_start();

// Regenerate session ID to prevent session fixation
session_regenerate_id(true);

echo "Session ID has been regenerated.";
echo "<br>New Session ID: " . session_id();
?>

Session Security Best Practices

Implementing proper security measures is essential to protect against session hijacking, fixation, and other attacks.

1. Secure Session Configuration:
<?php
// config/session_config.php
ini_set('session.cookie_httponly', 1);    // Prevent JavaScript access
ini_set('session.use_only_cookies', 1);   // Force cookies only
ini_set('session.cookie_secure', 1);      // HTTPS only
ini_set('session.cookie_samesite', 'Strict'); // CSRF protection
ini_set('session.use_strict_mode', 1);    // Reject uninitialized session IDs

session_start();
?>
2. Session Timeout Implementation:
<?php
session_start();

// Set timeout duration (30 minutes)
$timeout_duration = 1800;

// Check if session has expired
if (isset($_SESSION['last_activity'])) {
    $elapsed_time = time() - $_SESSION['last_activity'];

    if ($elapsed_time > $timeout_duration) {
        // Session expired
        session_unset();
        session_destroy();
        header("Location: login.php?timeout=1");
        exit();
    }
}

// Update last activity timestamp
$_SESSION['last_activity'] = time();
?>
3. Session Hijacking Prevention:
<?php
session_start();

// Store user agent and IP address
if (!isset($_SESSION['user_agent'])) {
    $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
}

if (!isset($_SESSION['ip_address'])) {
    $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
}

// Verify session on each request
if ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT'] ||
    $_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {

    // Possible session hijacking detected
    session_unset();
    session_destroy();
    die("Security violation detected!");
}
?>
4. Regenerate Session ID After Login:
<?php
// login_process.php
session_start();

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = $_POST["username"];
    $password = $_POST["password"];

    // Verify credentials (simplified)
    if (verify_credentials($username, $password)) {
        // Regenerate session ID to prevent fixation
        session_regenerate_id(true);

        // Set session variables
        $_SESSION['user_id'] = get_user_id($username);
        $_SESSION['username'] = $username;
        $_SESSION['logged_in'] = true;
        $_SESSION['login_time'] = time();

        // Redirect to dashboard
        header("Location: dashboard.php");
        exit();
    }
}

function verify_credentials($username, $password) {
    // Database verification logic here
    return true;
}

function get_user_id($username) {
    // Retrieve user ID from database
    return 12345;
}
?>
Security Checklist
  • Always use HTTPS in production
  • Set HttpOnly and Secure flags on session cookies
  • Regenerate session ID after login
  • Implement session timeouts
  • Validate user agent and IP address
  • Use strong session ID generation
  • Store sessions securely on the server
  • Never expose session IDs in URLs

Practical Examples

Example 1: Complete Login System
<?php
// login.php
session_start();

// Redirect if already logged in
if (isset($_SESSION["logged_in"]) && $_SESSION["logged_in"] === true) {
    header("Location: dashboard.php");
    exit();
}

$error = "";

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

    // Validate credentials (simplified)
    if ($username === "admin" && $password === "password123") {
        // Regenerate session ID
        session_regenerate_id(true);

        // Set session variables
        $_SESSION["logged_in"] = true;
        $_SESSION["username"] = $username;
        $_SESSION["user_id"] = 1;
        $_SESSION["login_time"] = time();

        header("Location: dashboard.php");
        exit();
    } else {
        $error = "Invalid username or password";
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <?php if ($error): ?>
        <p style="color: red;"><?php echo $error; ?></p>
    <?php endif; ?>

    <form method="POST" action="">
        <input type="text" name="username" placeholder="Username" required><br>
        <input type="password" name="password" placeholder="Password" required><br>
        <button type="submit">Login</button>
    </form>
</body>
</html>
Example 2: Protected Dashboard
<?php
// dashboard.php
session_start();

// Check if user is logged in
if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) {
    header("Location: login.php");
    exit();
}

// Calculate session duration
$session_duration = time() - $_SESSION["login_time"];
$minutes = floor($session_duration / 60);
?>

<!DOCTYPE html>
<html>
<head>
    <title>Dashboard</title>
</head>
<body>
    <h1>Welcome, <?php echo htmlspecialchars($_SESSION["username"]); ?>!</h1>
    <p>User ID: <?php echo $_SESSION["user_id"]; ?></p>
    <p>Logged in for: <?php echo $minutes; ?> minutes</p>
    <p><a href="logout.php">Logout</a></p>
</body>
</html>
Example 3: Shopping Cart with Sessions
<?php
// cart.php
session_start();

// Initialize cart if it doesn't exist
if (!isset($_SESSION["cart"])) {
    $_SESSION["cart"] = [];
}

// Add item to cart
if (isset($_POST["add_to_cart"])) {
    $product_id = $_POST["product_id"];
    $product_name = $_POST["product_name"];
    $price = $_POST["price"];

    // Check if product already in cart
    if (isset($_SESSION["cart"][$product_id])) {
        $_SESSION["cart"][$product_id]["quantity"]++;
    } else {
        $_SESSION["cart"][$product_id] = [
            "name" => $product_name,
            "price" => $price,
            "quantity" => 1
        ];
    }
}

// Remove item from cart
if (isset($_GET["remove"])) {
    $product_id = $_GET["remove"];
    unset($_SESSION["cart"][$product_id]);
}

// Clear entire cart
if (isset($_GET["clear"])) {
    $_SESSION["cart"] = [];
}

// Calculate total
$total = 0;
foreach ($_SESSION["cart"] as $item) {
    $total += $item["price"] * $item["quantity"];
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Shopping Cart</title>
</head>
<body>
    <h1>Shopping Cart</h1>

    <?php if (empty($_SESSION["cart"])): ?>
        <p>Your cart is empty.</p>
    <?php else: ?>
        <table border="1">
            <tr>
                <th>Product</th>
                <th>Price</th>
                <th>Quantity</th>
                <th>Subtotal</th>
                <th>Action</th>
            </tr>
            <?php foreach ($_SESSION["cart"] as $id => $item): ?>
                <tr>
                    <td><?php echo htmlspecialchars($item["name"]); ?></td>
                    <td>$<?php echo number_format($item["price"], 2); ?></td>
                    <td><?php echo $item["quantity"]; ?></td>
                    <td>$<?php echo number_format($item["price"] * $item["quantity"], 2); ?></td>
                    <td><a href="?remove=<?php echo $id; ?>">Remove</a></td>
                </tr>
            <?php endforeach; ?>
            <tr>
                <td colspan="3"><strong>Total:</strong></td>
                <td><strong>$<?php echo number_format($total, 2); ?></strong></td>
                <td></td>
            </tr>
        </table>
        <p><a href="?clear=1">Clear Cart</a></p>
    <?php endif; ?>

    <h2>Add Products</h2>
    <form method="POST">
        <input type="hidden" name="product_id" value="1">
        <input type="hidden" name="product_name" value="Laptop">
        <input type="hidden" name="price" value="999.99">
        <button type="submit" name="add_to_cart">Add Laptop ($999.99)</button>
    </form>

    <form method="POST">
        <input type="hidden" name="product_id" value="2">
        <input type="hidden" name="product_name" value="Mouse">
        <input type="hidden" name="price" value="29.99">
        <button type="submit" name="add_to_cart">Add Mouse ($29.99)</button>
    </form>
</body>
</html>
Example 4: Multi-Step Form with Sessions
<?php
// step1.php
session_start();

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $_SESSION["step1"] = [
        "first_name" => $_POST["first_name"],
        "last_name" => $_POST["last_name"],
        "email" => $_POST["email"]
    ];
    header("Location: step2.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Step 1: Personal Information</title>
</head>
<body>
    <h2>Step 1 of 3: Personal Information</h2>
    <form method="POST">
        <input type="text" name="first_name" placeholder="First Name" required><br>
        <input type="text" name="last_name" placeholder="Last Name" required><br>
        <input type="email" name="email" placeholder="Email" required><br>
        <button type="submit">Next</button>
    </form>
</body>
</html>


<?php
// step2.php
session_start();

if (!isset($_SESSION["step1"])) {
    header("Location: step1.php");
    exit();
}

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $_SESSION["step2"] = [
        "address" => $_POST["address"],
        "city" => $_POST["city"],
        "zip" => $_POST["zip"]
    ];
    header("Location: step3.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Step 2: Address</title>
</head>
<body>
    <h2>Step 2 of 3: Address</h2>
    <form method="POST">
        <input type="text" name="address" placeholder="Street Address" required><br>
        <input type="text" name="city" placeholder="City" required><br>
        <input type="text" name="zip" placeholder="ZIP Code" required><br>
        <button type="submit">Next</button>
    </form>
</body>
</html>


<?php
// step3.php
session_start();

if (!isset($_SESSION["step1"]) || !isset($_SESSION["step2"])) {
    header("Location: step1.php");
    exit();
}

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // Process complete form
    $complete_data = array_merge(
        $_SESSION["step1"],
        $_SESSION["step2"],
        ["phone" => $_POST["phone"]]
    );

    // Save to database or process data
    // ...

    // Clear session data
    unset($_SESSION["step1"]);
    unset($_SESSION["step2"]);

    echo "Form submitted successfully!";
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Step 3: Confirmation</title>
</head>
<body>
    <h2>Step 3 of 3: Confirmation</h2>

    <h3>Review Your Information:</h3>
    <p>Name: <?php echo $_SESSION["step1"]["first_name"] . " " . $_SESSION["step1"]["last_name"]; ?></p>
    <p>Email: <?php echo $_SESSION["step1"]["email"]; ?></p>
    <p>Address: <?php echo $_SESSION["step2"]["address"]; ?></p>
    <p>City: <?php echo $_SESSION["step2"]["city"]; ?></p>
    <p>ZIP: <?php echo $_SESSION["step2"]["zip"]; ?></p>

    <form method="POST">
        <input type="tel" name="phone" placeholder="Phone Number" required><br>
        <button type="submit">Submit</button>
    </form>
</body>
</html>

Session Summary

Key Points
  • Sessions store data on the server, making them more secure than cookies
  • Use session_start() to begin or resume a session
  • Store data in the $_SESSION superglobal array
  • Sessions persist across multiple pages until destroyed or expired
  • Always implement proper session destruction on logout
  • Regenerate session IDs after login to prevent fixation attacks
  • Implement session timeouts and validation for security
  • Use HTTPS and security flags (HttpOnly, Secure) in production
Next Session Preview

In the next session, we will explore Call-back Functions in PHP, learning how to use anonymous functions, closures, and callbacks to create more flexible and reusable code.