Skip to content

PHP Cookies

Cookie 是一种在客户端(用户的浏览器)存储少量数据的机制,通常用于在会话之间识别用户或存储偏好设置(preferences)。

Cookie 是由服务器创建并由用户的 Web 浏览器存储在用户计算机上的一个小文件。当用户从同一服务器请求页面时,浏览器会将相关的 cookie 发送回请求。PHP 提供了创建、检索、修改和删除 cookie 值的功能。

常见的用途包括会话管理(session management)(尽管通常更推荐使用 PHP 的 Session)、个性化(personalization)(例如主题)以及跟踪用户行为(user behavior)(由于隐私问题,现在不太常见)。

使用 setcookie() 函数创建 Cookie。调用此函数至关重要,它必须在任何 HTML 输出发送到浏览器之前(在 <html>、<?php echo …; ?> 甚至空白符之前)执行。

setcookie(name, value, expires_or_options, path, domain, secure, httponly)
或者使用现代的选项数组(PHP 7.3+):
setcookie(name, value, [‘expires’ => expiration_timestamp, ‘path’ => ’/’, ‘domain’ => ‘example.com’, ‘secure’ => true, ‘httponly’ => true, ‘samesite’ => ‘Lax’])

  • name:Cookie 的名称(必需)。
  • value:要存储的值。会自动进行 URL 编码(URL-encoded)。
  • expires_or_options:(可选)过期时间戳(Unix timestamp)或一个选项数组(推荐)。将过期时间设置为过去的时间会删除该 cookie。
  • path:(可选)cookie 在服务器上的可用路径。’/’ 表示整个域。
  • domain:(可选)cookie 有效的域(例如,对于子域,可以使用 ‘.example.com’)。
  • secure:(可选,布尔值)如果为 true,则只通过 HTTPS 连接发送 cookie。强烈推荐。
  • httponly:(可选,布尔值)如果为 true,则无法通过客户端脚本(如 JavaScript)访问此 cookie,有助于减轻 XSS 攻击。强烈推荐。
  • samesite:(可选,字符串)控制跨站请求行为(‘None’、‘Lax’、‘Strict’)。有助于减轻 CSRF 攻击。‘Lax’ 通常是一个不错的默认值。

此示例创建一个名为 ‘user’、值为 ‘John Doe’ 的 cookie。它将在 30 天后过期,在整个站点范围内可用,并包含重要的安全标志(security flags)。

然后,我们使用 $_COOKIE 超全局数组(superglobal array)检索该值,并使用 isset() 检查它是否存在。

<?php
$cookie_name = "user";
$cookie_value = "John Doe";
$expiry = time() + (86400 * 30); // 86400 秒 = 1 天
$path = "/";
$domain = ""; // 当前域
$secure = true; // 仅通过 HTTPS 发送
$httponly = true; // 阻止 JavaScript 访问
// 使用选项数组的现代语法 (PHP 7.3+)
setcookie($cookie_name, $cookie_value, [
'expires' => $expiry,
'path' => $path,
// 'domain' => $domain, // 通常最好留空或明确设置
'secure' => $secure,
'httponly' => $httponly,
'samesite' => 'Lax' // 推荐的默认值
]);
/* // Older syntax (still works)
setcookie($cookie_name, $cookie_value, $expiry, $path, $domain, $secure, $httponly);
*/
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PHP Cookie Example</title>
</head>
<body>
<h1>Cookie Status</h1>
<?php
if (!isset($_COOKIE[$cookie_name])) {
echo "Cookie named '" . htmlspecialchars($cookie_name) . "' is not set!";
} else {
echo "Cookie '" . htmlspecialchars($cookie_name) . "' is set!<br>";
// 始终净化来自 cookie(或任何用户输入)的输出
echo "Value is: " . htmlspecialchars($_COOKIE[$cookie_name]);
}
?>
<p>**注意:**Cookie 可能不会在设置它们的同一页面加载中立即在 $_COOKIE 中可用。它们由浏览器在后续请求中发送。</p>
</body>
</html>
重要: setcookie() 函数必须在任何输出发送到浏览器之前调用(HTML、空白符、echo/print 语句)。否则,将导致“Headers already sent”警告,并且 cookie 将不会被设置。

注意:cookie 值在发送时会自动进行 URL 编码,并在接收时解码。如果您需要发送未经 URL 编码的值(很少需要),请使用 setrawcookie()。

要修改 cookie,只需使用相同的名称、新的值和/或过期时间再次调用 setcookie()。请确保使用与原始 cookie 相同的路径(path)、域(domain)、secure 和 httponly 设置。

<?php
$cookie_name = "user";
$new_value = "Alex Porter";
$expiry = time() + (86400 * 30);
$path = "/";
$secure = true;
$httponly = true;
// Set the cookie again with the new value
setcookie($cookie_name, $new_value, [
'expires' => $expiry,
'path' => $path,
'secure' => $secure,
'httponly' => $httponly,
'samesite' => 'Lax'
]);
?>
<!DOCTYPE html>
<html lang="en">
<head><title>Modify Cookie</title></head>
<body>
<h1>Modifying Cookie</h1>
<p>Cookie '<?php echo htmlspecialchars($cookie_name); ?>' value is being updated.</p>
<?php
if (isset($_COOKIE[$cookie_name])) {
echo "<p>Current value (from previous request): " . htmlspecialchars($_COOKIE[$cookie_name]) . "</p>";
}
echo "<p>New value set to: " . htmlspecialchars($new_value) . " (will be visible on next page load)</p>";
?>
</body>
</html>

要删除 cookie,请使用 cookie 的名称和过去的过期日期调用 setcookie()。同样,为了使删除操作正确生效,需要匹配 path、domain 等设置。

<?php
$cookie_name = "user";
// 将过期日期设置为一小时前
setcookie($cookie_name, "", time() - 3600, "/", "", true, true); // 匹配 path, secure, httponly
// 或者,使用选项数组:
/*
setcookie($cookie_name, '', [
'expires' => time() - 3600,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
*/
?>
<!DOCTYPE html>
<html lang="en">
<head><title>Delete Cookie</title></head>
<body>
<h1>Deleting Cookie</h1>
<p>Cookie '<?php echo htmlspecialchars($cookie_name); ?>' has been deleted (or attempted deletion).</p>
<?php
// 在当前脚本中取消设置变量以立即生效(但这不会删除浏览器中的 cookie)
unset($_COOKIE[$cookie_name]);
if (!isset($_COOKIE[$cookie_name])) {
echo "<p>Cookie variable is now unset in this script execution.</p>";
} else {
echo "<p>Cookie variable still exists in this script execution (unexpected).</p>";
}
?>
<p>刷新页面以确认浏览器不再发送该 cookie。</p>
</body>
</html>

您可以通过尝试设置一个测试 cookie,然后在后续请求中检查它是否存在来检查 cookie 是否启用。一种常见的技术是设置一个 cookie,然后立即重定向或提供一个链接到另一个页面,该页面检查是否存在该 cookie。

简单检查(不太可靠,可能会显示先前访问时留下的 cookie):

<?php
// 尝试设置一个测试 cookie
setcookie("test_cookie", "test_value", time() + 3600, '/', '', true, true);
?>
<!DOCTYPE html>
<html lang="en">
<head><title>Check Cookies Enabled</title></head>
<body>
<h1>Checking Cookie Support</h1>
<?php
// 检查 $_COOKIE 是否有内容。这是一个基本检查。
// 更可靠的检查方法是设置一个 cookie,然后在 *下一个* 页面加载时检查它是否存在。
if (count($_COOKIE) > 0) {
echo "<p>Cookie 似乎已启用(找到现有或测试 cookie)。</p>";
} else {
// 如果这是第一次访问并且测试 cookie 尚未注册,可能会触发此情况。
echo "<p>Cookie 可能被禁用,或者这是第一次访问。</p>";
}
?>
<p><a href="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">刷新页面</a>以查看是否检测到测试 cookie。</p>
</body>
</html>

对于管理用户会话(user sessions)或更复杂的数据持久化(data persistence),通常推荐使用 PHP Session($_SESSION),而不是直接使用原始 cookie。Session 通常在内部使用 cookie,但以更安全、更抽象的方式处理存储和检索。对于无状态认证(stateless authentication),存储在 cookie 或本地存储(local storage)中的 JSON Web Token (JWT) 也非常流行。