Session vs Cookie in PHP: Difference with Login Example
A cookie lives in the user's browser (user can see/edit it); a session lives on the server with only an ID cookie in the browser. Login example and security rules.
The locker analogy
Both in code — the login example
<?php
// ---------- SESSION: the right way to log someone in ----------
session_start(); // must be the FIRST thing (before any HTML!)
// after verifying username+password from DB:
$_SESSION['user_id'] = 27; // stored ON SERVER
$_SESSION['role'] = 'admin';
// on every protected page:
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: login.php'); // not logged in -> out
exit;
}
// logout:
session_start();
session_destroy(); // locker emptied
?>
<?php
// ---------- COOKIE: the right way to remember a preference ----------
setcookie('theme', 'dark', time() + 86400*30, '/'); // 30 days, whole site
// NOTE: setcookie() also must run before any HTML output!
// on next visits:
$theme = $_COOKIE['theme'] ?? 'light'; // read what the browser carried back
echo "Theme: " . htmlspecialchars($theme);
?>
The security point that decides interviews
// NEVER do this:
setcookie('is_admin', '1'); // user opens DevTools -> Application ->
// Cookies -> changes 0 to 1 -> "admin"!
// ALWAYS do this:
$_SESSION['is_admin'] = true; // lives on server - user cannot touch it
Comparison table
| Point | Cookie | Session |
|---|---|---|
| Data lives | User's browser | Server (file/DB); browser keeps only ID |
| User can read/edit | ✅ Yes (DevTools) | ❌ No |
| Lifetime | You set expiry (days/months) | Ends on browser close / timeout (~24 min default) |
| Size limit | ~4KB per cookie | Practically large |
| Sent with every request | ✅ Yes (adds weight) | Only the small ID |
| Start with | setcookie() | session_start() |
| Read with | $_COOKIE | $_SESSION |
| Best for | Theme, language, "remember me" token | Login state, cart, OTP verification, roles |
Two traps every PHP beginner hits
- "Headers already sent" error: both
session_start()andsetcookie()travel in HTTP headers, so they must run before any output — even a single space before<?phptriggers it. Rule: session_start() is line 1. - Cookie not visible immediately: setcookie() sends the cookie with this response; $_COOKIE gets filled from the request — so the value appears only from the next page load. Not a bug; that is how the round-trip works.
- Interview line: "Cookie = client-side, user-editable, long-lived — for preferences. Session = server-side, tamper-proof, short-lived — for identity. They cooperate: the session ID itself rides in a cookie."
Locker वाली analogy
दोनों code में — login example
<?php
// ---------- SESSION: login कराने का सही तरीका ----------
session_start(); // सबसे PEHLI चीज़ (किसी भी HTML से पहले!)
// DB से username+password verify करने के बाद:
$_SESSION['user_id'] = 27; // SERVER par stored
$_SESSION['role'] = 'admin';
// हर protected page पर:
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: login.php'); // login नहीं -> बाहर
exit;
}
// logout:
session_start();
session_destroy(); // locker खाली
?>
<?php
// ---------- COOKIE: preference याद रखने का सही तरीका ----------
setcookie('theme', 'dark', time() + 86400*30, '/'); // 30 दिन, पूरी site
// NOTE: setcookie() भी किसी भी HTML output से पहले चलना चाहिए!
// अगली visits पर:
$theme = $_COOKIE['theme'] ?? 'light'; // browser जो वापस लाया वह पढ़ो
echo "Theme: " . htmlspecialchars($theme);
?>
वह security point जो interview तय करता है
// ऐसा KABHI न करें:
setcookie('is_admin', '1'); // user ने DevTools खोला -> Application ->
// Cookies -> 0 को 1 किया -> "admin"!
// HAMESHA ऐसा करें:
$_SESSION['is_admin'] = true; // server पर रहता है - user छू नहीं सकता
Comparison table
| Point | Cookie | Session |
|---|---|---|
| Data रहता है | User के browser में | Server पर (file/DB); browser में सिर्फ ID |
| User पढ़/बदल सकता है | ✅ हां (DevTools) | ❌ नहीं |
| Lifetime | आप expiry set करते हैं (दिन/महीने) | Browser बंद / timeout पर खत्म (~24 min default) |
| Size limit | ~4KB प्रति cookie | Practically बड़ा |
| हर request के साथ जाता है | ✅ हां (वज़न बढ़ाता है) | सिर्फ छोटी ID |
| शुरू करें | setcookie() | session_start() |
| पढ़ें | $_COOKIE | $_SESSION |
| Best for | Theme, language, "remember me" token | Login state, cart, OTP verification, roles |
दो traps जो हर PHP beginner को लगते हैं
- "Headers already sent" error:
session_start()औरsetcookie()दोनों HTTP headers में जाते हैं, इसलिए किसी भी output से पहले चलने चाहिए —<?phpसे पहले एक space भी यह error दे देता है. Rule: session_start() line 1 पर. - Cookie तुरंत नहीं दिखती: setcookie() cookie को इस response के साथ भेजता है; $_COOKIE request से भरता है — इसलिए value अगले page load से दिखती है. Bug नहीं; round-trip ऐसे ही काम करता है.
- Interview line: "Cookie = client-side, user-editable, लंबी उम्र — preferences के लिए. Session = server-side, tamper-proof, छोटी उम्र — identity के लिए. दोनों साथ काम करते हैं: session ID खुद cookie में सफर करती है."
Frequently Asked Questions
What is the difference between session and cookie?
A cookie stores data in the user's browser where the user can read and edit it; a session stores data on the server with only a random session ID kept in a browser cookie — so sensitive data like login state belongs in sessions.
Why should login status never be stored in a cookie?
Because cookies are fully editable in browser DevTools — a user could change is_admin from 0 to 1; session data lives on the server where the user cannot modify it.
Why does session_start() give a headers already sent error?
session_start() sends an HTTP header, and headers must go before any output — even one space or blank line before <?php causes the error, so call it as the very first statement.
