PHP: Sessions and Login System
Cookies keep data in the user's browser; Sessions keep it on the server. Login state, shopping carts, permission flags — any data you don't want the user touching belongs in a session. By the end of this lesson, you'll have built your first login system.
1. What Is a Session?
A session is a private storage area on the server created for each user. The browser only holds a cookie with the Session ID; all the real data stays server-side:
TEXT
📖 Display only
Cookie: Session:
Only holds the Session ID Stores the actual data (username, role, cart...)
┌──────────────┐ ┌──────────────────────┐
│ PHPSESSID │ ──match──→ │ user: John │
│ abc123 │ │ login: true │
└──────────────┘ │ cart: [3 items] │
In the browser │ role: admin │
└──────────────────────┘
On the server
💡 Tip: Session vs Cookie: Cookies live in the browser (visible and modifiable by the user); sessions live on the server (secure). But sessions rely on cookies to transmit the Session ID — if the user blocks cookies, sessions break.
2. session_start() — Starting a Session
You must call session_start() before using any session functionality. It does two things:
- If the browser sends a Session ID cookie → load the corresponding server data
- If no cookie is found → create a new session, generate a new ID, and send a cookie
PHP
<?php
// session_start() must come before any HTML output
session_start();
// Store data
$_SESSION['username'] = "John";
$_SESSION['login_time'] = date("Y-m-d H:i:s");
// Read data
echo "Welcome, {$_SESSION['username']}!";
echo "Logged in at: {$_SESSION['login_time']}";
?>
🔥 Common Mistake:
session_start() must be called before any output — echo, raw HTML, even a stray space before the <?php tag. Otherwise you'll get the dreaded headers already sent error. Put it at the very top of your file.
3. $_SESSION — Use It Like Any Array
PHP
<?php
session_start();
// Store any PHP data type
$_SESSION['user'] = [
'id' => 101,
'name' => 'John',
'role' => 'member'
];
$_SESSION['cart'] = [
['name' => 'PHP Tutorial', 'price' => 39.90, 'qty' => 2],
['name' => 'MySQL Basics', 'price' => 29.90, 'qty' => 1],
];
// Read
echo $_SESSION['user']['name']; // John
// Remove a single session variable
unset($_SESSION['cart']);
// Update
$_SESSION['user']['role'] = 'admin';
?>
▶ Example: A Session-Powered Shopping Cart
Output:
TEXT
📖 Display only
<h3>Your Cart</h3>
{item1} × {1}<br>
PHP
<?php
session_start();
// Initialize the cart
if (!isset($_SESSION['cart'])) {
$_SESSION['cart'] = [];
}
// Add an item
if (isset($_POST['add'])) {
$item = $_POST['add'];
$_SESSION['cart'][$item] = ($_SESSION['cart'][$item] ?? 0) + 1;
}
echo "<h3>Your Cart</h3>";
foreach ($_SESSION['cart'] as $item => $qty) {
echo "{$item} × {$qty}<br>";
}
?>
<form method='POST'>
<button name='add' value='PHP Tutorial'>Add PHP Tutorial</button>
<button name='add' value='MySQL Basics'>Add MySQL Basics</button>
</form>
Output:
TEXT
📖 Display only
Output displayed
4. Building a Login System
▶ Example: Complete Login System
Output:
TEXT
📖 Display only
(no visible output)
PHP
<?php
// login.php — Login System
session_start();
// Predefined test users (in a real project, these live in a database)
$users = [
'admin' => '123456',
'john' => 'password123',
];
$error = '';
// Already logged in? Redirect to profile
if (isset($_SESSION['user'])) {
header("Location: profile.php");
exit;
}
// Handle login request
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
if (isset($users[$username]) && $users[$username] === $password) {
// Credentials verified — store user in session
$_SESSION['user'] = [
'username' => $username,
'login_time' => date("Y-m-d H:i:s"),
'last_active' => time(),
];
// Redirect to profile page
header("Location: profile.php");
exit;
} else {
$error = "Invalid username or password";
}
}
?>
<h3>Login</h3>
<?php if ($error): ?>
<p style="color:red"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>
<form method="POST" action="">
<p>
<label>Username:</label>
<input type="text" name="username" required>
</p>
<p>
<label>Password:</label>
<input type="password" name="password" required>
</p>
<button type="submit">Log In</button>
</form>
<p style="color:#888">Test account: admin / 123456</p>
Output:
TEXT
📖 Display only
Username: admin
Logged in at: 2025-01-15 10:30:00
PHP
<?php
// profile.php — Profile Page (requires login)
session_start();
// Not logged in? Redirect to login
if (!isset($_SESSION['user'])) {
header("Location: login.php");
exit;
}
$user = $_SESSION['user'];
?>
<h2>Profile</h2>
<p>Username: <?= htmlspecialchars($user['username']) ?></p>
<p>Logged in at: <?= $user['login_time'] ?></p>
<a href="logout.php">Log Out</a>
(1) Logging Out
PHP
<?php
// logout.php
session_start();
// Option 1: Clear only the user data
unset($_SESSION['user']);
// Option 2: Wipe the entire session
session_unset(); // Clear the $_SESSION array
session_destroy(); // Delete the server-side session file
// Redirect to login
header("Location: login.php");
exit;
?>
| Operation | Function | What It Does |
|---|---|---|
| Remove single item | unset($_SESSION['key']) |
Deletes a specific key |
| Clear all variables | session_unset() |
Empties $_SESSION |
| Delete session file | session_destroy() |
Removes server-side session data |
| Delete cookie | setcookie(session_name(), '', time()-3600, '/') |
Removes the PHPSESSID cookie from the browser |
💡 Tip: The standard logout sequence:
session_unset() → session_destroy() → delete the PHPSESSID cookie → redirect to the login page.
5. The Session Lifecycle
TEXT
📖 Display only
User visits for the first time → PHP creates a session file (e.g., sess_abc123)
↓
Data is written to $_SESSION
↓
Cookie sent: PHPSESSID=abc123 to the browser
↓
Next visit → Browser sends PHPSESSID=abc123
↓
PHP finds sess_abc123, loads data into $_SESSION
↓
... User leaves (closes browser or is idle for a long time) ...
↓
Garbage collection → Expired session files are deleted
Sessions expire by default after 24 minutes (session.gc_maxlifetime = 1440 seconds in php.ini). The clock starts from the file's last modification time, not the user's last activity.
6. Session Security Configuration
PHP
<?php
// Configure before session_start()
ini_set('session.cookie_httponly', 1); // JS can't read the session cookie (XSS protection)
ini_set('session.cookie_secure', 1); // HTTPS only (required for production)
ini_set('session.cookie_samesite', 'Lax'); // CSRF mitigation
ini_set('session.use_strict_mode', 1); // Reject uninitialized session IDs
session_start();
?>
💡 Tip:
session.use_strict_mode = 1 prevents attackers from fabricating a Session ID. If an attacker invents a non-existent ID, PHP rejects it and creates a fresh session instead.
7. Cookies vs Sessions at a Glance
| Cookie | Session | |
|---|---|---|
| Data location | User's browser | Server |
| Security | Low (user can view/edit) | High (user never sees the data) |
| Capacity | 4KB | Unlimited (limited only by server disk) |
| Performance | Sent with every request | No bandwidth cost (server-side lookup) |
| Dependency | Standalone | Depends on cookies (for Session ID) |
| Best for | Preferences, light state | Login, permissions, shopping carts |
▶ Example: Session Destroy and Regenerate ID
Output:
TEXT
📖 Display only
Page views this session: " . value['views'] . "<br>
Session destroyed and ID regenerated
PHP
<?php
session_start();
$_SESSION['views'] = ($_SESSION['views'] ?? 0) + 1;
echo "Page views this session: " . $_SESSION['views'] . "<br>";
if (isset($_GET['reset'])) {
session_unset();
session_destroy();
session_start();
session_regenerate_id(true);
echo "Session destroyed and ID regenerated";
}
?>
<a href="?reset=1">Reset Session</a>
Output:
TEXT
📖 Display only
Output displayed
❓ FAQ
Q Does the session disappear when I close the browser?
A The session data still exists on the server (waiting for garbage collection), but the PHPSESSID cookie in the browser typically disappears when the browser closes. The next time you open the browser, there's no Session ID, so PHP creates a brand new session.
Q If multiple users log in at the same time, do their sessions interfere?
A No. Every user gets their own session with a unique Session ID.
$_SESSION always belongs to the current user — there's no cross-contamination.Q Can sessions work if the user has disabled cookies?
A Not by default, because the Session ID travels via cookie. You can pass it through the URL (
PHPSESSID=abc123), but this is very unsafe — the Session ID ends up in browser history, bookmarks, and server logs.📖 Summary
- Session data lives on the server; only the Session ID travels in a cookie
session_start()must be called before any output$_SESSIONbehaves like any other associative array- Login flow: validate credentials →
$_SESSION['user'] = ...→ redirect - Logout:
session_unset()+session_destroy()+ redirect - Security: httponly + secure + samesite + strict_mode
- Sessions are ideal for login state, shopping carts, and permission data
📝 Exercises
- Deploy the complete login system from the examples above (login.php → profile.php → logout.php).
- Add a "Change Password" feature to the profile page (validate against the predefined users array).
- Implement simple role-based access: only users with
role === 'admin'can see an "Admin Panel" link on the page.