PHP Cookies — Setting, Reading, and Securing HTTP Cookies
In this tutorial, you will learn about PHP Cookies. We cover key concepts, practical examples, and best practices to help you master this topic.
PHP cookies are small text files stored on the client browser, set via the setcookie function and read through the $_COOKIE superglobal, enabling persistent user preferences across sessions and visits.
Why It Matters
Cookies are the oldest and most widely supported mechanism for storing data on the client side. Unlike sessions, cookies survive browser restarts (unless set to expire on close). They are essential for remembering user preferences like language, theme, or "Remember Me" login tokens. However, cookies have size limits (4KB), are sent with every request, and are visible to the user, so they must never store sensitive data.
Real-World Use
Google Analytics uses cookies to track returning visitors. E-commerce sites store recently viewed items in cookies. WordPress uses cookies for comment authentication and admin login. Social media platforms use cookies for "Like" buttons across the web. Content sites store cookie consent preferences. DodaTech uses cookies to remember user theme preferences and tutorial progress indicators.
What You Will Learn
- Setting cookies with setcookie() and its parameters
- Reading cookies from $_COOKIE
- Cookie expiration, path, domain, and security flags
- Practical cookie use cases: themes, preferences, remember-me
- Cookie security: httponly, secure, samesite
- Deleting cookies and handling cookie consent
Learning Path
flowchart LR A[Sessions] --> B[Cookies
You are here] B --> C[Headers] C --> D[File Upload] D --> E[JSON API] style B fill:#f90,color:#fff
Setting Cookies
Use setcookie() to send a cookie to the browser. It must be called before any HTML output:
<?php
// Basic cookie - expires when browser closes
setcookie('theme', 'dark');
// Cookie that expires in 30 days
setcookie('preference', 'compact', time() + 86400 * 30);
// Cookie with all parameters
setcookie(
'user_token', // Name
'abc123def456', // Value
time() + 86400 * 7, // Expires in 7 days
'/', // Path (available everywhere)
'example.com', // Domain
true, // Secure (HTTPS only)
true // HttpOnly (not accessible via JS)
);
echo "Cookies set successfully.";
setcookie Parameters
The function signature is setcookie(string $name, string $value = '', int $expires = 0, string $path = '', string $domain = '', bool $secure = false, bool $httponly = false): bool
<?php
setcookie('name', 'value', [
'expires' => time() + 86400,
'path' => '/',
'domain' => '.example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
Reading Cookies
PHP automatically populates $_COOKIE with cookie values sent by the browser:
<?php
$theme = $_COOKIE['theme'] ?? 'light';
echo "Current theme: $theme";
// Check if cookie exists
if (isset($_COOKIE['user_token'])) {
$token = $_COOKIE['user_token'];
echo "User token found: " . substr($token, 0, 8) . "...";
}
Note: $_COOKIE is populated when the page loads, not when setcookie() is called. A cookie set on one page is available in $_COOKIE on the next page load.
Cookie Parameters Explained
Expires
Controls how long the cookie persists:
<?php
// Session cookie (deleted when browser closes)
setcookie('temp', 'value', 0);
// Cookie for specific duration
setcookie('one_hour', 'v', time() + 3600); // 1 hour
setcookie('one_week', 'v', time() + 86400 * 7); // 7 days
setcookie('one_year', 'v', time() + 86400 * 365); // 365 days
// Cookie in the past (deletes it)
setcookie('old_cookie', '', time() - 3600);
Path
Restricts the cookie to specific URL paths:
<?php
// Available everywhere on the domain
setcookie('global', 'v', 0, '/');
// Only available in /admin/ directory
setcookie('admin_pref', 'v', 0, '/admin/');
Domain
Controls which domains receive the cookie:
<?php
// Exact domain
setcookie('exact', 'v', 0, '/', 'example.com');
// Subdomain wildcard (including all subdomains)
setcookie('subdomains', 'v', 0, '/', '.example.com');
Secure Flag
Only send the cookie over HTTPS:
<?php
// Only over HTTPS
setcookie('secure_cookie', 'sensitive', 0, '/', '', true, false);
HttpOnly Flag
Prevent JavaScript from accessing the cookie (best for session cookies):
<?php
// Not accessible via document.cookie
setcookie('session_id', $id, 0, '/', '', true, true);
SameSite Attribute
Controls when cookies are sent with cross-site requests:
<?php
// Lax: sent for top-level navigation GET requests
setcookie('lax_cookie', 'v', ['samesite' => 'Lax']);
// Strict: never sent with cross-site requests
setcookie('strict_cookie', 'v', ['samesite' => 'Strict']);
// None: always sent (requires Secure flag)
setcookie('cross_site', 'v', ['samesite' => 'None', 'secure' => true]);
Practical Cookie Use Cases
Theme Switcher
Let users choose between light and dark themes:
<?php
// Set theme (when user toggles)
if (isset($_GET['theme'])) {
$allowed = ['light', 'dark', 'auto'];
$theme = in_array($_GET['theme'], $allowed) ? $_GET['theme'] : 'light';
setcookie('theme', $theme, time() + 86400 * 365, '/');
header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
exit;
}
// Read current theme
$theme = $_COOKIE['theme'] ?? 'light';
?>
<!DOCTYPE html>
<html data-theme="<?= htmlspecialchars($theme) ?>">
<body>
<a href="?theme=light">Light</a>
<a href="?theme=dark">Dark</a>
</body>
</html>
Remember Me Functionality
Persist login across browser restarts:
<?php
function createRememberMeToken(int $userId): string {
$token = bin2hex(random_bytes(32));
$hash = hash('sha256', $token);
// Store hash in database
$stmt = $pdo->prepare(
'INSERT INTO remember_tokens (user_id, token_hash, expires)
VALUES (?, ?, ?)'
);
$stmt->execute([$userId, $hash, time() + 86400 * 30]);
// Set cookie
setcookie('remember', "$userId:$token",
time() + 86400 * 30, '/', '', true, true);
return $token;
}
function validateRememberMeToken(): ?int {
if (!isset($_COOKIE['remember'])) return null;
[$userId, $token] = explode(':', $_COOKIE['remember'], 2);
$hash = hash('sha256', $token);
$stmt = $pdo->prepare(
'SELECT user_id FROM remember_tokens
WHERE user_id = ? AND token_hash = ? AND expires > ?'
);
$stmt->execute([(int)$userId, $hash, time()]);
return $stmt->fetchColumn() ?: null;
}
Deleting Cookies
To delete a cookie, set it with an expiration in the past:
<?php
// Delete a cookie
setcookie('old_cookie', '', time() - 3600, '/');
// Verify it was deleted
if (!isset($_COOKIE['old_cookie'])) {
echo "Cookie deleted";
}
You must match the same path and domain parameters used when setting the cookie.
Cookie Limitations
<?php
// Maximum cookie size is about 4KB
// You cannot set more than ~50 cookies per domain
// Cookies are included in EVERY request to the domain
// Bad: storing too much data
setcookie('large_data', json_encode($bigArray), time() + 3600);
// Use session storage or local storage for large data
// Bad: storing sensitive data
setcookie('credit_card', '4111-1111-1111-1111', time() + 86400);
// Never store sensitive data in cookies - they are visible to users
Cookie Consent (GDPR)
Modern web applications require cookie consent:
<?php
// Check if user has consented
$consent = $_COOKIE['cookie_consent'] ?? false;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['accept_cookies'])) {
setcookie('cookie_consent', 'accepted', time() + 86400 * 365, '/');
setcookie('analytics', 'enabled', time() + 86400 * 365, '/');
header('Location: ' . $_SERVER['REQUEST_URI']);
exit;
}
// Only set analytics cookies if consented
if ($consent === 'accepted') {
// Set tracking cookies here
}
?>
Common Mistakes
1. Calling setcookie After Output
echo "<html>";
setcookie('test', 'value'); // Warning: headers already sent
Call setcookie() before any HTML, echo, or whitespace. Use output buffering if needed.
2. Not Considering Cookie Size Limits
setcookie('data', str_repeat('x', 5000)); // May be rejected
Cookies are limited to about 4KB. Use sessions for larger data.
3. Expecting $_COOKIE to Update Immediately
setcookie('test', 'new');
echo $_COOKIE['test']; // Still shows old value or undefined
Cookies are populated from the HTTP request, not from setcookie(). The new value appears on the next page load.
4. Storing Sensitive Data in Cookies
setcookie('password', $password); // Visible in browser dev tools
Never store passwords, tokens, or personal data in plain cookies.
5. Not Matching Path/Domain When Deleting
setcookie('test', 'value', 0, '/admin');
// ...
setcookie('test', '', time() - 3600); // Wrong path, cookie not deleted
Use the exact same path and domain when deleting.
Practice Questions
How does setcookie differ from $_COOKIE? setcookie sends a cookie to the browser via HTTP headers. $_COOKIE reads cookies sent by the browser in the current request.
What does the HttpOnly flag do? It prevents JavaScript from accessing the cookie via document.cookie, mitigating XSS Attacks.
How do you delete a cookie? Call setcookie with the same name and an expiration in the past.
What is the SameSite attribute and why is it important? It controls whether cookies are sent with cross-site requests, helping prevent CSRF Attacks. Values: Lax, Strict, None.
Challenge: Build a complete cookie consent system that shows a banner, stores user preferences, and only sets analytics cookies after consent.
Mini Project: User Preferences Manager
Create a script that manages user preferences via cookies:
<?php
$defaults = [
'theme' => 'light',
'language' => 'en',
'font_size' => 'medium',
'sidebar' => 'visible',
];
$preferences = [];
foreach ($defaults as $key => $default) {
$preferences[$key] = $_COOKIE['pref_' . $key] ?? $default;
}
// Update preferences
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
foreach ($defaults as $key => $default) {
if (isset($_POST[$key])) {
$value = $_POST[$key];
setcookie('pref_' . $key, $value,
time() + 86400 * 365, '/', '', true, true);
$preferences[$key] = $value;
}
}
header('Location: ' . $_SERVER['REQUEST_URI']);
exit;
}
?>
<!DOCTYPE html>
<html lang="<?= htmlspecialchars($preferences['language']) ?>">
<head>
<style>
body { font-size: <?= $preferences['font_size'] === 'large' ? '20px' : ($preferences['font_size'] === 'small' ? '14px' : '16px') ?>; }
.sidebar { display: <?= $preferences['sidebar'] === 'visible' ? 'block' : 'none' ?>; }
</style>
</head>
<body class="<?= htmlspecialchars($preferences['theme']) ?>">
<form method="post">
<label>Theme:
<select name="theme">
<option value="light" <?= $preferences['theme'] === 'light' ? 'selected' : '' ?>>Light</option>
<option value="dark" <?= $preferences['theme'] === 'dark' ? 'selected' : '' ?>>Dark</option>
</select>
</label>
<label>Font Size:
<select name="font_size">
<option value="small" <?= $preferences['font_size'] === 'small' ? 'selected' : '' ?>>Small</option>
<option value="medium" selected>Medium</option>
<option value="large">Large</option>
</select>
</label>
<button type="submit">Save Preferences</button>
</form>
</body>
</html>
FAQ
What is Next
Now that you understand cookies, proceed to Headers to learn HTTP header manipulation for redirects, content types, and Caching. Then read File Upload to handle file uploads securely.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro