PHP Cookies and Sessions
PHP Cookies
Cookies, or browser cookies, are small pieces of data which the web server asks the client’s web browser to store. Each request back to the server will include these pieces of data. The data is organized as key/value pairs.
A cookie can be set using PHP’s setcookie() function.
<?php
setcookie('language', 'english');
?>
On future requests, the cookie key/value pairs will be assigned to the $_COOKIE superglobal.
<?php
echo $_COOKIE['language'];
// english
?>
In addition to the $name and $value arguments, setcookie() also accepts many other arguments for configuration. Since PHP 7.3, an array of options can be passed in place of the positional $expires, $path, $domain, $secure, and $httponly arguments. The array form is preferred because it is the only form that supports the samesite attribute.
<?php
$name = 'language';
$value = 'english';
// Note: isset($_SERVER['HTTPS']) is unreliable — some servers (e.g. IIS) set
// $_SERVER['HTTPS'] to 'off' for plain HTTP, and isset() still returns true.
$is_https = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
setcookie($name, $value, [
'expires' => time() + 60*60*24*3, // 3 days from now
'path' => '/blog',
'domain' => 'www.mysite.com',
'secure' => $is_https,
'httponly' => true,
'samesite' => 'Lax', // or 'Strict'; 'None' requires secure => true
]);
?>
Many of these configuration arguments are important for preventing attacks such as Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), Cookie Theft and Manipulation, Session Hijacking, and Session Fixation. SameSite=Lax (or Strict) is the first line of defense against CSRF in modern browsers; HttpOnly blocks JavaScript-based session theft via XSS; and Secure ensures the cookie is only transmitted over HTTPS.
For sensitive cookies, consider the __Host- cookie name prefix. A cookie whose name starts with __Host- is rejected by the browser unless it is set with the Secure attribute from an HTTPS page, has no Domain attribute, and uses Path=/. This pins the cookie to the exact host that set it, so other hosts on the domain cannot overwrite it (MDN: cookie prefixes). The example above cannot use the prefix because it sets domain and a /blog path. A __Host- cookie leaves out the domain key (so setcookie() sends no Domain attribute), sets path to '/', and sets secure to true:
<?php
setcookie('__Host-language', 'english', [
'expires' => time() + 60*60*24*3, // 3 days from now
'path' => '/', // required for __Host-
'secure' => true, // required for __Host-; only set this cookie over HTTPS
'httponly' => true,
'samesite' => 'Lax',
// no 'domain' key: a __Host- cookie must not have a Domain attribute
]);
?>
PHP Sessions
Sessions are an alternative to cookies. A session is usually a file or database record on the server side which contains the small pieces of data which the server wants to store for each user. Instead of sending key/value pairs to the browser, these values are stored on the server, and only a reference identifier (“session ID”) is sent to the user’s browser as a cookie. This session ID needs to be a long and unique string. On each future request, the browser will send the session ID as a cookie and the server will locate the corresponding session to allow access to the stored user data.
In PHP it is important to always initialize sessions using session_start(). After being initialized, session values can be set and retrieved using the $_SESSION superglobal.
<?php
session_start();
$_SESSION['user_id'] = 42;
echo $_SESSION['user_id'];
// 42
?>
A session can also be unset and destroyed when expired or no longer needed. If not unset/destroyed, then the session file and session data will remain on the server unless the file or database storage for the session is deleted.
<?php
// session_unset() clears the $_SESSION variables; session_destroy()
// removes the session data stored on the server. Note that neither
// deletes the session ID cookie from the browser.
session_unset();
session_destroy();
?>
There are several configurations for PHP sessions which can be set in the php.ini file.
session.use_strict_mode = 1
session.use_only_cookies = 1
session.cookie_lifetime = 0 ; '0' = expire when browser closes
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
In PHP 7.3 or greater, it is also possible to set these values when the session is started.
<?php
session_start([
'use_strict_mode' => 1,
'use_only_cookies' => 1,
'cookie_lifetime' => 0,
'cookie_secure' => 1,
'cookie_httponly' => 1,
'cookie_samesite' => 'Lax'
]);
?>
Many of these configuration arguments are important for preventing attacks such as Cookie Theft and Manipulation, Session Hijacking, and Session Fixation. session.use_strict_mode is disabled by default, but the PHP manual calls enabling it mandatory for secure sessions: in strict mode PHP rejects session IDs it did not generate itself and issues a new one instead, which protects against session fixation via session adoption (PHP manual: securing session INI settings).