我认为我有一个完美的方案,在访问者页面中使用 cookie 的 Base64 编码数据来识别访问者。 (实际上cookie代表RC4编码,用base64重新处理以产生“cookie安全”结果。由于base 64输出的字符在任何浏览器中对于cookie来说都是非法的,所以我相信这不会造成问题。我进一步希望通过 $_COOKIE 数组从 PHP 脚本检查 cookie。一切似乎都很顺利,直到特定的 cookie 值最终被 base64 编码为...
9xu3EhM5+6duW4feCL4aHuxOceo=
向我的浏览器写入或读取此 cookie 值绝对没有问题。如果我使用 javascript 创建它,然后使用浏览器的隐私选项检查它,它没有损坏。如果我通过 javascript 读取 cookie 并将其显示在alert() 或控制台中,它也没有损坏。但是当我从 PHP $_COOKIE 数组中“读取”cookie 时,我得到的结果是......
9xu3EhM5 6duW4feCL4aHuxOceo=
如果重要的话,这是 PHP 5.6。为什么缺少“+”符号?遗憾的是,问题不仅仅限于 $_COOKIE 数组!即使编写一个简单的 PHP 程序来响应我发送的内容(通过 GET 请求),我仍然看到响应中缺少“+”号。
如果这是与字符编码相关的问题,我不知道如何解决。即使我只是将 PHP 脚本 URL 插入浏览器的地址栏(其中没有事件页面设置任何字符编码),“+”符号也会在脚本路径中丢失。我还验证了一个简单的脚本,除了用硬编码的“未损坏”字符串进行响应外,什么也不做,效果很好。
很明显,问题仅限于从浏览器到 PHP 的数据传递。即使我可以想出一些疯狂的方案来补偿手动传递的字符串(例如通过 POST 请求),我也看不到任何方法来控制从 $_COOKIE 数组中提取数据时 PHP 脚本所看到的内容。/p>
我能做什么?我真的一直指望脚本能够完成这个看似简单的任务。
---编辑----------------
尽管我发现其他人提示这个神秘的“+”字符在发帖后丢失,但我没有看到简单的解决方案,因此决定实现我自己的解决方案。因为我一直在我的 PHP 脚本中完成所有的 Base64(编码和解码),并且由于我的代码是必须创建、存储和恢复这些字符串的唯一位置,所以我决定运行所有 Base64 编码在使用它存储 cookie 之前,请先通过此例程(如下)读取字符串。同样,我将在对其进行 Base-64 解码之前将获得的每个 cookie(例如,通过 $_COOKIE 数组)传递给它。
// from browser to PHP. substitute troublesome chars with
// other cookie safe chars, or vis-versa.
function fix64($inp) {
$out =$inp;
for($i = 0; $i < strlen($inp); $i++) {
$c = $inp[$i];
switch ($c) {
case '+': $c = '*'; break; // definitly won't transfer!
case '*': $c = '+'; break;
case '=': $c = ':'; break; // = symbol seems like a bad idea
case ':': $c = '='; break;
case '/': $c = '_'; break; // no good for dir name!!!
case '_': $c= '/'; break;
default: continue;
}
$out[$i] = $c;
}
return $out;
}
我只是用其他“cookie安全”字符替换“+”(我也决定用“=”),然后将编码值返回到页面,用作cookie。
编辑----- 我添加并更改了上面的一些内容,还删除/替换了“/”字符,这对于 $_COOKIE 数组来说不是问题,但如果例如您想写入一个文件或创建一个文件,那么它是一个麻烦的字符与 cookie 同名的目录。
请注意,正在处理的字符串的长度不会改变。当相同的(或网站上的另一个页面)再次运行我的 PHP 脚本,并且我恢复 cookie 时,我可以通过我创建的相同的 fix64() 调用将其传回,知道从那里我可以像正常的 base64 一样解码它.
我没有回答我自己的问题,因为我希望有一些简单的“官方”PHP 设置我可以调用来改变这种行为,并且我仍然希望这样的事情存在。但就我而言,就目前而言,这是一个合理的方法,如果有一天我需要的话,可以很容易地逆转。
最佳答案
setcookie()自 PHP/4 起就存在并生成 URL 编码值:
setcookie('a', '9xu3EhM5+6duW4feCL4aHuxOceo=');
Set-Cookie: a=9xu3EhM5%2B6duW4feCL4aHuxOceo%3D
因此,$_COOKIE
对值进行 URL 解码:
Cookie: a=9xu3EhM5%2B6duW4feCL4aHuxOceo%3D
array(1) {
["a"]=>
string(28) "9xu3EhM5+6duW4feCL4aHuxOceo="
}
从 PHP/5 开始,还有 setrawcookie()唯一的目的是不对值进行 URL 编码:
setrawcookie('b', '9xu3EhM5+6duW4feCL4aHuxOceo=');
Set-Cookie: b=9xu3EhM5+6duW4feCL4aHuxOceo=
但是 $_COOKIE
仍然假设 URL 编码输入和内容中断(+
是 U-0020 'SPACE' 的过时编码,又名旧空格):
Cookie: b=9xu3EhM5+6duW4feCL4aHuxOceo=
array(1) {
["b"]=>
string(28) "9xu3EhM5 6duW4feCL4aHuxOceo="
}
有趣的是,我找不到 setrawcookie()
的对应项。这让你不得不编写自己的解析器:-! $_SERVER['HTTP_COOKIE']
包含 HTTP header 的原始值,它是一个以分号分隔的列表,例如:
a=9xu3EhM5%2B6duW4feCL4aHuxOceo%3D; b=9xu3EhM5+6duW4feCL4aHuxOceo=
例如,Slim 微框架有 Cookies::parseHeader()方法来做到这一点(不知道为什么,因为他们 urldecode()
无论如何):
public static function parseHeader($header)
{
if (is_array($header) === true) {
$header = isset($header[0]) ? $header[0] : '';
}
if (is_string($header) === false) {
throw new InvalidArgumentException('Cannot parse Cookie data. Header value must be a string.');
}
$header = rtrim($header, "\r\n");
$pieces = preg_split('@[;]\s*@', $header);
$cookies = [];
foreach ($pieces as $cookie) {
$cookie = explode('=', $cookie, 2);
if (count($cookie) === 2) {
$key = urldecode($cookie[0]);
$value = urldecode($cookie[1]);
if (!isset($cookies[$key])) {
$cookies[$key] = $value;
}
}
}
return $cookies;
}
我想你可以使用这段代码并跳过解码部分。
关于php - 为什么传递给 PHP 的 cookie 或数据字符串中缺少 "+"个字符,以及如何更正此问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56861080/