Skip to content

PHP Cookies — Setting, Reading, and Securing HTTP Cookies

DodaTech Updated 2026-06-28 9 min read

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.

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]);

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.

<?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

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.

setcookie('data', str_repeat('x', 5000));  // May be rejected

Cookies are limited to about 4KB. Use sessions for larger data.

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

  1. 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.

  2. What does the HttpOnly flag do? It prevents JavaScript from accessing the cookie via document.cookie, mitigating XSS Attacks.

  3. How do you delete a cookie? Call setcookie with the same name and an expiration in the past.

  4. 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.

  5. 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

How many cookies can a domain set?

Most browsers allow at least 50 cookies per domain. The total size of all cookies for a domain should stay under 4KB each and 50 total.

Can cookies work over HTTP instead of HTTPS?

Yes, but the Secure flag requires HTTPS. Without it, cookies are sent in plain text. Always use Secure for authentication cookies.

What happens if the user blocks cookies?

setcookie returns false but no error is shown. Check with headers_list() or test by reading back the cookie on the next request.

What is the difference between session cookies and persistent cookies?

Session cookies have no expiration (expires=0) and are deleted when the browser closes. Persistent cookies have an expiration date and survive browser restarts.

Can I read cookies set by JavaScript in PHP?

Yes, PHP $_COOKIE includes all cookies sent by the browser regardless of how they were set, as long as they are not HttpOnly.

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