1
0
mirror of https://github.com/php/doc-zh.git synced 2026-03-26 08:02:16 +01:00
Files
2026-01-22 10:32:08 +08:00

377 lines
15 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 9434c9439bb8f86d92ba5f227151432ea0b90b8f Maintainer: daijie Status: ready -->
<!-- CREDITS: mowangjuanzi, Luffy -->
<refentry xml:id="function.setcookie" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<refnamediv>
<refname>setcookie</refname>
<refpurpose>发送 Cookie</refpurpose>
</refnamediv>
<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<type>bool</type><methodname>setcookie</methodname>
<methodparam><type>string</type><parameter>name</parameter></methodparam>
<methodparam choice="opt"><type>string</type><parameter>value</parameter><initializer>""</initializer></methodparam>
<methodparam choice="opt"><type>int</type><parameter>expires_or_options</parameter><initializer>0</initializer></methodparam>
<methodparam choice="opt"><type>string</type><parameter>path</parameter><initializer>""</initializer></methodparam>
<methodparam choice="opt"><type>string</type><parameter>domain</parameter><initializer>""</initializer></methodparam>
<methodparam choice="opt"><type>bool</type><parameter>secure</parameter><initializer>&false;</initializer></methodparam>
<methodparam choice="opt"><type>bool</type><parameter>httponly</parameter><initializer>&false;</initializer></methodparam>
</methodsynopsis>
<simpara>自 PHP 7.3.0 起可用的替代签名(不支持命名参数):</simpara>
<methodsynopsis>
<type>bool</type><methodname>setcookie</methodname>
<methodparam><type>string</type><parameter>name</parameter></methodparam>
<methodparam choice="opt"><type>string</type><parameter>value</parameter><initializer>""</initializer></methodparam>
<methodparam choice="opt"><type>array</type><parameter>options</parameter><initializer>[]</initializer></methodparam>
</methodsynopsis>
<simpara>
<function>setcookie</function> 用于定义 Cookie会和其它 HTTP header 一起发送给客户端。和其他 HTTP header 一样Cookie
必须在脚本输出任意内容<emphasis>之前</emphasis>发送 Cookie这是协议限制。该函数必须在输出任何内容包括
<literal>&lt;html&gt;</literal><literal>&lt;head&gt;</literal> 或者任何空白字符)之前调用。
</simpara>
<simpara>
一旦设置 Cookie 后,下次打开页面时可以使用 <varname>$_COOKIE</varname>
读取。Cookie 值同样也存在于 <varname>$_REQUEST</varname>
</simpara>
</refsect1>
<refsect1 role="parameters">
&reftitle.parameters;
<para>
<link xlink:href="&url.rfc;6265">RFC 6265</link> 提供了 <function>setcookie</function> 每个参数的参考标准。
<variablelist>
<varlistentry>
<term><parameter>name</parameter></term>
<listitem>
<simpara>
Cookie 名称。
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>value</parameter></term>
<listitem>
<simpara>
Cookie 值。这个值储存于用户的电脑里,请勿储存敏感信息。比如
<parameter>name</parameter><literal>'cookiename'</literal>,可通过
<varname>$_COOKIE['cookiename']</varname> 获取它的值。
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>expires_or_options</parameter></term>
<listitem>
<simpara>
Cookie 的过期时间。这是 Unix 时间戳,即纪元以来的秒数。一种设置此值的方式是将
cookie 过期前的秒数与调用 <function>time</function>
的结果相加。例如,<literal>time()+60*60*24*30</literal>
就是设置 Cookie 30 天后过期。还有一种选择就是使用 <function>mktime</function>
函数。如果设置为 <literal>0</literal> 或者忽略Cookie 会在会话结束时过期(关掉浏览器时)。
</simpara>
<note>
<simpara>
<parameter>expires_or_options</parameter> 使用 Unix 时间戳而非 <literal>Wdy, DD-Mon-YYYY
HH:MM:SS GMT</literal> 这样的日期格式,是因为 PHP 内部作了转换。
</simpara>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>path</parameter></term>
<listitem>
<simpara>
Cookie 有效的服务器路径。设置成 <literal>'/'</literal>Cookie 对整个域名
<parameter>domain</parameter> 有效。如果设置成 <literal>'/foo/'</literal>Cookie
仅仅对 <parameter>domain</parameter><literal>/foo/</literal>
目录及其子目录有效(比如 <literal>/foo/bar/</literal>)。默认值是设置 Cookie 时的当前目录。
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>domain</parameter></term>
<listitem>
<simpara>
Cookie 的有效域名/子域名。设置成子域名(例如 <literal>'www.example.com'</literal>),会使
Cookie 对这个子域名和它的三级域名有效(例如 w2.www.example.com。要让 Cookie
对整个域名有效(包括它的全部子域名),只要设置成域名就可以了(这个示例里是 <literal>'example.com'</literal>)。
</simpara>
<simpara>
旧版浏览器仍然在使用废弃的 <link xlink:href="&url.rfc;2109">RFC 2109</link>,需要一个前置的点
<literal>.</literal> 来匹配所有子域名。
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>secure</parameter></term>
<listitem>
<simpara>
设置这个 Cookie 是否仅仅通过安全的 HTTPS 连接传给客户端。设置成 &true; 时,只有安全连接存在时才会设置
Cookie。如果是在服务器端处理这个需求程序员需要仅仅在安全连接上发送此类 Cookie通过
<varname>$_SERVER["HTTPS"]</varname> 判断)。
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>httponly</parameter></term>
<listitem>
<simpara>
设置成 &true;Cookie 仅可通过 HTTP 协议访问。这意思就是 Cookie 无法通过类似 JavaScript
这样的脚本语言访问。要有效减少 XSS 攻击时的身份窃取行为,可建议用此设置(虽然不是所有浏览器都支持),不过这个说法经常有争议。
&true;&false;
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>options</parameter></term>
<listitem>
<simpara>
关联 <type>array</type>,可能会存在以下键
<literal>expires</literal><literal>path</literal><literal>domain</literal><literal>secure</literal><literal>httponly</literal>
<literal>samesite</literal>。如果存在其它的键,会生成 <constant>E_WARNING</constant>
级别的错误。这些值的含义跟同名参数的描述相同。<literal>samesite</literal> 元素的值应该是
<literal>None</literal><literal>Lax</literal>
<literal>Strict</literal>。如果没有指定任何允许的选项,它们的默认值与显式参数的默认值相同。如果省略
<literal>samesite</literal> 元素,则不设置 SameSite cookie 属性。
</simpara>
<note>
<simpara>
要设置一个包含不在列出的关键字中的属性的 Cookie使用 <function>header</function>
</simpara>
</note>
<note>
<simpara>
<literal>samesite</literal><literal>"None"</literal>,则必须同时启用
<literal>secure</literal>,否则客户端将阻止该 Cookie。
</simpara>
</note>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1 role="returnvalues">
&reftitle.returnvalues;
<simpara>
如果在调用本函数以前就产生了输出,<function>setcookie</function> 会失败并返回 &false;。如果
<function>setcookie</function> 成功运行,返回 &true;。当然,它的意思并非用户是否已接受 Cookie。
</simpara>
</refsect1>
<refsect1 role="changelog">
&reftitle.changelog;
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>8.2.0</entry>
<entry>
Cookie 的日期格式现在为 <literal>'D, d M Y H:i:s \G\M\T'</literal>
以前是 <literal>'D, d-M-Y H:i:s T'</literal>
</entry>
</row>
<row>
<entry>7.3.0</entry>
<entry>
新增对替代签名 <parameter>options</parameter> 数组的支持。此签名还支持 SameSite cookie 属性的设置。
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</refsect1>
<refsect1 role="examples">
&reftitle.examples;
<simpara>
下列示例的效果可通过浏览器开发者工具中的 Cookie 列表(通常位于 Storage 或 Application 标签页)进行观察。
</simpara>
<example>
<title><function>setcookie</function> 发送示例</title>
<programlisting role="php">
<![CDATA[
<?php
$value = 'something from somewhere';
// 设置“会话 Cookie”在浏览器关闭时失效
setcookie("TestCookie", $value);
// 设置一小时后失效的 Cookie
setcookie("TestCookie", $value, time()+3600);
// 设置仅适用于特定域名下特定路径的 Cookie
// 注意所使用的域名应与站点域名一致
setcookie("TestCookie", $value, time()+3600, "/~rasmus/", "example.com", true);
?>
]]>
</programlisting>
</example>
<simpara>
注意Cookie 的值部分会由 PHP 自动进行 URL 编码和解码。若要避免此行为,可改用 <function>setrawcookie</function>
</simpara>
<simpara>
要在后续请求中查看上述示例所设置的 Cookie 内容:
</simpara>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// 打印一个单独的 Cookie
echo $_COOKIE["TestCookie"];
// debug/test 查看所有 Cookie 的另一种方式
print_r($_COOKIE);
?>
]]>
</programlisting>
</informalexample>
<example>
<title><function>setcookie</function> 删除示例</title>
<simpara>
要删除 Cookie需将过期时间设为过去的时间值但不能设为零因为零专用于会话 Cookie
</simpara>
<simpara>
删除前例中设置的 Cookie
</simpara>
<programlisting role="php">
<![CDATA[
<?php
// 设置过期时间为一个小时前
setcookie("TestCookie", "", time() - 3600);
setcookie("TestCookie", "", time() - 3600, "/~rasmus/", "example.com", 1);
?>
]]>
</programlisting>
</example>
<example>
<title><function>setcookie</function> 和数组</title>
<simpara>
在 Cookie 名称中使用数组表示法可设置“Cookie 数组”。其效果是为数组中的每个元素分别设置一个
Cookie当脚本接收到 Cookie 时,所有值会被合并到一个以该 Cookie 名称命名的数组中:
</simpara>
<programlisting role="php">
<![CDATA[
<?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";
}
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
three : cookiethree
two : cookietwo
one : cookieone
]]>
</screen>
</example>
<note>
<simpara>
使用 <literal>[</literal><literal>]</literal> 分隔符作为 cookie 名称的一部分不符合
RFC 6265 第 4 节。但根据 RFC 6265 第 5 节应该由 user agent 支持。
</simpara>
</note>
</refsect1>
<refsect1 role="notes">
&reftitle.notes;
<note>
<simpara>
可使用输出缓冲机制,使脚本在调用此函数前产生输出。会缓冲所有输出,直到冲刷缓冲(手动冲刷或脚本执行结束时自动刷新)。实现方式是在脚本中调用
<function>ob_start</function><function>ob_end_flush</function>,或在 &php.ini; 或服务器配置文件中启用
<literal>output_buffering</literal> 配置项。
</simpara>
</note>
<para>
注意避坑:
<itemizedlist>
<listitem>
<simpara>
在页面Cookie 可见的页面下次刷新前Cookie 不会生效。
测试 Cookie 是否已经成功设置需要在下次页面加载时、Cookie 过期前检测。
过期时间是通过 <parameter>expires_or_options</parameter> 参数设置的。
直接调用 <literal>print_r($_COOKIE);</literal> 调试检测 Cookie 是个很好的方式。
</simpara>
</listitem>
<listitem>
<simpara>
为同一个参数再次设置 Cookie 前,必须先把它删掉。
如果 <parameter>value</parameter> 的值是空 string并且其他参数和上次调用 <function>setcookie</function> 仍旧一样,
则指定的名称会被远程客户端删除。
内部的实现是:将值设置成 <literal>'deleted'</literal>,且过去的过期时间。
</simpara>
</listitem>
<listitem>
<simpara>
因为设置值成 &false; 会导致 Cookie 被删除,所以不应该使用布尔值。代替方式:<emphasis>0</emphasis>&false;<emphasis>1</emphasis>&true;
</simpara>
</listitem>
<listitem>
<simpara>
Cookie 名称可以设置成数组名称PHP 脚本里会是数组,浏览器储存的是单独分开的 Cookie。可以考虑使用
<function>json_encode</function> 为一个 Cookie 设置多个名称和值。不建议将
<function>serialize</function> 用于此处,因为它会导致安全漏洞。
</simpara>
</listitem>
</itemizedlist>
</para>
<simpara>
多次调用 <function>setcookie</function> 会按调用顺序执行。
</simpara>
</refsect1>
<refsect1 role="seealso">
&reftitle.seealso;
<simplelist>
<member><function>header</function></member>
<member><function>setrawcookie</function></member>
<member><link linkend="features.cookies">Cookie 章节</link></member>
<member><link xlink:href="&url.rfc;6265">RFC 6265</link></member>
<member><link xlink:href="&url.rfc;2109">RFC 2109</link></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->