Cookie
一个**HTTP cookie**(网站 cookie、浏览器 cookie)是一个服务器发送到用户浏览器的一小段数据。浏览器可以存储它,并在以后向同一服务器的请求中发送它。通常,它用于判断两个请求是否来自同一个浏览器 - 例如,用于保持用户登录状态。它为无状态的 HTTP 协议保存状态信息。
Cookie 主要用于三个目的:
- 会话管理:登录、购物车、游戏分数或服务器需要记住的任何其他内容 
- 个性化:用户首选项、主题和其他设置 
- 跟踪:记录和分析用户行为 
为了帮助你在请求和响应中跨浏览器高效使用 cookie,CodeIgniter 提供了 CodeIgniter\Cookie\Cookie 类来抽象 cookie 的交互。
创建 Cookie
目前有四种方式可以创建一个新的 Cookie 值对象。
<?php
use CodeIgniter\Cookie\Cookie;
use DateTime;
// Using the constructor
$cookie = new Cookie(
    'remember_token',
    'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6',
    [
        'expires'  => new DateTime('+2 hours'),
        'prefix'   => '__Secure-',
        'path'     => '/',
        'domain'   => '',
        'secure'   => true,
        'httponly' => true,
        'raw'      => false,
        'samesite' => Cookie::SAMESITE_LAX,
    ]
);
// Supplying a Set-Cookie header string
$cookie = Cookie::fromHeaderString(
    'remember_token=f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6; Path=/; Secure; HttpOnly; SameSite=Lax',
    false, // raw
);
// Using the fluent builder interface
$cookie = (new Cookie('remember_token'))
    ->withValue('f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6')
    ->withPrefix('__Secure-')
    ->withExpires(new DateTime('+2 hours'))
    ->withPath('/')
    ->withDomain('')
    ->withSecure(true)
    ->withHTTPOnly(true)
    ->withSameSite(Cookie::SAMESITE_LAX);
// Using the global function `cookie` which implicitly calls `new Cookie()`
$cookie = cookie('remember_token', 'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6');
在构造 Cookie 对象时,只需要 name 属性是必需的。其余的都是可选的。如果没有修改可选属性,它们的值将由 Cookie 类中保存的默认值填充。要覆盖类中当前存储的默认值,你可以传递一个 Config\Cookie 实例或默认值数组给静态 Cookie::setDefaults() 方法。
<?php
use CodeIgniter\Cookie\Cookie;
use Config\Cookie as CookieConfig;
// pass in a Config\Cookie instance before constructing a Cookie class
Cookie::setDefaults(new CookieConfig());
$cookie = new Cookie('login_token');
// pass in an array of defaults
$myDefaults = [
    'expires'  => 0,
    'samesite' => Cookie::SAMESITE_STRICT,
];
Cookie::setDefaults($myDefaults);
$cookie = new Cookie('login_token');
将 Config\Cookie 实例或数组传递给 Cookie::setDefaults() 将有效地覆盖你的默认值,并且持续到新的默认值被传递。如果你不想要这种行为,而只是想在有限的时间内更改默认值,你可以利用 Cookie::setDefaults() 的返回值,它返回旧的默认值数组。
<?php
use CodeIgniter\Cookie\Cookie;
use Config\Cookie as CookieConfig;
$oldDefaults = Cookie::setDefaults(new CookieConfig());
$cookie      = new Cookie('my_token', 'muffins');
// return the old defaults
Cookie::setDefaults($oldDefaults);
访问 Cookie 的属性
一旦实例化,你就可以通过使用其 getter 方法之一轻松访问 Cookie 的属性。
<?php
use CodeIgniter\Cookie\Cookie;
use DateTime;
use DateTimeZone;
$cookie = new Cookie(
    'remember_token',
    'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6',
    [
        'expires'  => new DateTime('2025-02-14 00:00:00', new DateTimeZone('UTC')),
        'prefix'   => '__Secure-',
        'path'     => '/',
        'domain'   => '',
        'secure'   => true,
        'httponly' => true,
        'raw'      => false,
        'samesite' => Cookie::SAMESITE_LAX,
    ]
);
$cookie->getName(); // 'remember_token'
$cookie->getPrefix(); // '__Secure-'
$cookie->getPrefixedName(); // '__Secure-remember_token'
$cookie->getExpiresTimestamp(); // Unix timestamp
$cookie->getExpiresString(); // 'Fri, 14-Feb-2025 00:00:00 GMT'
$cookie->isExpired(); // false
$cookie->getMaxAge(); // the difference from time() to expires
$cookie->isRaw(); // false
$cookie->isSecure(); // true
$cookie->getPath(); // '/'
$cookie->getDomain(); // ''
$cookie->isHTTPOnly(); // true
$cookie->getSameSite(); // 'Lax'
// additional getter
$cookie->getId(); // '__Secure-remember_token;;/'
// when using `setcookie()`'s alternative signature on PHP 7.3+
// you can easily use the `getOptions()` method to supply the
// $options parameter
$cookie->getOptions();
不可变 Cookie
新的 Cookie 实例是一个 HTTP cookie 的不可变值对象表示。由于是不可变的,修改实例的任何属性都不会影响原始实例。修改**总是**返回一个新实例。你需要保留这个新实例才能使用它。
<?php
use CodeIgniter\Cookie\Cookie;
$cookie = new Cookie('login_token', 'admin');
$cookie->getName(); // 'login_token'
$cookie->withName('remember_token');
$cookie->getName(); // 'login_token'
$new = $cookie->withName('remember_token');
$new->getName(); // 'remember_token'
验证 Cookie 的属性
一个 HTTP cookie 受到几个规范的约束,这些规范需要遵循才能被浏览器接受。因此,在创建或修改 Cookie 的某些属性时,会对其进行验证,以检查它们是否遵循规范。
如果报告了违规,则会抛出 CookieException。
验证名称属性
cookie 名称可以是任何 US-ASCII 字符,以下字符除外:
- 控制字符; 
- 空格或制表符; 
- 分隔符,例如 - ( ) < > @ , ; : \ " / [ ] ? = { }
如果将 $raw 参数设置为 true,则会严格进行此验证。这是因为 PHP 的 setcookie 和 setrawcookie 会拒绝具有无效名称的 cookie。另外,cookie 名称不能为空字符串。
验证前缀属性
在使用 __Secure- 前缀时,必须将 cookie 的 $secure 标志设置为 true。如果使用 __Host- 前缀,cookie 必须展示以下特征:
- 将 - $secure标志设置为- true
- $domain为空
- $path必须为- /
验证 SameSite 属性
SameSite 属性只接受三个值:
- Lax: 在第三方站点加载图像或框架等正常跨站子请求时不会发送 Cookie,但是在用户导航到源站点时会发送(即点击链接时)。 
- Strict: Cookie 只会在第一方环境下发送,不会随第三方网站发起的请求一起发送。 
- None: 在所有环境下发送 Cookie,即对第一方和跨域请求的响应中都会发送。 
但是,CodeIgniter 允许你将 SameSite 属性设置为空字符串。提供空字符串时,将使用 Cookie 类中保存的默认 SameSite 设置。如上所述,你可以使用 Cookie::setDefaults() 更改默认 SameSite。
最近的 cookie 规范做了更改,要求现代浏览器在未提供时给一个默认的 SameSite。这个默认的是 Lax。如果你已将 SameSite 设置为空字符串,而默认的 SameSite 也为空字符串,你的 cookie 将被赋予 Lax 值。
如果将 SameSite 设置为 None,你需要确保 Secure 也设置为 true。
在编写 SameSite 属性时, Cookie 类以不区分大小写的方式接受任何这些值。你也可以利用类的常量来避免麻烦。
<?php
use CodeIgniter\Cookie\Cookie;
Cookie::SAMESITE_LAX; // 'lax'
Cookie::SAMESITE_STRICT; // 'strict'
Cookie::SAMESITE_NONE; // 'none'
使用 Cookie 存储
CookieStore 类表示 Cookie 对象的一个不可变集合。可以从当前的 Response 对象访问 CookieStore 实例。
<?php
use Config\Services;
$cookieStore = Services::response()->getCookieStore();
CodeIgniter 提供了另外三种创建 CookieStore 新实例的方法。
<?php
use CodeIgniter\Cookie\Cookie;
use CodeIgniter\Cookie\CookieStore;
// Passing an array of `Cookie` objects in the constructor
$store = new CookieStore([
    new Cookie('login_token'),
    new Cookie('remember_token'),
]);
// Passing an array of `Set-Cookie` header strings
$store = CookieStore::fromCookieHeaders([
    'remember_token=me; Path=/; SameSite=Lax',
    'login_token=admin; Path=/; SameSite=Lax',
]);
// using the global `cookies` function
$store = cookies([new Cookie('login_token')], false);
// retrieving the `CookieStore` instance saved in our current `Response` object
$store = cookies();
备注
在使用全局 cookies() 函数时,只有在第二个参数 $getGlobal 设置为 false 时,才会考虑传递的 Cookie 数组。
检查存储中的 Cookie
要检查 CookieStore 实例中是否存在一个 Cookie 对象,你可以用几种方法:
<?php
use CodeIgniter\Cookie\Cookie;
use CodeIgniter\Cookie\CookieStore;
use Config\Services;
// check if cookie is in the current cookie collection
$store = new CookieStore([
    new Cookie('login_token'),
    new Cookie('remember_token'),
]);
$store->has('login_token');
// check if cookie is in the current Response's cookie collection
cookies()->has('login_token');
Services::response()->hasCookie('remember_token');
// using the cookie helper to check the current Response
// not available to v4.1.1 and lower
helper('cookie');
has_cookie('login_token');
获取存储中的 Cookie
在 cookie 集合中检索一个 Cookie 实例非常简单:
<?php
use CodeIgniter\Cookie\Cookie;
use CodeIgniter\Cookie\CookieStore;
use Config\Services;
// getting cookie in the current cookie collection
$store = new CookieStore([
    new Cookie('login_token'),
    new Cookie('remember_token'),
]);
$store->get('login_token');
// getting cookie in the current Response's cookie collection
cookies()->get('login_token');
Services::response()->getCookie('remember_token');
// using the cookie helper to get cookie from the Response's cookie collection
helper('cookie');
get_cookie('remember_token');
从 CookieStore 直接获取 Cookie 实例时,无效名称会抛出 CookieException。
<?php
// throws CookieException
$store->get('unknown_cookie');
从当前 Response 的 cookie 集合获取 Cookie 实例时,无效名称只会返回 null。
<?php
cookies()->get('unknown_cookie'); // null
如果在从 Response 获取 cookie 时没有提供参数,则会显示存储中的所有 Cookie 对象。
<?php
cookies()->get(); // array of Cookie objects
// alternatively, you can use the display method
cookies()->display();
// or even from the Response
Services::response()->getCookies();
备注
帮助函数 get_cookie() 从当前的 Request 对象获取 cookie,而不是从 Response 获取。如果该 cookie 已设置,此函数会检查 $_COOKIE 数组并立即获取它。
在存储中添加/删除 Cookie
如前所述, CookieStore 对象是不可变的。你需要保存修改后的实例才能对其进行操作。原始实例保持不变。
<?php
use CodeIgniter\Cookie\Cookie;
use CodeIgniter\Cookie\CookieStore;
use Config\Services;
$store = new CookieStore([
    new Cookie('login_token'),
    new Cookie('remember_token'),
]);
// adding a new Cookie instance
$new = $store->put(new Cookie('admin_token', 'yes'));
// removing a Cookie instance
$new = $store->remove('login_token');
备注
从存储中删除 cookie 不会 从浏览器中删除它。 如果你打算从浏览器中删除 cookie,你必须向存储放入一个具有相同名称的空值 cookie。
当与当前 Response 对象中的 cookie 存储进行交互时,你可以安全地添加或删除 cookie,而不用担心 cookie 集合的不可变性质。 Response 对象将用修改后的实例替换该实例。
<?php
use Config\Services;
Services::response()->setCookie('admin_token', 'yes');
Services::response()->deleteCookie('login_token');
// using the cookie helper
helper('cookie');
set_cookie('admin_token', 'yes');
delete_cookie('login_token');
分派存储中的 Cookie
更多时候,你不需要自己手动发送 cookie。CodeIgniter 会为你做这件事。但是,如果你真的需要手动发送 cookie,你可以使用 dispatch 方法。就像发送其他标头一样,你需要确保标头还未发送,方法是检查 headers_sent() 的值。
<?php
use CodeIgniter\Cookie\Cookie;
use CodeIgniter\Cookie\CookieStore;
$store = new CookieStore([
    new Cookie('login_token'),
    new Cookie('remember_token'),
]);
$store->dispatch(); // After dispatch, the collection is now empty.
Cookie 个性化
Cookie 类中已经有了一些默认设置,以确保平滑地创建 cookie 对象。但是,你可能希望通过更改 app/Config/Cookie.php 文件中的以下 Config\Cookie 类来定义自己的设置。
| 设置 | 选项/类型 | 默认值 | 描述 | 
|---|---|---|---|
| $prefix | 
 | 
 | 要添加到 cookie 名称前面的前缀。 | 
| $expires | 
 | 
 | 过期时间戳。 | 
| $path | 
 | 
 | cookie 的 path 属性。 | 
| $domain | 
 | 
 | cookie 的 domain 属性,带尾部斜杠。 | 
| $secure | 
 | 
 | 是否通过安全的 HTTPS 发送。 | 
| $httponly | 
 | 
 | 是否不可通过 JavaScript 访问。 | 
| $samesite | 
 | 
 | SameSite 属性。 | 
| $raw | 
 | 
 | 是否使用  | 
在运行时,你可以使用 Cookie::setDefaults() 方法手动提供新的默认值。
类参考
- class CodeIgniter\Cookie\Cookie
- static setDefaults([$config = []])
- 参数
- $config ( - ConfigCookie|array) – 配置数组或实例
 
- 返回类型
- array
- 返回
- 旧的默认值 
 - 通过从 - \Config\Cookie配置或数组中注入值来设置 Cookie 实例的默认属性。
 - static fromHeaderString(string $header[, bool $raw = false])
- 参数
- $header ( - string) –- Set-Cookie头字符串
- $raw ( - bool) – 是否不进行 URL 编码并通过- setrawcookie()发送
 
- 返回类型
- Cookie
- 返回
- Cookie实例
- Throws
- CookieException
 - 从 - Set-Cookie头创建一个新的 Cookie 实例。
 - __construct(string $name[, string $value = ''[, array $options = []]])
- 参数
- $name ( - string) – cookie 名称
- $value ( - string) – cookie 值
- $options ( - array) – cookie 选项
 
- 返回类型
- Cookie
- 返回
- Cookie实例
- Throws
- CookieException
 - 构造一个新的 Cookie 实例。 
 - getId()
- 返回类型
- string
- 返回
- 在 cookie 集合中的索引 ID。 
 
 - getPrefix() → string
 - getName() → string
 - getPrefixedName() → string
 - getValue() → string
 - getExpiresTimestamp() → int
 - getExpiresString() → string
 - isExpired() → bool
 - getMaxAge() → int
 - getDomain() → string
 - getPath() → string
 - isSecure() → bool
 - isHTTPOnly() → bool
 - getSameSite() → string
 - isRaw() → bool
 - getOptions() → array
 - withRaw([bool $raw = true])
- 参数
- $raw ( - bool) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个更新了 URL 编码选项的新的 Cookie。 
 - withPrefix([string $prefix = ''])
- 参数
- $prefix ( - string) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新前缀的新的 Cookie。 
 - withName(string $name)
- 参数
- $name ( - string) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新名称的新的 Cookie。 
 - withValue(string $value)
- 参数
- $value ( - string) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新值的新的 Cookie。 
 - withExpires($expires)
- 参数
- $expires ( - DateTimeInterface|string|int) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新的 cookie 过期时间的新的 Cookie。 
 - withExpired()
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个从浏览器过期的新的 Cookie。 
 - withNeverExpiring()
- 4.2.6 版后已移除. - 重要 - 这个方法已弃用。它将在未来的版本中删除。 - 参数
- $name ( - string) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个几乎永不过期的新的 Cookie。 
 - withDomain(?string $domain)
- 参数
- $domain ( - string|null) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新域的新的 Cookie。 
 - withPath(?string $path)
- 参数
- $path ( - string|null) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新路径的新的 Cookie。 
 - withSecure([bool $secure = true])
- 参数
- $secure ( - bool) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新的“Secure”属性的新的 Cookie。 
 - withHTTPOnly([bool $httponly = true])
- 参数
- $httponly ( - bool) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新的“HttpOnly”属性的新的 Cookie。 
 - withSameSite(string $samesite)
- 参数
- $samesite ( - string) –
 
- 返回类型
- Cookie
- 返回
- 新的 - Cookie实例
 - 创建一个带有新的“SameSite”属性的新的 Cookie。 
 - toHeaderString()
- 返回类型
- string
- 返回
- 可以作为头字符串传递的字符串表示。 
 
 - toArray()
- 返回类型
- array
- 返回
- 返回 Cookie 实例的数组表示形式。 
 
 
- class CodeIgniter\Cookie\CookieStore
- static fromCookieHeaders(array $headers[, bool $raw = false])
- 参数
- $header ( - array) –- Set-Cookie头数组
- $raw ( - bool) – 是否不使用 URL 编码
 
- 返回类型
- CookieStore
- 返回
- CookieStore实例
- Throws
- CookieException
 - 从 - Set-Cookie头数组创建一个 CookieStore。
 - __construct(array $cookies)
- 参数
- $cookies ( - array) –- Cookie对象数组
 
- 返回类型
- CookieStore
- 返回
- CookieStore实例
- Throws
- CookieException
 
 - has(string $name[, string $prefix = ''[, ?string $value = null]]) → bool
- 参数
- $name ( - string) – Cookie 名称
- $prefix ( - string) – Cookie 前缀
- $value ( - string|null) – Cookie 值
 
- 返回类型
- bool
- 返回
- 检查由名称和前缀标识的 - Cookie对象是否存在于集合中。
 
 - get(string $name[, string $prefix = '']) → Cookie
- 参数
- $name ( - string) – Cookie 名称
- $prefix ( - string) – Cookie 前缀
 
- 返回类型
- Cookie
- 返回
- 检索由名称和前缀标识的 Cookie 实例。 
- Throws
- CookieException
 
 - put(Cookie $cookie) → CookieStore
- 参数
- $cookie ( - Cookie) – 一个 Cookie 对象
 
- 返回类型
- CookieStore
- 返回
- 新的 - CookieStore实例
 - 存储一个新 cookie 并返回一个新集合。原始集合保持不变。 
 - remove(string $name[, string $prefix = '']) → CookieStore
- 参数
- $name ( - string) – Cookie 名称
- $prefix ( - string) – Cookie 前缀
 
- 返回类型
- CookieStore
- 返回
- 新的 - CookieStore实例
 - 从集合中删除一个 cookie 并返回更新后的集合。原始集合保持不变。 
 - dispatch() → void
- 返回类型
- void
 - 分派存储中的所有 cookie。 
 - display() → array
- 返回类型
- array
- 返回
- 返回存储中的所有 cookie 
 
 - clear() → void
- 返回类型
- void
 - 清除 cookie 集合。