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
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
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 ( |
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
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
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"
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
setcookie('theme', '', time() - 3600, '/');
unset($_COOKIE['theme']); // also clear it for the rest of this scriptSize 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$_COOKIEduring the current script.Always set
httponlyunless client-side JavaScript genuinely needs to read the cookie.secureshould 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.