PHPCookies ($_COOKIE)

Cookies ($_COOKIE)

A cookie is a small piece of text that a server asks the browser to store, and that the browser then sends back with every later request to the same site. PHP exposes cookies that arrived with the current request through the $_COOKIE superglobal, and lets you ask the browser to store a new one with the setcookie() function. Cookies are how a stateless protocol like HTTP can remember something about a visitor between separate page loads — things like a "remember me" preference, a shopping cart id, or a session identifier.

Setting a cookie

setcookie() sends a Set-Cookie header to the browser, so — just like header() — it must be called before any HTML or other output has been sent. The classic signature takes a name, a value, and a handful of attributes that control where and how long the cookie applies.

Setting a cookie with setcookie()

PHP
<?php
setcookie(
    'theme',          // name
    'dark',           // value
    time() + 86400,   // expires: 1 day from now (Unix timestamp)
    '/',              // path: available on the whole site
    '',               // domain: default to the current host
    true,             // secure: only sent over HTTPS
    true              // httponly: not readable from JavaScript
);

Since PHP 7.3, there is also an array form that lets you set the samesite attribute directly instead of appending it to the path string as older code used to do.

setcookie() with the options array

PHP
<?php
setcookie('theme', 'dark', [
    'expires' => time() + 86400,
    'path' => '/',
    'domain' => '',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax', // 'Strict', 'Lax', or 'None'
]);
What each attribute actually controls

Attribute

What it does

expires

A Unix timestamp for when the cookie should be deleted. Leaving it out (or 0) makes it a session cookie, cleared when the browser closes.

path

Restricts the cookie to URLs under this path. '/' means the whole domain.

domain

Which host(s) the cookie is sent to. Leave empty to default to the exact host that set it.

secure

The browser will only send this cookie over an HTTPS connection, never plain HTTP.

httponly

Blocks JavaScript (document.cookie) from reading the cookie, which limits damage from an XSS bug.

samesite

Controls whether the cookie is sent on cross-site requests, which helps mitigate CSRF.

Reading a cookie back

Once a cookie has been stored, the browser attaches it to every matching request automatically, and PHP decodes it into $_COOKIE for you to read like any other array.

Reading $_COOKIE

PHP
<?php
if (isset($_COOKIE['theme'])) {
    $theme = $_COOKIE['theme'];
} else {
    $theme = 'light'; // sensible default
}

echo "Using theme: " . htmlspecialchars($theme, ENT_QUOTES, 'UTF-8');
Using theme: dark
The gotcha: cookies apply on the NEXT request

setcookie() only queues a Set-Cookie response header — it does not retroactively make the value available in $_COOKIE during the same script run. The browser has to receive the response, store the cookie, and send it back on a future request before PHP will see it in $_COOKIE. Beginners often write code like this and are confused when it does not print what they expect.

This will NOT print 'dark' on this request

PHP
<?php
setcookie('theme', 'dark', time() + 86400, '/');

// $_COOKIE['theme'] is still whatever it was BEFORE this script ran
// (unset, on a brand-new visitor) — setcookie() does not update it.
var_dump($_COOKIE['theme'] ?? 'not set yet');
string(11) "not set yet"
Don't test cookies by setting and reading them in one script
If you need the value immediately for logic later in the same request, store it in a local variable alongside the `setcookie()` call rather than reading it back from `$_COOKIE`. Reload the page (or write a separate test script) to confirm the cookie actually persisted across requests.
Deleting a cookie

There is no deletecookie() function. To remove a cookie you call setcookie() again with the same name, path, and domain it was originally set with, but with an expiration timestamp in the past. The browser sees an already-expired cookie and discards it.

Deleting a cookie

PHP
<?php
setcookie('theme', '', time() - 3600, '/');
unset($_COOKIE['theme']); // also clear it for the rest of this script
Path and domain must match exactly
A cookie set with `path => '/account'` will not be deleted by a call using `path => '/'` — from the browser's point of view those are different cookies. If deletion silently "isn't working," the most common cause is a mismatched path or domain between the original `setcookie()` call and the one meant to clear it.
Size and count limits

Cookies are not a general-purpose storage mechanism. Most browsers cap an individual cookie at around 4KB, and also cap the number of cookies allowed per domain (commonly somewhere around 50 to a few hundred, depending on the browser). Every cookie for the current domain is also sent on every single request to that domain, adding overhead to every page load, image request, and API call. For anything beyond a small identifier or a short preference value, store the real data server-side (a database row, a session file) and keep only a reference — like a session id — in the cookie itself.

  • setcookie() queues a response header; it never affects $_COOKIE during the current script.

  • Always set httponly unless client-side JavaScript genuinely needs to read the cookie.

  • secure should be true on any site served over HTTPS, which today means almost every site.

  • Deleting a cookie means resetting it with a past expiration, using the exact same path and domain.

  • Keep cookie payloads small — a few bytes of identifier, not JSON blobs of user data.

Tip
If you only need a value to last until the browser closes, simply omit `expires` (or pass `0`). Not every cookie needs a long lifetime — a shorter-lived cookie is one less piece of state to worry about securing and expiring correctly.