php - 为什么传递给 PHP 的 cookie 或数据字符串中缺少 "+"个字符,以及如何更正此问题

标签 php string cookies character-encoding connection-string

我认为我有一个完美的方案,在访问者页面中使用 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/

相关文章:

php - json_encode 是否足够的 XSS 保护?

javascript用字符串创建网格

php - 空变量的键等于空而不是错误

php - MySQL Concat 或 Fetch and Merge with PHP;哪个服务器便宜?

C# 字符串以特定字符结尾为整数

javascript - 使用 JavaScript 删除字符串中特定字符之后的所有内容

Java Servlet 不删除 cookie

JavaScript:set-cookie 和 response 是否处理原子操作?

javascript - 将数组携带到新页面

PHP curl 和 HTTPS