-
Notifications
You must be signed in to change notification settings - Fork 105
/
Copy pathsetcookie.xml
377 lines (364 loc) · 14.2 KB
/
setcookie.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 1ad4e2d550953000e2441b663226300596962ef2 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>
<para>自 PHP 7.3.0 起可用的替代签名(不支持命名参数):</para>
<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>
<para>
<function>setcookie</function> 定义了
Cookie,会和剩下的消息头一起发送给客户端。和其他消息头一样,必须在脚本产生任意输出<emphasis>之前</emphasis>发送
Cookie(由于协议的限制)。请在产生任何输出之前(包括 <literal><html></literal> 和 <literal><head></literal> 或者空格)调用本函数。
</para>
<para>
一旦设置 Cookie 后,下次打开页面时可以使用 <varname>$_COOKIE</varname>
读取。Cookie 值同样也存在于 <varname>$_REQUEST</varname>。
</para>
</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>
<para>
Cookie 名称。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>value</parameter></term>
<listitem>
<para>
Cookie 值。这个值储存于用户的电脑里,请勿储存敏感信息。比如
<parameter>name</parameter> 是 <literal>'cookiename'</literal>,可通过
<varname>$_COOKIE['cookiename']</varname> 获取它的值。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>expires_or_options</parameter></term>
<listitem>
<para>
Cookie 的过期时间。这是 Unix 时间戳,即纪元以来的秒数。一种设置此值的方式是将
cookie 过期前的秒数与调用 <function>time</function>
的结果相加。例如,<literal>time()+60*60*24*30</literal>
就是设置 Cookie 30 天后过期。还有一种选择就是使用 <function>mktime</function>
函数。如果设置为 <literal>0</literal> 或者忽略,Cookie 会在会话结束时过期(关掉浏览器时)。
</para>
<para>
<note>
<para>
可能会注意到,<parameter>expires_or_options</parameter> 使用 Unix 时间戳而非 <literal>Wdy, DD-Mon-YYYY
HH:MM:SS GMT</literal> 这样的日期格式,是因为 PHP 内部作了转换。
</para>
</note>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>path</parameter></term>
<listitem>
<para>
Cookie 有效的服务器路径。设置成 <literal>'/'</literal> 时,Cookie 对整个域名
<parameter>domain</parameter> 有效。如果设置成 <literal>'/foo/'</literal>,Cookie
仅仅对 <parameter>domain</parameter> 中 <literal>/foo/</literal>
目录及其子目录有效(比如 <literal>/foo/bar/</literal>)。默认值是设置 Cookie 时的当前目录。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>domain</parameter></term>
<listitem>
<para>
Cookie 的有效域名/子域名。设置成子域名(例如 <literal>'www.example.com'</literal>),会使
Cookie 对这个子域名和它的三级域名有效(例如 w2.www.example.com)。要让 Cookie
对整个域名有效(包括它的全部子域名),只要设置成域名就可以了(这个示例里是 <literal>'example.com'</literal>)。
</para>
<para>
旧版浏览器仍然在使用废弃的 <link xlink:href="&url.rfc;2109">RFC 2109</link>,需要一个前置的点
<literal>.</literal> 来匹配所有子域名。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>secure</parameter></term>
<listitem>
<para>
设置这个 Cookie 是否仅仅通过安全的 HTTPS 连接传给客户端。设置成 &true; 时,只有安全连接存在时才会设置
Cookie。如果是在服务器端处理这个需求,程序员需要仅仅在安全连接上发送此类 Cookie(通过
<varname>$_SERVER["HTTPS"]</varname> 判断)。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>httponly</parameter></term>
<listitem>
<para>
设置成 &true;,Cookie 仅可通过 HTTP 协议访问。这意思就是 Cookie 无法通过类似 JavaScript
这样的脚本语言访问。要有效减少 XSS 攻击时的身份窃取行为,可建议用此设置(虽然不是所有浏览器都支持),不过这个说法经常有争议。
&true; 或 &false;
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>options</parameter></term>
<listitem>
<para>
关联 <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 属性。
</para>
<para>
<note>
<para>
要设置一个包含不在列出的关键字中的属性的 Cookie,使用 <function>header</function>。
</para>
</note>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
如果在调用本函数以前就产生了输出,<function>setcookie</function> 会失败并返回 &false;。如果
<function>setcookie</function> 成功运行,返回 &true;。当然,它的意思并非用户是否已接受 Cookie。
</para>
</refsect1>
<refsect1 role="changelog">
&reftitle.changelog;
<para>
<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>
</para>
</refsect1>
<refsect1 role="examples">
&reftitle.examples;
<para>
以下示例展示了一些发送 Cookie 的方法。
<example>
<title><function>setcookie</function> 发送示例</title>
<programlisting role="php">
<![CDATA[
<?php
$value = 'something from somewhere';
setcookie("TestCookie", $value);
setcookie("TestCookie", $value, time()+3600); /* 1 小时过期 */
setcookie("TestCookie", $value, time()+3600, "/~rasmus/", "example.com", true);
?>
]]>
</programlisting>
</example>
</para>
<para>
注意:在发送 Cookie 时,值的部分会被自动 urlencode 编码。收到 Cookie 时,会自动解码,并赋值到可变的
Cookie 名称上。如果不想被编码,可以使用 <function>setrawcookie</function>
代替。在脚本里查看我们的测试 Cookie 的内容,使用下面的一个示例:
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// 打印一个单独的 Cookie
echo $_COOKIE["TestCookie"];
// debug/test 查看所有 Cookie 的另一种方式
print_r($_COOKIE);
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
<example>
<title><function>setcookie</function> 删除示例</title>
<para>
要删除一个 Cookie,应该设置过期时间为过去,以触发浏览器的删除机制。下面的示例展示了如何删除上个示例里的 Cookie:
</para>
<programlisting role="php">
<![CDATA[
<?php
// 设置过期时间为一个小时前
setcookie("TestCookie", "", time() - 3600);
setcookie("TestCookie", "", time() - 3600, "/~rasmus/", "example.com", 1);
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title><function>setcookie</function> 和数组</title>
<para>
通过带 array 标记的 Cookie 名称,也可以把 Cookie 设置成数组。如果有数组元素,可以把它放进 Cookie
里;脚本接收到时,Cookie 名称里的值会是一个数组:
</para>
<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>
</para>
</refsect1>
<refsect1 role="notes">
&reftitle.notes;
<note>
<para>
要在调用本函数前输出内容,可以使用输出缓冲,让输出的内容在服务器里缓冲起来,直至真正发送给浏览器。可在脚本里调用
<function>ob_start</function> 和 <function>ob_end_flush</function>,或设置
<literal>output_buffering</literal> &php.ini; 或服务器配置文件里的配置指令。
</para>
</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>explode</function> 为一个 Cookie 设置多个名称和值。
不建议将 <function>serialize</function> 用于此处,因为它会导致安全漏洞。
</simpara>
</listitem>
</itemizedlist>
</para>
<simpara>
多次调用 <function>setcookie</function> 会按调用顺序执行。
</simpara>
</refsect1>
<refsect1 role="seealso">
&reftitle.seealso;
<para>
<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>
</para>
</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
-->