Cookie是存储在用户浏览器中的小型文本文件,用于在多个页面请求之间持久化数据。Cookie是构建现代Web应用程序的关键技术之一,广泛应用于用户认证、偏好设置、会话管理等功能。
Cookie是服务器发送到用户浏览器并保存在本地的小型数据片段,每次浏览器向同一服务器发送请求时,都会携带这些数据。Cookie的主要用途包括:
每个Cookie包含以下主要属性:
// Cookie的基本参数
setcookie(
name, // Cookie名称
value, // Cookie值
expire, // 过期时间(时间戳)
path, // 服务器上的有效路径
domain, // Cookie有效的域名
secure, // 是否仅通过HTTPS传输
httponly // 是否仅可通过HTTP访问(防止JavaScript访问)
);
<?php
// 注意:setcookie()函数必须在任何HTML输出之前调用
// 否则会产生"headers already sent"错误
// 设置一个简单的Cookie,30分钟后过期
setcookie("user_name", "张三", time() + 1800);
// 设置带多个参数的Cookie
setcookie(
"user_preferences",
json_encode(['theme' => 'dark', 'language' => 'zh-CN']),
time() + (30 * 24 * 60 * 60), // 30天过期
"/", // 整个网站有效
"example.com", // 指定域名
true, // 仅通过HTTPS传输
true // 仅HTTP访问(防止JavaScript访问)
);
echo "Cookie已设置成功!";
?>
<!DOCTYPE html>
<html>
<head>
<title>设置Cookie示例</title>
</head>
<body>
<p>页面内容...</p>
</body>
</html>
setrawcookie()与setcookie()功能相同,但不会对Cookie值进行URL编码。
<?php
// setcookie()会自动进行URL编码
setcookie("test1", "value with spaces", time() + 3600);
// 存储的值会是 "value%20with%20spaces"
// setrawcookie()不进行URL编码
setrawcookie("test2", "value with spaces", time() + 3600);
// 存储的值保持为 "value with spaces"
echo "使用setrawcookie()设置的Cookie不会进行URL编码。";
?>
<?php
// 方法1:使用名称数组
setcookie("user[name]", "张三", time() + 3600);
setcookie("user[email]", "zhangsan@example.com", time() + 3600);
setcookie("user[preferences]", json_encode(['theme' => 'dark']), time() + 3600);
// 方法2:使用JSON编码
$userData = [
'name' => '张三',
'email' => 'zhangsan@example.com',
'preferences' => ['theme' => 'dark', 'language' => 'zh-CN']
];
setcookie("user_data", json_encode($userData), time() + 3600);
echo "Cookie数组设置完成!";
?>
<?php
// 读取单个Cookie
if (isset($_COOKIE['user_name'])) {
$userName = htmlspecialchars($_COOKIE['user_name']);
echo "欢迎回来," . $userName . "!<br>";
} else {
echo "这是您第一次访问本网站。<br>";
}
// 读取Cookie数组
if (isset($_COOKIE['user'])) {
$user = $_COOKIE['user'];
echo "用户名: " . htmlspecialchars($user['name'] ?? '') . "<br>";
echo "邮箱: " . htmlspecialchars($user['email'] ?? '') . "<br>";
// 解码JSON数据
if (isset($user['preferences'])) {
$preferences = json_decode($user['preferences'], true);
if ($preferences) {
echo "主题设置: " . ($preferences['theme'] ?? '默认') . "<br>";
}
}
}
// 读取JSON编码的Cookie
if (isset($_COOKIE['user_data'])) {
$userData = json_decode($_COOKIE['user_data'], true);
if ($userData) {
echo "用户数据: <pre>" . print_r($userData, true) . "</pre>";
}
}
?>
<?php
/**
* 安全读取Cookie值的函数
* @param string $name Cookie名称
* @param mixed $default 默认值
* @return mixed 安全的Cookie值
*/
function getSecureCookie($name, $default = null) {
if (!isset($_COOKIE[$name])) {
return $default;
}
$value = $_COOKIE[$name];
// 对字符串进行安全过滤
if (is_string($value)) {
$value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
// 如果是JSON字符串,尝试解码并递归过滤
if (is_string($value) && ($decoded = json_decode($value, true)) !== null) {
$value = array_map(function($item) {
return is_string($item) ? htmlspecialchars($item, ENT_QUOTES, 'UTF-8') : $item;
}, $decoded);
}
return $value;
}
// 使用安全函数读取Cookie
$safeUserName = getSecureCookie('user_name', '访客');
echo "安全用户名: " . $safeUserName;
// 读取并验证重要数据
$sessionToken = getSecureCookie('session_token');
if ($sessionToken && validateSessionToken($sessionToken)) {
// 有效的会话令牌
echo "会话验证成功!";
}
function validateSessionToken($token) {
// 在实际应用中,这里应该验证令牌的有效性
return strlen($token) === 64 && ctype_xdigit($token);
}
?>
<?php
// 显示所有Cookie(调试用途)
function displayAllCookies() {
echo "<h3>当前所有Cookie:</h3>";
if (empty($_COOKIE)) {
echo "<p>没有找到Cookie。</p>";
return;
}
echo "<table border='1' cellpadding='8' cellspacing='0' style='border-collapse: collapse;'>";
echo "<thead><tr><th>Cookie名称</th><th>值</th><th>大小</th></tr></thead>";
echo "<tbody>";
foreach ($_COOKIE as $name => $value) {
$safeName = htmlspecialchars($name);
$safeValue = htmlspecialchars(substr($value, 0, 100)) . (strlen($value) > 100 ? '...' : '');
$size = strlen($value);
echo "<tr>";
echo "<td><code>$safeName</code></td>";
echo "<td style='word-break: break-all;'>$safeValue</td>";
echo "<td>$size 字节</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 统计信息
echo "<p>总计: " . count($_COOKIE) . " 个Cookie</p>";
echo "<p>总大小: " . array_sum(array_map('strlen', $_COOKIE)) . " 字节</p>";
}
// 仅在调试模式下显示
if (defined('DEBUG_MODE') && DEBUG_MODE) {
displayAllCookies();
}
?>
<?php
// 方法1:将过期时间设置为过去的时间
setcookie("user_name", "", time() - 3600);
// 方法2:清空值并设置过期时间
setcookie("session_token", "", time() - 3600, "/", "example.com", true, true);
// 方法3:删除Cookie数组的特定元素
if (isset($_COOKIE['user']) && is_array($_COOKIE['user'])) {
setcookie("user[preferences]", "", time() - 3600);
}
echo "Cookie删除成功!<br>";
// 验证Cookie是否已删除
if (!isset($_COOKIE['user_name'])) {
echo "user_name Cookie已被成功删除。";
}
?>
<?php
/**
* 批量删除Cookie
* @param array $cookiesToDelete 要删除的Cookie名称数组
*/
function deleteCookies(array $cookiesToDelete) {
foreach ($cookiesToDelete as $cookieName) {
// 检查Cookie是否存在
if (isset($_COOKIE[$cookieName])) {
// 设置为过期
setcookie($cookieName, "", time() - 3600);
// 从当前请求的$_COOKIE数组中移除
unset($_COOKIE[$cookieName]);
}
}
}
/**
* 删除特定前缀的所有Cookie
* @param string $prefix Cookie名称前缀
*/
function deleteCookiesByPrefix($prefix) {
foreach ($_COOKIE as $name => $value) {
if (strpos($name, $prefix) === 0) {
setcookie($name, "", time() - 3600);
unset($_COOKIE[$name]);
}
}
}
// 使用示例
$cookiesToRemove = ['session_id', 'user_preferences', 'tracking_token'];
deleteCookies($cookiesToRemove);
// 删除所有以"temp_"开头的Cookie
deleteCookiesByPrefix("temp_");
echo "批量删除操作完成!";
?>
<?php
// 会话Cookie(浏览器关闭时过期)
setcookie("session_cookie", "value", 0); // 0表示会话Cookie
// 短期Cookie(1小时)
setcookie("short_term", "value", time() + 3600);
// 中期Cookie(7天)
setcookie("medium_term", "value", time() + (7 * 24 * 60 * 60));
// 长期Cookie(1年)
setcookie("long_term", "value", time() + (365 * 24 * 60 * 60));
// 永久Cookie(10年)
setcookie("permanent", "value", time() + (10 * 365 * 24 * 60 * 60));
// 使用mktime设置特定日期
$expiryDate = mktime(23, 59, 59, 12, 31, 2024); // 2024年12月31日23:59:59
setcookie("new_year", "Happy New Year!", $expiryDate);
echo "各种有效期的Cookie已设置!";
?>
<?php
/**
* Cookie有效期计算工具函数
*/
class CookieExpiry {
// 单位时间秒数定义
const MINUTE = 60;
const HOUR = 3600;
const DAY = 86400;
const WEEK = 604800;
const MONTH = 2592000; // 30天
const YEAR = 31536000; // 365天
/**
* 计算Cookie过期时间戳
* @param string $duration 持续时间(如:"1 hour", "30 days", "1 year")
* @return int 过期时间戳
*/
public static function calculate($duration) {
$units = [
'second' => 1,
'minute' => self::MINUTE,
'hour' => self::HOUR,
'day' => self::DAY,
'week' => self::WEEK,
'month' => self::MONTH,
'year' => self::YEAR,
];
$pattern = '/(\d+)\s*(second|minute|hour|day|week|month|year)s?/i';
if (preg_match($pattern, $duration, $matches)) {
$number = (int)$matches[1];
$unit = strtolower($matches[2]);
if (isset($units[$unit])) {
return time() + ($number * $units[$unit]);
}
}
// 默认30天
return time() + self::MONTH;
}
/**
* 设置会话Cookie(浏览器关闭时过期)
*/
public static function setSessionCookie($name, $value) {
return setcookie($name, $value, 0, '/', '', false, true);
}
/**
* 设置带持续时间的Cookie
*/
public static function setCookieWithDuration($name, $value, $duration) {
$expiry = self::calculate($duration);
return setcookie($name, $value, $expiry, '/', '', false, true);
}
}
// 使用示例
CookieExpiry::setSessionCookie('session_id', uniqid());
CookieExpiry::setCookieWithDuration('user_token', 'abc123xyz', '30 days');
CookieExpiry::setCookieWithDuration('remember_me', '1', '1 year');
// 手动计算
$expireTime = CookieExpiry::calculate('2 weeks');
setcookie('two_week_cookie', 'value', $expireTime);
echo "使用Cookie有效期工具函数完成设置!";
?>
HttpOnly标志防止JavaScript通过document.cookie访问Cookie,可以有效防止XSS攻击窃取Cookie。
<?php
// 设置HttpOnly Cookie(推荐用于会话Cookie)
setcookie(
'secure_session',
bin2hex(random_bytes(32)), // 安全的随机令牌
time() + 3600, // 1小时后过期
'/', // 整个网站
'example.com', // 域名
false, // 不强制HTTPS(根据实际情况调整)
true // HttpOnly标志
);
echo "HttpOnly Cookie已设置,JavaScript无法访问此Cookie。";
?>
Secure标志确保Cookie仅通过HTTPS连接传输,防止中间人攻击。
<?php
// 仅在HTTPS连接时设置Secure Cookie
if ($_SERVER['HTTPS'] === 'on' || $_SERVER['SERVER_PORT'] == 443) {
setcookie(
'secure_auth_token',
bin2hex(random_bytes(16)),
time() + 86400, // 24小时
'/',
'example.com',
true, // Secure标志
true // HttpOnly标志
);
echo "Secure Cookie已设置(仅HTTPS)。";
} else {
echo "警告:当前不是HTTPS连接,无法设置Secure Cookie。";
}
?>
SameSite属性控制Cookie是否在跨站请求中发送,可以有效防止CSRF攻击。
<?php
// PHP 7.3+ 支持SameSite属性
if (PHP_VERSION_ID >= 70300) {
// 设置SameSite=Lax(推荐默认值)
setcookie('samesite_lax', 'value', [
'expires' => time() + 3600,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
// 设置SameSite=Strict(更严格)
setcookie('samesite_strict', 'value', [
'expires' => time() + 3600,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// 设置SameSite=None(需要配合Secure标志)
setcookie('samesite_none', 'value', [
'expires' => time() + 3600,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'None'
]);
}
// 对于PHP 7.2及以下版本,可以使用header()函数
if (PHP_VERSION_ID < 70300) {
header('Set-Cookie: legacy_cookie=value; SameSite=Lax');
}
echo "SameSite Cookie属性设置完成!";
?>
<?php
// 登录处理
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$remember = isset($_POST['remember_me']);
// 验证用户(简化示例,实际应从数据库验证)
if ($username === 'admin' && $password === 'password123') {
// 创建会话
session_start();
$_SESSION['user_id'] = 1;
$_SESSION['username'] = $username;
// 如果用户选择了"记住我"
if ($remember) {
// 生成记住我令牌
$token = bin2hex(random_bytes(32));
$hashedToken = hash('sha256', $token);
// 存储到数据库(简化示例)
// 实际应该存储:user_id, hashed_token, expiry_date
// $db->query("INSERT INTO remember_tokens VALUES (...)")
// 设置Cookie(30天有效期)
$expiry = time() + (30 * 24 * 60 * 60);
setcookie('remember_me', $token, $expiry, '/', '', true, true);
echo "登录成功!已启用记住我功能。";
} else {
echo "登录成功!";
}
} else {
echo "用户名或密码错误!";
}
}
// 检查记住我Cookie自动登录
function checkRememberMe() {
if (!isset($_SESSION['user_id']) && isset($_COOKIE['remember_me'])) {
$token = $_COOKIE['remember_me'];
$hashedToken = hash('sha256', $token);
// 从数据库验证令牌(简化示例)
// $user = $db->query("SELECT user_id FROM remember_tokens WHERE token = ? AND expiry_date > NOW()")
// 如果令牌有效,创建会话
session_start();
$_SESSION['user_id'] = 1; // 从数据库获取的实际ID
$_SESSION['username'] = 'admin'; // 从数据库获取的用户名
echo "通过记住我Cookie自动登录成功!";
return true;
}
return false;
}
// 页面加载时检查
checkRememberMe();
?>
<?php
// 处理偏好设置表单
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_preferences'])) {
$preferences = [
'theme' => $_POST['theme'] ?? 'light',
'language' => $_POST['language'] ?? 'zh-CN',
'font_size' => $_POST['font_size'] ?? 'medium',
'notifications' => isset($_POST['notifications']) ? true : false
];
// 保存到Cookie(JSON编码)
setcookie(
'user_preferences',
json_encode($preferences),
time() + (365 * 24 * 60 * 60), // 1年有效期
'/',
'',
false,
true
);
echo "偏好设置已保存!";
}
// 获取当前偏好设置
function getUserPreferences() {
$defaults = [
'theme' => 'light',
'language' => 'zh-CN',
'font_size' => 'medium',
'notifications' => true
];
if (isset($_COOKIE['user_preferences'])) {
$preferences = json_decode($_COOKIE['user_preferences'], true);
if ($preferences) {
return array_merge($defaults, $preferences);
}
}
return $defaults;
}
// 应用偏好设置
$prefs = getUserPreferences();
// 根据偏好设置应用样式
echo "<style>";
echo "body {";
echo " font-size: " . ($prefs['font_size'] === 'large' ? '16px' : '14px') . ";";
if ($prefs['theme'] === 'dark') {
echo " background-color: #333; color: #fff;";
}
echo "}";
echo "</style>";
// 显示偏好设置表单
?>
<form method="POST">
<h3>偏好设置</h3>
<div>
<label>主题:</label>
<select name="theme">
<option value="light" <?= $prefs['theme'] === 'light' ? 'selected' : '' ?>>浅色</option>
<option value="dark" <?= $prefs['theme'] === 'dark' ? 'selected' : '' ?>>深色</option>
</select>
</div>
<div>
<label>语言:</label>
<select name="language">
<option value="zh-CN" <?= $prefs['language'] === 'zh-CN' ? 'selected' : '' ?>>简体中文</option>
<option value="en-US" <?= $prefs['language'] === 'en-US' ? 'selected' : '' ?>>English</option>
</select>
</div>
<div>
<label><input type="checkbox" name="notifications" <?= $prefs['notifications'] ? 'checked' : '' ?>> 启用通知</label>
</div>
<button type="submit" name="save_preferences">保存设置</button>
</form>
<?php
// 购物车类
class ShoppingCart {
private $cookieName = 'shopping_cart';
public function __construct() {
// 初始化购物车
if (!isset($_COOKIE[$this->cookieName])) {
$this->saveCart([]);
}
}
// 获取购物车内容
public function getCart() {
if (isset($_COOKIE[$this->cookieName])) {
$cart = json_decode($_COOKIE[$this->cookieName], true);
return $cart ?: [];
}
return [];
}
// 添加商品到购物车
public function addItem($productId, $quantity = 1, $productData = []) {
$cart = $this->getCart();
if (isset($cart[$productId])) {
$cart[$productId]['quantity'] += $quantity;
} else {
$cart[$productId] = [
'quantity' => $quantity,
'added_at' => time(),
'data' => $productData
];
}
$this->saveCart($cart);
return true;
}
// 从购物车移除商品
public function removeItem($productId) {
$cart = $this->getCart();
if (isset($cart[$productId])) {
unset($cart[$productId]);
$this->saveCart($cart);
return true;
}
return false;
}
// 更新商品数量
public function updateQuantity($productId, $quantity) {
if ($quantity <= 0) {
return $this->removeItem($productId);
}
$cart = $this->getCart();
if (isset($cart[$productId])) {
$cart[$productId]['quantity'] = $quantity;
$this->saveCart($cart);
return true;
}
return false;
}
// 清空购物车
public function clearCart() {
$this->saveCart([]);
return true;
}
// 获取购物车商品总数
public function getTotalItems() {
$cart = $this->getCart();
$total = 0;
foreach ($cart as $item) {
$total += $item['quantity'];
}
return $total;
}
// 获取购物车总价
public function getTotalPrice($priceList) {
$cart = $this->getCart();
$total = 0;
foreach ($cart as $productId => $item) {
if (isset($priceList[$productId])) {
$total += $item['quantity'] * $priceList[$productId];
}
}
return $total;
}
// 保存购物车到Cookie
private function saveCart($cart) {
setcookie(
$this->cookieName,
json_encode($cart),
time() + (30 * 24 * 60 * 60), // 30天有效期
'/',
'',
false,
true
);
$_COOKIE[$this->cookieName] = json_encode($cart);
}
}
// 使用示例
$cart = new ShoppingCart();
// 添加商品
if (isset($_GET['add_to_cart'])) {
$productId = $_GET['add_to_cart'];
$cart->addItem($productId, 1, ['name' => '商品' . $productId]);
echo "商品已添加到购物车!";
}
// 显示购物车
$cartItems = $cart->getCart();
echo "<h3>购物车 (共" . $cart->getTotalItems() . "件商品)</h3>";
if (empty($cartItems)) {
echo "<p>购物车为空</p>";
} else {
echo "<ul>";
foreach ($cartItems as $productId => $item) {
echo "<li>";
echo "商品ID: $productId, 数量: " . $item['quantity'];
echo " <a href='?remove_from_cart=$productId'>移除</a>";
echo "</li>";
}
echo "</ul>";
// 假设的价格列表
$prices = [
'1' => 100,
'2' => 200,
'3' => 150
];
$totalPrice = $cart->getTotalPrice($prices);
echo "<p>总价: ¥" . $totalPrice . "</p>";
}
// 清空购物车链接
echo "<p><a href='?clear_cart=1'>清空购物车</a></p>";
?>
可能的原因:
浏览器对Cookie有以下限制:
主要区别:
| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端浏览器 | 服务器端 |
| 安全性 | 较低(客户端可访问) | 较高(仅服务器访问) |
| 存储容量 | 有限(约4KB) | 较大(受服务器内存限制) |
| 生命周期 | 可设置长期有效 | 通常会话结束即销毁 |
| 性能影响 | 每次请求都会发送 | 仅存储session_id在Cookie中 |
<?php
// Cookie检测函数
function checkCookieSupport() {
if (isset($_GET['check_cookies'])) {
if (isset($_COOKIE['cookie_test'])) {
echo "浏览器支持Cookie!";
setcookie('cookie_test', '', time() - 3600); // 清理测试Cookie
} else {
echo "浏览器可能禁用了Cookie,请启用Cookie后重试。";
}
exit;
}
// 设置测试Cookie并重定向
setcookie('cookie_test', '1', time() + 60);
header('Location: ' . $_SERVER['PHP_SELF'] . '?check_cookies=1');
exit;
}
// 在需要检测的地方调用
// checkCookieSupport();
?>
<?php
/**
* 检测浏览器Cookie支持情况的脚本
*/
function checkBrowserCompatibility() {
echo "<script>";
echo "if (navigator.cookieEnabled) {";
echo " console.log('浏览器支持Cookie');";
echo " document.cookie = 'js_cookie_test=1; path=/; max-age=60';";
echo "} else {";
echo " console.log('浏览器不支持或禁用了Cookie');";
echo "}";
echo "</script>";
// 服务器端验证
if (isset($_COOKIE['js_cookie_test'])) {
echo "<p class='text-success'>✓ JavaScript Cookie设置成功</p>";
} else {
echo "<p class='text-warning'>⚠ JavaScript Cookie设置失败</p>";
}
}
checkBrowserCompatibility();
?>
当Cookie不可用时,可以考虑以下替代方案:
<?php
class SessionManager {
private $useCookies = true;
public function __construct() {
// 检测Cookie支持
$this->useCookies = $this->checkCookieSupport();
if (!$this->useCookies) {
$this->startSessionWithoutCookies();
} else {
session_start();
}
}
private function checkCookieSupport() {
// 简单的Cookie检测
setcookie('test_cookie', '1', time() + 60);
return isset($_COOKIE['test_cookie']) || isset($_GET['test_cookie']);
}
private function startSessionWithoutCookies() {
// 使用URL传递session_id
if (isset($_GET[session_name()])) {
session_id($_GET[session_name()]);
} elseif (isset($_POST[session_name()])) {
session_id($_POST[session_name()]);
}
session_start();
// 为链接和表单添加session_id
$this->addSessionIdToUrls();
}
private function addSessionIdToUrls() {
// 这个函数应该在输出HTML时被调用
// 用于在URL中添加session_id参数
$sessionId = session_id();
// 可以使用输出缓冲来修改所有链接
// 这里只是示例
}
public function getSessionLink($url) {
if (!$this->useCookies) {
$separator = (strpos($url, '?') === false) ? '?' : '&';
return $url . $separator . session_name() . '=' . session_id();
}
return $url;
}
}
// 使用示例
$session = new SessionManager();
echo "<a href='" . $session->getSessionLink('page.php') . "'>下一页</a>";
?>