session_start() / $_SESSION / session_destroy()
| Since: | PHP 4(2000) |
|---|
Starts a session and stores per-user data on the server. Use it when you need to persist data across pages, such as managing login state or a shopping cart.
Syntax
session_start($options); // Store and retrieve session variables. $_SESSION['key'] = $value; // Destroy the session. session_destroy(); // Regenerate the session ID. session_regenerate_id($delete_old_session); session_id($id); // Set session cookie parameters. session_set_cookie_params($options);
Function List
| Function | Description |
|---|---|
| session_start($options) | Starts a session. Does nothing if a session is already active. You can pass options such as cookie_lifetime and cookie_secure as an associative array. |
| $_SESSION | A superglobal array that stores session variables. Values saved to this array are available on the next request from the same user. |
| session_destroy() | Destroys all data associated with the current session. Because session variables are not cleared immediately, also set $_SESSION = [] to empty the array. |
| session_regenerate_id($delete_old) | Generates a new session ID. Pass true to also delete the old session file. |
| session_id($id) | Returns the current session ID when called with no argument. Pass a string to set the session ID. |
| session_set_cookie_params($options) | Sets the session cookie parameters. Must be called before session_start(). |
Sample Code
Call session_start() exactly once at the top of every page, before any output.
session_start.php
<?php
// Start the session.
session_start();
// Store data in session variables.
$_SESSION['username'] = 'Kiryu Kazuma';
$_SESSION['favorite_song'] = 'Baka Mitai';
$_SESSION['login_time'] = time();
echo $_SESSION['username'] . "\n"; // Outputs 'Kiryu Kazuma'.
echo $_SESSION['favorite_song'] . "\n"; // Outputs 'Baka Mitai'.
if (isset($_SESSION['username'])) {
echo "Logged in as: " . $_SESSION['username'] . "\n";
}
// Check the session ID.
echo session_id() . "\n"; // Outputs an ID like 'abc123def456...'.
// Configure the session cookie with secure settings.
session_set_cookie_params([
'lifetime' => 0, // Valid until the browser is closed.
'path' => '/',
'domain' => '',
'secure' => true, // Send the cookie over HTTPS only.
'httponly' => true, // Prevents JavaScript from accessing the cookie.
'samesite' => 'Lax' // Sets the SameSite attribute as a CSRF countermeasure.
]);
session_start(); // ← In real code, this is the only call to session_start() per page.
// Regenerate the session ID on successful login.
session_regenerate_id(true); // Also deletes the old session file.
$_SESSION['user_id'] = 1;
// Complete logout implementation.
$_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"]
); // Delete the session cookie.
}
session_destroy(); // Destroy the session data.
Running the code produces the following output:
php session_start.php Kiryu Kazuma Baka Mitai Logged in as: Kiryu Kazuma abc123def456789ghijk012345lmnop
Practical Pattern: Complete Login Implementation
The following sample uses this users table. Passwords should be stored as hashes generated by password_hash().
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) DEFAULT 'user'
);
-- Hash of password 'secret123' (generated by password_hash())
INSERT INTO users (email, password_hash, role) VALUES
('kiryu_kazuma@wp-p.info', '$2y$10$xxxxx...', 'admin');
Verify the table contents.
SELECT * FROM users; +----+------------------------+--------------------------------------------------------------+-------+ | id | email | password_hash | role | +----+------------------------+--------------------------------------------------------------+-------+ | 1 | kiryu_kazuma@wp-p.info | $2y$10$xxxxx... | admin | +----+------------------------+--------------------------------------------------------------+-------+ 1 row in set
sample_login.php
<?php
// Complete login implementation pattern.
// 1. Configure session cookie parameters before calling session_start().
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
// 2. Verify the CSRF token (compare against the token submitted with the form).
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
http_response_code(403);
exit('Forbidden');
}
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
// 3. Authenticate the user against the database (stub implementation here).
$pdo = new PDO('mysql:host=localhost;dbname=sample_db;charset=utf8mb4', 'root', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email LIMIT 1");
$stmt->execute([':email' => $email]);
$user = $stmt->fetch();
// Verify the password hash with password_verify().
if ($user && !password_verify($password, $user['password_hash'])) {
$user = false;
}
if ($user) {
// 4. Regenerate the session ID immediately on successful login (prevents session fixation).
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['role'] = $user['role'];
$_SESSION['login_time'] = time();
header('Location: /dashboard.php');
exit;
} else {
$_SESSION['error'] = 'Invalid email or password.';
}
}
// 5. Issue a CSRF token when displaying the form.
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
Use curl commands to verify the behavior. The following shell script retrieves the login form, extracts the CSRF token, and submits a login request.
sample_login_test.sh
#!/bin/bash # 1. Retrieve the login form and extract the CSRF token. CSRF=$(curl -c cookie.txt -s http://localhost/login.php \ | grep -o 'value="[^"]*"' | head -1 | cut -d'"' -f2) echo "CSRF token: $CSRF" # 2. Send a login request. curl -b cookie.txt -c cookie.txt -s -D - \ -d "email=kiryu_kazuma@wp-p.info&password=secret123&csrf_token=$CSRF" \ http://localhost/login.php
Running the code produces the following output:
sh sample_login_test.sh CSRF token: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 HTTP/1.1 302 Found Location: /dashboard.php Set-Cookie: PHPSESSID=new_session_id; path=/; secure; HttpOnly; SameSite=Lax
On successful login, a 302 redirect is returned and a new cookie with a regenerated session ID is issued. On authentication failure, the same page is displayed and the error message is stored in $_SESSION["error"].
Common Mistakes
Common mistake 1: output before session_start()
Outputting anything before session_start() causes a "headers already sent" error.
<?php // NG: Outputting anything before session_start() causes a 'headers already sent' error. echo "Hello"; // Even whitespace or a blank line triggers this. session_start(); // Error: Cannot send session cookie - headers already sent
The corrected version is:
<?php // OK: Call session_start() at the very top of the file, before any output. session_start(); echo "Hello";
Common mistake 2: session_destroy() only logout
Calling session_destroy() alone does not clear session variables — they remain in memory. Logout requires three steps.
<?php // NG: Calling session_destroy() alone does not clear session variables. session_destroy(); echo $_SESSION['username']; // Still accessible in memory.
The corrected version is:
<?php
// OK: Three steps are required: clear variables, delete the cookie, destroy the data.
$_SESSION = [];
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();
Common mistake 3: no session ID regeneration
Not regenerating the session ID after login risks a session fixation attack.
<?php // NG: Not regenerating the session ID after login risks a session fixation attack. $_SESSION['user_id'] = $user['id']; // Session fixation risk
The corrected version is:
<?php // OK: Always regenerate immediately after login. session_regenerate_id(true); $_SESSION['user_id'] = $user['id'];
Common mistake 4: duplicate session_start() calls
Calling session_start() again in a required/included file causes an error.
<?php // NG: Calling session_start() again in a required/included file causes an error. // common.php: session_start(); // login.php: require 'common.php'; session_start(); // Warning: session already started
The corrected version is:
<?php
// OK: Check the session status before starting.
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
session_start() only runs when the status is PHP_SESSION_NONE (not yet started). Use this pattern in shared files that may be included from multiple entry points.
Overview
session_start() initiates PHP's session management and reserves a per-user data area on the server. To prevent session fixation attacks, always call session_regenerate_id(true) to regenerate the session ID immediately after a successful login.
It is important to set the secure, httponly, and samesite attributes on the session cookie. Enabling httponly prevents JavaScript from accessing the cookie, which guards against session hijacking via XSS attacks.
When logging out, you must perform all three steps: clear the session variables, delete the session cookie, and destroy the session data. Calling session_destroy() alone is not enough, because the contents of $_SESSION remain in memory. For cookie operations, also see setcookie().
If you find any errors or copyright issues, please contact us.