PHP Sessions — Session Management, Security, and Best Practices
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:
- Checks if a session ID cookie exists in the request
- If yes, loads the corresponding session data from storage
- If no, generates a new session ID and sends it as a cookie
- Makes the
$_SESSIONsuperglobal 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.
4. Not Setting Secure Cookie Flags
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
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.
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.
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.
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.
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
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