PHP setcookie() 函数

setcookie() 函数用于设置一个 Cookie。

Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储这些数据,并在后续请求中将其发送回服务器。Cookie 通常用于:

  • 会话管理(登录状态、购物车等)
  • 个性化设置(主题、语言偏好等)
  • 跟踪用户行为
重要:setcookie() 函数必须在任何实际输出之前调用,包括 HTML 标签、空格、换行符或 PHP 输出。否则会导致 "headers already sent" 错误。
提示:Cookie 的值会在发送时自动进行 URL 编码,接收时自动解码。如果要设置未经编码的值,请使用 setrawcookie() 函数。

语法

setcookie ( string $name [, string $value = "" [, int $expires = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] ) : bool

从 PHP 7.3.0 开始,支持数组参数格式:

setcookie ( string $name , string $value = "" , array $options = [] ) : bool

参数

参数 类型 描述
$name string 必需的。Cookie 的名称。
$value string 可选的。Cookie 的值。如果为空字符串,则创建一个空值 Cookie。
注意:不要在 Cookie 值中存储敏感信息。Cookie 存储在用户浏览器中,可能被用户查看或修改。
$expires int 可选的。Cookie 的过期时间,以 Unix 时间戳表示。
  • 0:会话 Cookie,浏览器关闭时过期
  • time() + 3600:1 小时后过期
  • time() + (86400 * 30):30 天后过期
$path string 可选的。Cookie 有效的服务器路径。默认为当前目录。
  • /:整个域名下都有效
  • /admin/:仅在 /admin/ 目录下有效
  • 空字符串:当前目录及其子目录有效
$domain string 可选的。Cookie 有效的域名。默认为当前域名。
  • example.com:主域名和所有子域名有效
  • www.example.com:仅 www 子域名有效
  • .example.com:主域名和所有子域名有效
$secure bool 可选的。如果设置为 true,Cookie 仅通过 HTTPS 连接传输。
安全最佳实践:在生产环境中,应始终通过 HTTPS 传输 Cookie。
$httponly bool 可选的。如果设置为 true,Cookie 只能通过 HTTP 协议访问,JavaScript 无法访问。
安全最佳实践:设置为 true 可以防止 XSS 攻击窃取 Cookie。
$options (PHP 7.3+) array 可选的。包含上述所有参数(除 $name 和 $value)的关联数组,支持更多选项:
  • expires - 过期时间
  • path - 路径
  • domain - 域名
  • secure - 仅 HTTPS
  • httponly - 仅 HTTP 访问
  • samesite - SameSite 属性(Strict/Lax/None)

返回值

返回值 描述
true 如果成功设置 Cookie 头信息。这并不意味着用户浏览器接受了 Cookie。
false 如果设置失败。通常是因为:
  • 输出已经发送("headers already sent" 错误)
  • 参数格式不正确

示例

示例 1:基本使用 - 设置简单的 Cookie

设置一个名为 "user" 的 Cookie,值为 "John Doe",过期时间为 1 小时。

<?php
// 设置一个简单的 Cookie
$cookie_name = "user";
$cookie_value = "John Doe";
$expiry_time = time() + (60 * 60); // 1小时后过期

if (setcookie($cookie_name, $cookie_value, $expiry_time)) {
    echo "Cookie '$cookie_name' 已设置成功。\n";
} else {
    echo "设置 Cookie 失败。\n";
}

// 注意:新设置的 Cookie 在下一次页面加载时才能通过 $_COOKIE 访问
if (isset($_COOKIE[$cookie_name])) {
    echo "Cookie 值: " . $_COOKIE[$cookie_name];
} else {
    echo "Cookie 尚未在当前请求中可用。请刷新页面。";
}
?>

示例 2:设置带所有参数的 Cookie

设置一个包含所有参数的完整 Cookie。

<?php
// 设置一个完整的 Cookie
$cookie_name = "preferences";
$cookie_value = json_encode([
    'theme' => 'dark',
    'language' => 'zh-CN',
    'notifications' => true
]);

$expires = time() + (86400 * 30); // 30天后过期
$path = "/";                      // 整个站点有效
$domain = "";                     // 当前域名(可设为 ".example.com" 使所有子域名有效)
$secure = true;                   // 仅通过 HTTPS 传输
$httponly = true;                 // 防止 JavaScript 访问

if (setcookie($cookie_name, $cookie_value, $expires, $path, $domain, $secure, $httponly)) {
    echo "偏好设置 Cookie 已设置。\n";
}

// 解码并显示 Cookie 值
if (isset($_COOKIE[$cookie_name])) {
    $preferences = json_decode($_COOKIE[$cookie_name], true);
    echo "当前主题: " . ($preferences['theme'] ?? '未设置') . "\n";
}
?>

示例 3:PHP 7.3+ 数组参数格式

使用新的数组参数格式设置 Cookie(推荐用于 PHP 7.3+)。

<?php
// PHP 7.3+ 新语法
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
    // 使用数组参数格式
    setcookie('session_id', 'abc123def456', [
        'expires' => time() + (86400 * 7),  // 7天后过期
        'path' => '/',
        'domain' => 'example.com',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict'  // SameSite 属性(PHP 7.3+)
    ]);

    echo "使用新语法设置 Cookie 成功。\n";
} else {
    // 传统语法
    setcookie('session_id', 'abc123def456', time() + (86400 * 7), '/', 'example.com', true, true);
    echo "使用传统语法设置 Cookie 成功。\n";
}

// SameSite 属性的解释
echo "SameSite 属性说明:\n";
echo "- Strict: 完全禁止第三方 Cookie\n";
echo "- Lax: 允许部分安全的第三方 Cookie(默认)\n";
echo "- None: 允许所有第三方 Cookie(必须同时设置 Secure)\n";
?>

示例 4:删除 Cookie

通过设置过期时间为过去的时间来删除 Cookie。

<?php
// 删除名为 "user" 的 Cookie
$cookie_name = "user";

// 方法1:设置过期时间为过去的时间
if (setcookie($cookie_name, "", time() - 3600)) {
    echo "Cookie '$cookie_name' 已删除。\n";
}

// 方法2:设置所有参数与创建时相同,但过期时间为过去
if (setcookie($cookie_name, "", time() - 3600, "/", "example.com", true, true)) {
    echo "Cookie '$cookie_name' 已完全删除。\n";
}

// 方法3:使用 unset() 从 $_COOKIE 数组中移除(仅影响当前脚本)
unset($_COOKIE[$cookie_name]);
echo "从当前请求中移除了 Cookie '$cookie_name'。\n";

// 验证 Cookie 是否已删除
if (!isset($_COOKIE[$cookie_name])) {
    echo "Cookie '$cookie_name' 不存在。\n";
}
?>

示例 5:处理登录状态

使用 Cookie 实现简单的登录状态管理。

<?php
// 登录处理
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';

    // 简单的认证检查(实际应用中应使用更安全的方法)
    if ($username === 'admin' && $password === 'password123') {
        // 创建会话标识符
        $session_id = bin2hex(random_bytes(16));

        // 设置 Cookie
        setcookie('session_id', $session_id, [
            'expires' => time() + (86400 * 7), // 7天有效
            'path' => '/',
            'secure' => true,
            'httponly' => true,
            'samesite' => 'Strict'
        ]);

        // 在服务器端存储会话数据(实际应用中应使用数据库或会话存储)
        // 这里使用文件存储作为示例
        $session_data = [
            'user_id' => 1,
            'username' => $username,
            'login_time' => time(),
            'ip_address' => $_SERVER['REMOTE_ADDR']
        ];

        file_put_contents("sessions/$session_id.json", json_encode($session_data));

        echo "登录成功!已设置会话 Cookie。\n";
        header("Location: /dashboard.php");
        exit;
    } else {
        echo "用户名或密码错误。\n";
    }
}

// 检查登录状态
function is_logged_in() {
    if (!isset($_COOKIE['session_id'])) {
        return false;
    }

    $session_id = $_COOKIE['session_id'];
    $session_file = "sessions/$session_id.json";

    if (!file_exists($session_file)) {
        return false;
    }

    $session_data = json_decode(file_get_contents($session_file), true);

    // 检查会话是否过期(24小时)
    if (time() - $session_data['login_time'] > 86400) {
        unlink($session_file); // 删除过期会话
        return false;
    }

    return $session_data;
}

// 登出处理
if (isset($_GET['logout'])) {
    if (isset($_COOKIE['session_id'])) {
        $session_id = $_COOKIE['session_id'];
        $session_file = "sessions/$session_id.json";

        if (file_exists($session_file)) {
            unlink($session_file);
        }

        // 删除 Cookie
        setcookie('session_id', '', time() - 3600, '/', '', true, true);
    }

    echo "已登出。\n";
    header("Location: /");
    exit;
}

// 显示登录状态
$user_data = is_logged_in();
if ($user_data) {
    echo "欢迎回来," . htmlspecialchars($user_data['username']) . "!\n";
} else {
    echo "您尚未登录。\n";
}
?>

注意事项

  • 输出前调用:setcookie() 必须在任何输出之前调用,否则会导致 "headers already sent" 错误。可以使用 headers_sent() 函数检查。
  • 大小限制:大多数浏览器限制每个 Cookie 为 4KB,每个域名下最多 50 个 Cookie。
  • 安全传输:始终通过 HTTPS 传输 Cookie(设置 $secure 参数为 true)。
  • HttpOnly:对于会话 Cookie,应设置 $httponlytrue 以防止 XSS 攻击。
  • SameSite:在 PHP 7.3+ 中,使用 samesite 选项控制第三方 Cookie(推荐使用 "Strict" 或 "Lax")。
  • 延迟生效:新设置的 Cookie 在当前请求的 $_COOKIE 数组中不可用,需要刷新页面或在下一次请求中才能访问。
  • 编码问题:setcookie() 会自动对值进行 URL 编码。如果不需要编码,使用 setrawcookie()
  • 删除 Cookie:要删除 Cookie,将其过期时间设置为过去的时间,并确保其他参数与设置时相同。

安全最佳实践

实践 描述
使用 HTTPS 始终设置 $secure = true,确保 Cookie 仅通过加密连接传输。
HttpOnly 标志 设置 $httponly = true,防止 JavaScript 访问 Cookie,减少 XSS 攻击风险。
SameSite 属性 使用 samesite = "Strict""Lax" 防止 CSRF 攻击。
合理的过期时间 根据需求设置适当的过期时间,避免过长的会话持续时间。
服务器端验证 不要信任 Cookie 中的数据,始终在服务器端进行验证。
加密敏感数据 如果需要存储敏感信息,应先加密再存入 Cookie。
限制路径和域 使用最严格的路径和域名限制,减少 Cookie 暴露范围。

相关函数