setcookie

(PHP 4, PHP 5, PHP 7, PHP 8)

setcookie发送 Cookie

描述

setcookie(
    字符串 $name,
    字符串 $value = "",
    整数 $expires_or_options = 0,
    字符串 $path = "",
    字符串 $domain = "",
    布尔值 $secure = false,
    布尔值 $httponly = false
): 布尔值

从 PHP 7.3.0 开始提供备用签名(不支持命名参数)

setcookie(字符串 $name, 字符串 $value = "", 数组 $options = []): 布尔值

setcookie() 定义一个 cookie,以便与其他 HTTP 标头一起发送。与其他标头一样,cookie 必须在脚本的任何输出 *之前* 发送(这是协议限制)。这要求您在任何输出之前放置对该函数的调用,包括 <html><head> 标签以及任何空格。

设置 Cookie 后,可以使用 $_COOKIE 数组在下一个页面加载时访问它们。Cookie 值也可能存在于 $_REQUEST 中。

参数

» RFC 6265 提供了有关如何解释每个 setcookie() 参数的规范性参考。

name

Cookie 的名称。

value

Cookie 的值。此值存储在客户端计算机上;不要存储敏感信息。假设 name'cookiename',此值通过 $_COOKIE['cookiename'] 检索。

expires_or_options

Cookie 过期的时间。这是一个 Unix 时间戳,因此是以自纪元以来的秒数为单位的。设置此值的一种方法是将 Cookie 过期前的秒数加到调用 time() 的结果上。例如,time()+60*60*24*30 将设置 Cookie 在 30 天后过期。另一个选择是使用 mktime() 函数。如果设置为 0 或省略,则 Cookie 将在会话结束时(浏览器关闭时)过期。

注意:

您可能会注意到 expires_or_options 参数采用 Unix 时间戳,而不是日期格式 Wdy, DD-Mon-YYYY HH:MM:SS GMT,这是因为 PHP 在内部进行此转换。

path

服务器上 Cookie 可用的路径。如果设置为 '/',则 Cookie 将在整个 domain 中可用。如果设置为 '/foo/',则 Cookie 仅在 /foo/ 目录及其所有子目录(如 /foo/bar/)中可用。默认值为设置 Cookie 的当前目录。

domain

Cookie 可用的(子)域。将其设置为子域(如 'www.example.com')将使 Cookie 可用于该子域及其所有其他子域(例如 w2.www.example.com)。要使 Cookie 可用于整个域(包括其所有子域),只需将值设置为域名称(在本例中为 'example.com')。

仍然实现已弃用的 » RFC 2109 的旧浏览器可能需要前导 . 才能匹配所有子域。

secure

表示 Cookie 应该只通过客户端上的安全 HTTPS 连接传输。当设置为 true 时,只有在存在安全连接时才会设置 Cookie。在服务器端,程序员需要在安全连接上发送这种 Cookie(例如,关于 $_SERVER["HTTPS"])。

httponly

true 时,Cookie 将仅通过 HTTP 协议访问。这意味着 Cookie 无法被脚本语言(如 JavaScript)访问。有人建议此设置可以有效地帮助减少通过 XSS 攻击造成的身份盗窃(尽管并非所有浏览器都支持),但这种说法经常受到争议。truefalse

options

一个关联的 数组,它可能具有以下任何键:expirespathdomainsecurehttponlysamesite。如果存在任何其他键,则会生成级别为 E_WARNING 的错误。这些值与具有相同名称的参数的描述相同。samesite 元素的值应为 NoneLaxStrict 之一。如果省略任何允许的选项,它们的默认值与显式参数的默认值相同。如果省略 samesite 元素,则不会设置 SameSite Cookie 属性。

注意:

要设置包含不在列出键中的属性的 Cookie,请使用 header()

返回值

如果在调用此函数之前存在输出,则 setcookie() 将失败并返回 false。如果 setcookie() 成功运行,则将返回 true。这并不表示用户是否接受了 Cookie。

变更日志

版本 描述
8.2.0 Cookie 的日期格式现在为 'D, d M Y H:i:s \G\M\T';以前是 'D, d-M-Y H:i:s T'
7.3.0 添加了支持 options 数组的备用签名。此签名还支持设置 SameSite Cookie 属性。

示例

以下示例演示了一些发送 Cookie 的方法。

示例 #1 setcookie() 发送示例

<?php

$value
= 'something from somewhere';

setcookie("TestCookie", $value);
setcookie("TestCookie", $value, time()+3600); /* expire in 1 hour */
setcookie("TestCookie", $value, time()+3600, "/~rasmus/", "example.com", true);

?>

请注意,当您发送 Cookie 时,Cookie 的值部分会自动进行 URL 编码,并且在收到时,它会自动解码并分配给与 Cookie 名称相同的变量。如果您不希望这样做,可以使用 setrawcookie()。要查看我们测试 Cookie 的内容,只需使用以下示例之一

<?php
// Print an individual cookie
echo $_COOKIE["TestCookie"];

// Another way to debug/test is to view all cookies
print_r($_COOKIE);
?>

示例 #2 setcookie() 删除示例

删除 Cookie 时,应确保过期日期已过,以触发浏览器中的删除机制。以下示例说明如何删除先前示例中发送的 Cookie。

<?php
// 将过期日期设置为一小时前
setcookie("TestCookie", "", time() - 3600);
setcookie("TestCookie", "", time() - 3600, "/~rasmus/", "example.com", 1);
?>

示例 #3 setcookie() 和数组

您也可以通过在 Cookie 名称中使用数组表示法来设置数组 Cookie。这将设置与您拥有的数组元素数量相同的 Cookie,但当您的脚本收到 Cookie 时,所有值都将放置在以 Cookie 名称命名的数组中。

<?php
// 设置 Cookie
setcookie("cookie[three]", "cookiethree");
setcookie("cookie[two]", "cookietwo");
setcookie("cookie[one]", "cookieone");

// 页面重新加载后,打印它们
if (isset($_COOKIE['cookie'])) {
foreach (
$_COOKIE['cookie'] as $name => $value) {
$name = htmlspecialchars($name);
$value = htmlspecialchars($value);
echo
"$name : $value <br />\n";
}
}
?>

以上示例将输出

three : cookiethree
two : cookietwo
one : cookieone

注意 将分隔符字符(例如 [])作为 Cookie 名称的一部分使用不符合 RFC 6265 第 4 节,但根据 RFC 6265 第 5 节,用户代理应该支持它。

说明

注意:

您可以在调用此函数之前使用输出缓冲区发送输出,并承担将所有输出缓冲到服务器中,直到您将其发送到浏览器为止的所有开销。您可以在脚本中调用 ob_start()ob_end-flush() 来实现这一点,或者在 php.ini 或服务器配置文件中将 output_buffering 配置指令设置为开启。

常见陷阱

  • Cookie 只有在下次加载需要显示 Cookie 的页面时才会变得可见。要测试 Cookie 是否已成功设置,请在 Cookie 过期之前,在下次加载的页面上检查 Cookie 是否存在。过期时间是通过 expires_or_options 参数设置的。调试 Cookie 存在性的一个好方法是简单地调用 print_r($_COOKIE);
  • Cookie 必须使用与设置时相同的参数删除。如果 value 参数为空字符串,并且所有其他参数与先前对 setcookie() 的调用匹配,那么具有指定名称的 Cookie 将从远程客户端删除。这是通过将值内部设置为 'deleted' 并在过去设置过期时间来实现的。
  • 由于使用值为 false 设置 Cookie 会尝试删除 Cookie,因此不应使用布尔值。相反,应使用 0 代表 false,使用 1 代表 true
  • Cookie 名称可以设置为数组名称,并将作为数组提供给您的 PHP 脚本,但每个 Cookie 都单独存储在用户的系统上。请考虑使用 explode() 使用多个名称和值设置一个 Cookie。不建议为此目的使用 serialize(),因为它会导致安全漏洞。

setcookie() 的多次调用将按调用的顺序执行。

另请参阅

添加注释

用户贡献注释 13 条注释

388
walterquez
11 年前
代替以下代码
<?php setcookie( "TestCookie", $value, time()+(60*60*24*30) ); ?>

您可以使用以下代码
<?php setcookie( "TestCookie", $value, strtotime( '+30 days' ) ); ?>
267
Bachsau
12 年前
想要删除 Cookie?

许多人以复杂的方式执行此操作
setcookie('name', 'content', time()-3600);

但为什么您要使它如此复杂并冒着无法正常工作的风险,当客户端的时间错误时?为什么要与 time() 搞来搞去?

以下是删除 Cookie 的最简单方法
setcookie('name', 'content', 1);

就是这样。
86
匿名
4 年前
只是一个示例,用于阐明数组选项的使用,特别是由于 Mozilla 将弃用/惩罚 SameSite = none 的使用,这是在不使用数组选项的情况下默认使用的。

<?php
$arr_cookie_options
= array (
'expires' => time() + 60*60*24*30,
'path' => '/',
'domain' => '.example.com', // 为了兼容性,在前面添加点,或者使用子域
'secure' => true, // 或 false
'httponly' => true, // 或 false
'samesite' => 'None' // None || Lax || Strict
);
setcookie('TestCookie', 'The Cookie Value', $arr_cookie_options);
?>
37
paul nospam AT nospam sitepoint dot com
17 年前
注意,在设置“数组 Cookie”时,会为数组的每个元素设置一个单独的 Cookie。

在流量很大的网站上,这会显著增加客户端后续 HTTP 请求的大小(包括对同一域上的静态内容的请求)。

更重要的是,Cookie 规范指出浏览器只需要为每个域接受 20 个 Cookie。这个限制由 Firefox 提高到 50,由 Opera 提高到 30,但 IE6 和 IE7 仍然强制执行每个域 20 个 Cookie 的限制。超过此限制的任何 Cookie 都会要么删除旧的 Cookie,要么被浏览器忽略/拒绝。
22
nacho at casinelli dot com
7 年前
值得一提的是:您应该避免在 Cookie 名称中使用点。

<?php
// 实际上,这将设置 'ace_fontSize' 名称:
setcookie( 'ace.fontSize', 18 );
?>
42
匿名
17 年前
这里没有明确说明的一点,让我困惑了一段时间,那就是域名必须包含至少两个点(.),因此 'localhost' 无效,浏览器将拒绝设置 Cookie!相反,对于 localhost,您应该使用 false。

要使您的代码在 localhost 和正常域名上都能正常工作,您可以执行以下操作

<?php

$domain
= ($_SERVER['HTTP_HOST'] != 'localhost') ? $_SERVER['HTTP_HOST'] : false;
setcookie('cookiename', 'data', time()+60*60*24*365, '/', $domain, false);

?>
11
synnus at gmail dot com
4 年前
由于 " PHPSESSID " cookie 的 " sameSite " 属性设置为 " none " 或无效值,且没有 " secure " 属性,它将很快被拒绝。要详细了解 "sameSite" 属性,请访问 https://mdn.org.cn/docs/Web/HTTP/Headers/Set-Cookie/SameSite.

<?php
ini_set
("session.cookie_secure", 1);
session_start();

我的 PHP 代码 ....

?>
9
ellert at vankoperen dot nl
10 年前
注意:如果你使用 URL RewriteRules 将类似 domain.com/bla/stuf/etc 的内容转换成参数,那么在设置 cookie 时可能会遇到问题。
至少在我的设置中,参数的更改会导致 cookie 不再存在。
解决方法很简单:指定域。"/" 通常可以正常工作。
16
gabe at fijiwebdesign dot com
17 年前
如果你想删除域中所有 cookie,你可能想使用

<?php $_SERVER['HTTP_COOKIE'] ?>

而不是

<?php $_COOKIE ?>

来确定 cookie 名称。
如果 cookie 名称采用数组表示法,例如:user[username]
那么 PHP 会在 $_COOKIE 中自动创建一个相应的数组。相反,请使用 $_SERVER['HTTP_COOKIE'],因为它反映了实际的 HTTP 请求头。

<?php

// 删除 cookie
if (isset($_SERVER['HTTP_COOKIE'])) {
$cookies = explode(';', $_SERVER['HTTP_COOKIE']);
foreach(
$cookies as $cookie) {
$parts = explode('=', $cookie);
$name = trim($parts[0]);
setcookie($name, '', time()-1000);
setcookie($name, '', time()-1000, '/');
}
}

?>
5
laffen
15 年前
请注意,$_COOKIE 变量不会保存具有相同名称的多个 cookie。在同一个主机上设置两个具有相同名称的 cookie 是合法的,前提是子域不同。
<?php
setcookie
("testcookie", "value1hostonly", time(), "/", ".example.com", 0, true);
setcookie("testcookie", "value2subdom", time(), "/", "subdom.example.com", 0, true);
?>
浏览器下次请求时,$_SERVER['HTTP_COOKIE'] 变量中将包含这两个 cookie,但 $_COOKIE 变量中只会有其中一个。对 subdom.example.com 的请求将包含这两个 cookie,而对 example.com 或 www.example.com 的请求只会发送值为 "value1hostonly" 的 cookie。

<?php
$kaker
= explode(";", $_SERVER['HTTP_COOKIE']);
foreach(
$kaker as $val){
$k = explode("=", $val);
echo
trim($k[0]) . " => " . $k[1];
}

// 输出
testcookie => value1hostonly
testcookie
=> value2subdom

?>
3
Anonymous
13 年前
cookie 名称中的句点 (如 user.name) 似乎在 $_COOKIE 数组中显示为下划线 (因此为 user_name)。这意味着,例如,必须使用 $_COOKIE["user_name"] 来读取使用 setcookie("user.name" ...) 设置的 cookie,这已经相当令人困惑了。

此外,变量 $_COOKIE["user_name"] 将保留由 setcookie("user.name" ...) 设置的值,无论调用多少次 setcookie("user_name" ...) 也不会改变此值。这可以通过清除 "user.name" cookie 来轻松解决,但可能需要一段时间才能意识到这一点,因为 $_COOKIE 中只有 "user_name"。

希望这能为某人节省一些时间。
0
ilya at ilya dot top
5 天前
在任何网络浏览器中,都有一种非常常用的选项 "打开之前的窗口和标签页",它默认情况下是禁用的,但许多人会启用它。
当此选项处于活动状态时,网络浏览器在关闭并重新打开时,不会执行终止并启动新会话的操作,而是会保存并恢复当前会话,以及会话 cookie 和 sessionStorage。
与预期相反,会话 cookie 和 sessionStorage 可以在很长一段时间内保持有效,直到用户在关闭网络浏览器之前关闭标签页。
如果你希望 cookie (例如带时间偏移量的 cookie) 确保具有较短的生存期,则应该明确指定此较短的生存期,而不是依赖于会话 cookie 的自删除功能。
1
hansel at gretel dot com
17 年前
以下代码片段将 abdullah 和 Charles Martin 的示例组合成一个功能强大的组合函数(并修复了至少一个 bug)。

<?php
function set_cookie_fix_domain($Name, $Value = '', $Expires = 0, $Path = '', $Domain = '', $Secure = false, $HTTPOnly = false)
{
if (!empty(
$Domain))
{
// 修复域以接受带和不带 'www.' 的域。
if (strtolower(substr($Domain, 0, 4)) == 'www.') $Domain = substr($Domain, 4);
$Domain = '.' . $Domain;

// 删除端口信息。
$Port = strpos($Domain, ':');
if (
$Port !== false) $Domain = substr($Domain, 0, $Port);
}

header('Set-Cookie: ' . rawurlencode($Name) . '=' . rawurlencode($Value)
. (empty(
$Expires) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $Expires) . ' GMT')
. (empty(
$Path) ? '' : '; path=' . $Path)
. (empty(
$Domain) ? '' : '; domain=' . $Domain)
. (!
$Secure ? '' : '; secure')
. (!
$HTTPOnly ? '' : '; HttpOnly'), false);
}
?>

基本上,如果提供了域参数,它将被转换为支持更广泛的域。这种行为可能是也可能不是可取的(例如,根据服务器的情况,可能存在安全问题),但它使 cookie 处理变得非常方便(IMO)。
To Top