PHP Conference Japan 2024

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() 定义一个要与 HTTP 标头其余部分一起发送的 Cookie。与其他标头一样,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/)的 domain 中可用。默认值为设置 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); /* 过期时间为 1 小时 */
setcookie("TestCookie", $value, time()+3600, "/~rasmus/", "example.com", true);

?>

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

<?php
// 打印单个 Cookie
echo $_COOKIE["TestCookie"];

// 另一种调试/测试方法是查看所有 Cookie
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,因此您不应使用布尔值。相反,对于 false,使用 0,对于 true,使用 1
  • Cookie 名称可以设置为数组名称,并且可以作为数组在 PHP 脚本中使用,但单独的 Cookie 存储在用户的系统上。考虑使用 explode() 来设置一个具有多个名称和值的 Cookie。不建议为此目的使用 serialize(),因为它可能导致安全漏洞。

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

参见

添加注释

用户贡献的注释 12 条注释

389
walterquez
12 年前
而不是这样
<?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);

就是这样。
88
Anonymous
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);
?>
1
ilya at ilya dot top
3 个月前
在任何 Web 浏览器中,都存在一个非常常用的选项“打开以前的窗口和选项卡”,默认情况下该选项处于禁用状态,但许多人会启用它。
当此选项处于活动状态时,Web 浏览器在关闭和重新打开时,不会执行终止并启动新会话的操作,而是会保存并恢复当前会话以及会话 Cookie 和 sessionStorage。
与预期相反,会话 Cookie 和 sessionStorage 都可以存在很长时间,直到用户在关闭 Web 浏览器之前关闭选项卡。
如果您希望 Cookie(例如带有时间偏移的 Cookie)保证具有较短的生命周期,则应明确指定此较短的生命周期,而不是依赖于会话 Cookie 上的自删除。
35
paul nospam AT nospam sitepoint dot com
17年前
注意,在设置“数组 Cookie”时,每个数组元素都会设置一个单独的 Cookie。

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

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

<?php
// 这实际上会设置名为 'ace_fontSize' 的 Cookie:
setcookie( 'ace.fontSize', 18 );
?>
40
匿名用户
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);

?>
18
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, '/');
}
}

?>
9
ellert at vankoperen dot nl
10年前
警告:如果您使用 URL 重写规则将类似 domain.com/bla/stuf/etc 这样的内容转换为参数,则在设置 Cookie 时可能会遇到问题。
至少在我的设置中,其中一个参数的更改会导致 Cookie 不再“存在”。
解决方法很简单:指定域名。'/' 通常可以正常工作。
9
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 代码 ....

?>
4
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
匿名用户
14年前
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"。

希望这能为某些人节省一些时间。
To Top