PHP setrawcookie() 函数

setrawcookie() 函数用于发送一个未经 URL 编码的 Cookie。

setcookie() 函数不同,setrawcookie() 不会对 Cookie 值进行自动 URL 编码。这在你需要存储原始二进制数据或已经编码过的数据时非常有用。

重要:setrawcookie() 函数必须在任何实际输出之前调用,包括 HTML 标签、空格、换行符或 PHP 输出。否则会导致 "headers already sent" 错误。
提示:由于 Cookie 值不会自动编码,你需要确保值中不包含可能破坏 HTTP 头格式的字符(如换行符)。特殊字符可能需要手动编码。

语法

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 时间戳表示。
  • 0:会话 Cookie,浏览器关闭时过期
  • time() + 3600:1 小时后过期
  • time() + (86400 * 30):30 天后过期
$path string 可选的。Cookie 有效的服务器路径。
  • /:整个域名下都有效
  • /admin/:仅在 /admin/ 目录下有效
  • 空字符串:当前目录及其子目录有效
$domain string 可选的。Cookie 有效的域名。
  • example.com:主域名和所有子域名有效
  • www.example.com:仅 www 子域名有效
  • .example.com:主域名和所有子域名有效
$secure bool 可选的。如果设置为 true,Cookie 仅通过 HTTPS 连接传输。
$httponly bool 可选的。如果设置为 true,Cookie 只能通过 HTTP 协议访问,JavaScript 无法访问。
$options (PHP 7.3+) array 可选的。包含上述所有参数(除 $name 和 $value)的关联数组。
  • expires - 过期时间
  • path - 路径
  • domain - 域名
  • secure - 仅 HTTPS
  • httponly - 仅 HTTP 访问
  • samesite - SameSite 属性

返回值

返回值 描述
true 如果成功设置 Cookie 头信息。这并不意味着用户浏览器接受了 Cookie。
false 如果设置失败。通常是因为:
  • 输出已经发送("headers already sent" 错误)
  • 参数格式不正确
  • 值中包含非法字符

setrawcookie() 与 setcookie() 的区别

特性 setrawcookie() setcookie()
URL 编码 不自动编码
值以原始形式发送
自动编码
值自动进行 URL 编码
特殊字符处理 需要手动处理特殊字符 自动处理特殊字符
二进制数据 适合存储二进制或已编码数据 需要先编码再存储
JSON 数据 直接存储 JSON 字符串 JSON 中的特殊字符会被编码
安全性 需要确保值中不包含破坏 HTTP 头的字符 更安全,自动处理编码问题
使用场景 存储已编码数据、二进制数据、严格控制格式的数据 存储普通文本、表单数据、大多数通用场景

示例

示例 1:基本使用 - 设置原始 Cookie

设置一个未经 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";
?>

示例 2:存储 JSON 数据

使用 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);
}
?>

示例 3:存储二进制数据(Base64 编码)

存储经过 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, '/');
?>

示例 4:手动编码处理

当需要控制编码时,手动处理 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 名称是大小写敏感的。在读取时需要使用与设置时完全相同的名称。
  • 特殊字符:分号(;)、逗号(,)和等号(=)在 Cookie 值中有特殊含义,需要小心处理。
  • 编码责任:使用 setrawcookie() 时,你需要负责处理值的编码。确保值符合 HTTP Cookie 规范。
  • 安全性:原始 Cookie 值可能包含恶意内容。在服务器端读取时应进行验证和过滤。
  • 浏览器兼容性:某些旧浏览器可能对 Cookie 值有额外的限制。测试你的目标浏览器以确保兼容性。
  • 调试困难:由于值不进行编码,调试 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 在当前请求中不可用。需要刷新页面或在下一次请求中读取。
浏览器兼容性问题 测试不同浏览器,避免使用边缘特性的字符或格式。

相关函数