mirror of
https://github.com/php/doc-zh.git
synced 2026-03-26 08:02:16 +01:00
377 lines
15 KiB
XML
377 lines
15 KiB
XML
<?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><html></literal> 和 <literal><head></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
|
||
-->
|