21. PHP Sessions and Cookies
What you will learn
- Why websites need to remember visitors
- How cookies and sessions differ
- How to start a session and store data
- How to build a simple login-style flow safely
The problem: HTTP forgets
Every page request is separate. The server does not remember that the same visitor loaded the last page. To keep a shopping basket or a login, the site must give the browser something to carry from page to page.
Cookies
A cookie is a small piece of text stored in the visitor’s browser. The browser sends it back with every request to your site.
PHP code: set-cookie.php
<?php
setcookie("theme", "dark", [
"expires" => time() + 60 * 60 * 24 * 30, // 30 days
"path" => "/",
"secure" => false, // set to true on a live HTTPS site
"httponly" => true,
"samesite" => "Lax",
]);
echo "Cookie sent. Open read-cookie.php next.";
PHP code: read-cookie.php
<?php
$theme = $_COOKIE["theme"] ?? "light";
echo "Your theme is: " . htmlspecialchars($theme, ENT_QUOTES, "UTF-8");
Output on read-cookie.php after visiting set-cookie.php first
Your theme is: dark
setcookie()must run before any output.- A cookie set on one request appears in
$_COOKIEonly from the next request. httponlyhides the cookie from JavaScript, andsecuresends it only over HTTPS.samesitelimits sending it from other sites.- To delete a cookie, set it again with an
expirestime in the past.
Cookies are controlled by the visitor. They can read, change, or delete them. Never trust a cookie, and never store passwords or private data in one. Cookies that are not strictly necessary may need visitor consent under privacy laws such as the GDPR, so check the rules for your audience.
Sessions
A session keeps data on the server. The browser holds only a random session ID in a cookie. PHP uses the ID to find the right data. This is why sessions are the right place for logins and baskets.
PHP code: visits.php
<?php
session_start();
if (!isset($_SESSION["visits"])) {
$_SESSION["visits"] = 0;
}
$_SESSION["visits"]++;
echo "You have loaded this page " . $_SESSION["visits"] . " time(s) in this session.";
Output after loading the page three times
You have loaded this page 3 time(s) in this session.
- Call
session_start()at the very top, before any output, on every page that uses the session. - Store data in
$_SESSION, which works like any associative array.
Cookie or session?
| Cookie | Session | |
|---|---|---|
| Stored | In the browser | On the server (the browser keeps an ID) |
| Visitor can edit it | Yes | No, only the ID |
| Size | Small (about 4 KB) | Much larger |
| Lasts | As long as you set | Until the browser closes or it expires |
| Use for | Harmless preferences such as a theme | Logins, baskets, form tokens |
A simple login flow
This example shows the idea with a fixed user so you can see the moving parts. A real site stores users in a database and checks passwords with password_verify(), as the next lessons explain.
PHP code: login.php
<?php
session_start();
$error = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$user = trim($_POST["username"] ?? "");
$pass = $_POST["password"] ?? "";
// Demo only: a real site checks a stored password HASH
$demo_hash = password_hash("secret123", PASSWORD_DEFAULT);
if ($user === "sam" && password_verify($pass, $demo_hash)) {
session_regenerate_id(true); // new ID after login
$_SESSION["user"] = "sam";
header("Location: dashboard.php");
exit;
}
$error = "Wrong username or password.";
}
?>
<form method="post">
<label for="u">Username</label>
<input type="text" id="u" name="username">
<label for="p">Password</label>
<input type="password" id="p" name="password">
<button type="submit">Log in</button>
</form>
<p><?= htmlspecialchars($error, ENT_QUOTES, "UTF-8") ?></p>
PHP code: dashboard.php
<?php
session_start();
if (!isset($_SESSION["user"])) {
header("Location: login.php");
exit;
}
echo "Welcome, " . htmlspecialchars($_SESSION["user"], ENT_QUOTES, "UTF-8") . "! ";
echo '<a href="logout.php">Log out</a>';
PHP code: logout.php
<?php
session_start();
$_SESSION = [];
if (ini_get("session.use_cookies")) {
$p = session_get_cookie_params();
setcookie(session_name(), "", time() - 3600, $p["path"], $p["domain"], $p["secure"], $p["httponly"]);
}
session_destroy();
header("Location: login.php");
exit;
What happens
Wrong password: the login page shows “Wrong username or password.”
Username sam and password secret123: the browser moves to the dashboard, which says “Welcome, sam!”
Visiting the dashboard without logging in sends you to the login page. Logging out clears the session.
Session security habits
- Call
session_regenerate_id(true)right after a successful login, to stop session fixation. - Protect every private page by checking
$_SESSIONat the top, thenexitafter the redirect. - Use HTTPS on a live site, and mark session cookies
secureandhttponly. - Never put the session ID in a web address.
- Store as little as possible in a session, and never store a plain password.
- Offer a logout that destroys the session fully.
WordPress handles logins for you with its own, carefully tested system. Do not build a login for WordPress by hand. Use its built-in accounts, roles, and plugins.
Common mistakes
- Output before
session_start()orsetcookie(), giving “headers already sent”. - Forgetting
session_start()on one of the pages. - Expecting a new cookie to be readable in the same request.
- Trusting cookie values.
- Forgetting
exitafter a redirect, so the page keeps running. - Not regenerating the session ID after login.
Exercise
Write a page that uses a session to remember a visitor’s chosen colour. If ?color=blue is in the address, save it (only if it is red, green, or blue). Always print Your colour is: followed by the saved value, or none.
Show solution
<?php
session_start();
$allowed = ["red", "green", "blue"];
$color = $_GET["color"] ?? "";
if (in_array($color, $allowed, true)) {
$_SESSION["color"] = $color;
}
echo "Your colour is: " . htmlspecialchars($_SESSION["color"] ?? "none", ENT_QUOTES, "UTF-8");
Visit it with ?color=blue, then again with no query. It should still say blue.
Knowledge check
1. Where is a cookie stored, and where is session data stored?
Cookies are stored in the browser. Session data is stored on the server.
2. Which function must run first on every page that uses a session?
session_start()
3. Why call session_regenerate_id(true) after login?
To prevent session fixation, where an attacker plants a known session ID.
Summary
- Cookies live in the browser and can be edited, so use them only for harmless preferences.
- Sessions keep data on the server, and the browser holds only an ID.
- Start sessions before output, regenerate the ID on login, protect private pages, and log out properly.