setrawcookie() 函数用于发送一个未经 URL 编码的 Cookie。
与 setcookie() 函数不同,setrawcookie() 不会对 Cookie 值进行自动 URL 编码。这在你需要存储原始二进制数据或已经编码过的数据时非常有用。
setrawcookie() 函数必须在任何实际输出之前调用,包括 HTML 标签、空格、换行符或 PHP 输出。否则会导致 "headers already sent" 错误。
setrawcookie ( string $name [, string $value = "" [, int $expires = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] ) : bool
从 PHP 7.3.0 开始,支持数组参数格式:
setrawcookie ( string $name , string $value = "" , array $options = [] ) : bool
| 参数 | 类型 | 描述 |
|---|---|---|
$name |
string | 必需的。Cookie 的名称。 |
$value |
string |
可选的。Cookie 的原始值。不会进行 URL 编码。
注意:值中不能包含换行符、回车符等可能破坏 HTTP 头格式的字符。
|
$expires |
int |
可选的。Cookie 的过期时间,以 Unix 时间戳表示。
|
$path |
string |
可选的。Cookie 有效的服务器路径。
|
$domain |
string |
可选的。Cookie 有效的域名。
|
$secure |
bool |
可选的。如果设置为 true,Cookie 仅通过 HTTPS 连接传输。
|
$httponly |
bool |
可选的。如果设置为 true,Cookie 只能通过 HTTP 协议访问,JavaScript 无法访问。
|
$options (PHP 7.3+) |
array |
可选的。包含上述所有参数(除 $name 和 $value)的关联数组。
|
| 返回值 | 描述 |
|---|---|
true |
如果成功设置 Cookie 头信息。这并不意味着用户浏览器接受了 Cookie。 |
false |
如果设置失败。通常是因为:
|
| 特性 | setrawcookie() | setcookie() |
|---|---|---|
| URL 编码 | 不自动编码 值以原始形式发送 |
自动编码 值自动进行 URL 编码 |
| 特殊字符处理 | 需要手动处理特殊字符 | 自动处理特殊字符 |
| 二进制数据 | 适合存储二进制或已编码数据 | 需要先编码再存储 |
| JSON 数据 | 直接存储 JSON 字符串 | JSON 中的特殊字符会被编码 |
| 安全性 | 需要确保值中不包含破坏 HTTP 头的字符 | 更安全,自动处理编码问题 |
| 使用场景 | 存储已编码数据、二进制数据、严格控制格式的数据 | 存储普通文本、表单数据、大多数通用场景 |
设置一个未经 URL 编码的 Cookie。
<?php
// 设置原始 Cookie
$cookie_name = "raw_data";
$cookie_value = "Hello World!"; // 不会进行 URL 编码
$expiry_time = time() + (60 * 60); // 1小时后过期
if (setrawcookie($cookie_name, $cookie_value, $expiry_time)) {
echo "原始 Cookie '$cookie_name' 已设置成功。\n";
} else {
echo "设置原始 Cookie 失败。\n";
}
// 对比 setcookie() 的行为
$encoded_value = "Hello World!";
setcookie("encoded_data", $encoded_value, $expiry_time);
echo "setrawcookie() 发送的值: $cookie_value\n";
echo "setcookie() 发送的值会被编码,实际存储: " . urlencode($encoded_value) . "\n";
?>
使用 setrawcookie() 存储 JSON 字符串,避免双重编码问题。
<?php
// 准备 JSON 数据
$user_data = [
'id' => 123,
'name' => '张三',
'email' => 'zhangsan@example.com',
'preferences' => ['theme' => 'dark', 'language' => 'zh-CN']
];
$json_string = json_encode($user_data, JSON_UNESCAPED_UNICODE);
// 使用 setrawcookie() 存储 JSON
setrawcookie('user_json', $json_string, time() + (86400 * 7), '/');
// 对比:如果使用 setcookie(),JSON 中的特殊字符会被编码
setcookie('user_json_encoded', $json_string, time() + (86400 * 7), '/');
echo "JSON 数据已存储到 Cookie。\n";
echo "原始 JSON: " . $json_string . "\n\n";
// 读取 Cookie
if (isset($_COOKIE['user_json'])) {
$decoded_data = json_decode($_COOKIE['user_json'], true);
echo "从原始 Cookie 读取的数据:\n";
print_r($decoded_data);
}
// 注意:由于 Cookie 是浏览器发送的,特殊字符可能需要处理
function safe_json_cookie($name, $value, $expires = 0, $path = '/') {
// 确保 JSON 字符串是有效的
if (json_decode($value) === null && json_last_error() !== JSON_ERROR_NONE) {
return false;
}
// 使用 setrawcookie 存储原始 JSON
return setrawcookie($name, $value, $expires, $path);
}
?>
存储经过 Base64 编码的二进制数据。
<?php
// 假设有一些二进制数据(例如加密后的数据)
$binary_data = random_bytes(32); // 32字节的随机数据
$base64_data = base64_encode($binary_data);
// 使用 setrawcookie() 存储 Base64 编码的数据
// 注意:Base64 编码可能包含 '+'、'/'、'=' 等字符
if (setrawcookie('encrypted_data', $base64_data, time() + 3600, '/')) {
echo "Base64 编码数据已存储到 Cookie。\n";
echo "Base64 字符串: " . $base64_data . "\n";
// 解码验证
$decoded = base64_decode($base64_data);
echo "解码后长度: " . strlen($decoded) . " 字节\n";
} else {
echo "存储失败。\n";
}
// 安全注意事项:Base64 字符串可能包含 '=' 填充字符
// 这些字符在 Cookie 中是安全的,但某些旧系统可能有问题
function safe_base64_cookie($name, $data, $expires = 0, $path = '/') {
// 对 Base64 进行 URL 安全的编码(替换 '+' 和 '/')
$base64_url = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
return setrawcookie($name, $base64_url, $expires, $path);
}
// 使用安全版本
$secure_data = "敏感数据需要加密存储";
safe_base64_cookie('secure_cookie', $secure_data, time() + 3600, '/');
?>
当需要控制编码时,手动处理 Cookie 值。
<?php
// 需要包含特殊字符的值
$special_value = "Line 1\nLine 2\tTab"; // 包含换行符和制表符
// 这些字符会破坏 HTTP 头,需要处理
$safe_value = str_replace(["\n", "\r", "\t"], ['\\n', '\\r', '\\t'], $special_value);
if (setrawcookie('multiline_data', $safe_value, time() + 3600, '/')) {
echo "包含特殊字符的数据已安全存储。\n";
echo "原始值: " . addcslashes($special_value, "\n\r\t") . "\n";
echo "存储值: " . $safe_value . "\n";
}
// 读取时反向处理
if (isset($_COOKIE['multiline_data'])) {
$restored_value = str_replace(['\\n', '\\r', '\\t'], ["\n", "\r", "\t"], $_COOKIE['multiline_data']);
echo "恢复的值:\n" . $restored_value . "\n";
}
// 更通用的编码函数
function encode_cookie_value($value) {
// 对可能破坏 HTTP 头的字符进行编码
$search = ["\n", "\r", "\t", ";", ","];
$replace = ['%0A', '%0D', '%09', '%3B', '%2C'];
return str_replace($search, $replace, $value);
}
function decode_cookie_value($value) {
$search = ['%0A', '%0D', '%09', '%3B', '%2C'];
$replace = ["\n", "\r", "\t", ";", ","];
return str_replace($search, $replace, $value);
}
// 使用编码函数
$encoded = encode_cookie_value("Value;with,special\nchars");
setrawcookie('encoded_cookie', $encoded, time() + 3600, '/');
?>
setrawcookie() 必须在任何输出之前调用,否则会导致 "headers already sent" 错误。\n)、回车符(\r)或空字符(\0),这些字符会破坏 HTTP 头格式。;)、逗号(,)和等号(=)在 Cookie 值中有特殊含义,需要小心处理。setrawcookie() 时,你需要负责处理值的编码。确保值符合 HTTP Cookie 规范。| 实践 | 描述 |
|---|---|
| 验证输入 | 在存储到 Cookie 之前,验证数据的格式和内容。 |
| 避免敏感数据 | 不要在 Cookie 中存储敏感信息(如密码、密钥等)。 |
| 使用 HTTPS | 始终设置 $secure = true,确保 Cookie 仅通过加密连接传输。 |
| HttpOnly 标志 | 设置 $httponly = true,防止 JavaScript 访问 Cookie。 |
| SameSite 属性 | 在 PHP 7.3+ 中,使用 samesite 选项防止 CSRF 攻击。 |
| 清理特殊字符 | 移除或编码可能破坏 HTTP 头的字符(换行符、回车符等)。 |
| 大小限制 | 遵守浏览器对 Cookie 大小的限制(通常每个 Cookie 不超过 4KB)。 |
| 服务器端验证 | 不要信任 Cookie 中的数据,始终在服务器端进行验证。 |
| 问题 | 解决方案 |
|---|---|
| Cookie 值被截断 | 确保值中没有换行符或其他控制字符。检查浏览器 Cookie 大小限制。 |
| 特殊字符导致问题 | 手动编码特殊字符,或使用 setcookie() 让 PHP 自动处理。 |
| JSON 数据双重编码 | 使用 setrawcookie() 存储 JSON 字符串,避免 setcookie() 的自动编码。 |
| 二进制数据存储 | 先进行 Base64 编码,再使用 setrawcookie() 存储。 |
| "headers already sent" 错误 | 确保在输出任何内容之前调用 setrawcookie()。使用输出缓冲或检查文件编码。 |
| Cookie 读取不到 | Cookie 在当前请求中不可用。需要刷新页面或在下一次请求中读取。 |
| 浏览器兼容性问题 | 测试不同浏览器,避免使用边缘特性的字符或格式。 |