为啥 PHP 将 $_COOKIE 中的加号替换为空格?

Posted

技术标签:

【中文标题】为啥 PHP 将 $_COOKIE 中的加号替换为空格?【英文标题】:Why does PHP replace pluses with spaces in $_COOKIE?为什么 PHP 将 $_COOKIE 中的加号替换为空格? 【发布时间】:2013-01-01 06:22:34 【问题描述】:

所以根据我对 php 和 cookie 的理解,如果我使用 setcookie() 函数,那么我会得到一个自动 url 编码的 cookie。当我转到$_COOKIE 数组时,我应该取回cookie,自动对url 进行解码。问题是,当我查看 $_COOKIE 时,它似乎对 cookie 进行了两次解码。

假设我有一个cookie,其值为“Name|ID|Email”,例如:

乔|123|my+email@somewhere.com

这将被编码为:

Joe%7C123%7Cmy%2Bemail%40somewhere.com

注意加号是编码的,所以理论上我应该在解码后取回它。由于这是在$_COOKIE 中自动完成的,所以我应该找回我开始的内容。但相反,我要回来了:

乔|123|我的电子邮件@somewhere.com

注意加号所在的空间。如果我在 cookie 上运行一个额外的 urldecode(),这就是我所期望的。但我不是,所以我不知道为什么我会得到一个空格而不是一个加号。

另一个有趣的转折。页面上的刷新似乎会产生正确的输出。任何想法为什么它会这样?

仅供参考,为了设置初始 cookie,我使用 javascriptescape() 脚本来生成编码字符串。这可能是 javascript 和 PHP 之间的交接问题吗?

想法将不胜感激。

【问题讨论】:

你试过用 JavaScript 的 encodeURI() 函数代替转义吗? 如果您使用urlencode('+'),它将返回%2B,在urldecode('%2B') 之后应该返回+ - 请参阅this。如果您仍然有一些问题,您可以通过将 + 替换为诸如 > 之类的 email-address-forbidden-character 并在从 COOKIE 恢复数据后将 > 替换回+... 您可能在 JavaScript 中设置了稍微不正确的 cookie,导致 PHP 在第一次遇到它时“修复”它。看起来你的一些细节有误,所以我认为如果没有看到你的一些代码,我们就不会更进一步。 忽略我之前的评论encodeURI() 不会编码'+' 符号,你需要encodeURIComponent() - 抱歉:\ 没有实际代码,很难判断发生了什么。但毫无疑问,您正在解码两次,您需要对其进行追踪和删除。这可能会导致除此之外的其他问题。例如 %2540 不应解码为 %40 而不是 @。顺便说一句,我当然希望您不要使用该电子邮件地址来识别用户,而无需对其进行加密并使用 HMAC。否则,你会遇到更严重的问题。请参阅j.mp/learn-state-manipulation 上有关黑客 cookie 的部分 【参考方案1】:

如果不想自动对cookie进行编码,可以使用setrawcookie函数。 这个函数的例外是,你不能使用这些字符: (,; \t\r\n\013\014) :

setrawcookie("NAME","Joe|123|my+email@somewhere.com");  

# Output in browser:   
Joe|123|my+email@somewhere.com 

# Output in PHP `echo $_COOKIE['NAME']`:  
Joe|123|my email@somewhere.com

用 PHP 5.3 测试

setcookie("NAME","Joe|123|my+email@somewhere.com");

# Output in browser:  
Joe%7C123%7Cmy%2Bemail%40somewhere.com  

# Output in PHP echo $_COOKIE['NAME']`:  
Joe|123|my+email@somewhere.com  

现在:作为替代方式,您可以使用setcookie()和rawurldecode()对其进行解码:

 echo rawurldecode($_COOKIE['NAME'])

【讨论】:

【参考方案2】:

首先,PHP 将始终在 JavaScript 之前运行 - 它是服务器端而不是客户端,因此您使用 JavaScript 设置的 cookie 实际上在您刷新页面之前对 PHP 不可用(因此出现了这个问题)。

下一个 JavaScript 有不同的方式来编码字符串;只有一个会自动使用 PHP。

所以:

document.cookie = "testuser=" + "Joe|123|my+email@somewhere.com";
// Joe|123|my email@somewhere.com (when decoded by PHP)

document.cookie = "testuser=" + escape("Joe|123|my+email@somewhere.com");
// Joe|123|my email@somewhere.com (when decoded by PHP)

document.cookie = "testuser=" + encodeURI("Joe|123|my+email@somewhere.com");
// Joe|123|my email@somewhere.com (when decoded by PHP)

document.cookie = "testuser=" + encodeURIComponent("Joe|123|my+email@somewhere.com");
// Joe|123|my+email@somewhere.com 

所以,为了测试,试试这个(记住你需要刷新页面才能看到 cookie 值):

<html>
<head>
    <title>Cookie Juggling</title>
    <script type="text/javascript">
        document.cookie = "testuser=" + encodeURIComponent("Joe|123|my+email@somewhere.com");
    </script>
</head>

<body>
    <div><?php echo !empty($_COOKIE['testuser']) ? $_COOKIE['testuser'] : "Cookie not set yet"; ?></div>
</body>
</html>

【讨论】:

【参考方案3】:

值得注意的是,“%20”和“+”都是空格字符的有效编码。根据URL encoding 上的***文章(强调添加):

当已经输入 HTML 表单的数据被提交时,表单 字段名称和值被编码并以 HTTP 形式发送到服务器 使用 GET 或 POST 方法请求消息,或者历史上通过电子邮件。 默认使用的编码是基于一个非常早期的版本 通用 URI 百分比编码规则,有一些修改 例如换行规范化和用“+”替换空格而不是 “%20”。以这种方式编码的数据的 MIME 类型是 application/x-www-form-urlencoded,目前已定义(仍 以非常过时的方式)在 HTML 和 XForms 规范中。

更具体地与 PHP 和 JavaScript 相关,请参阅此问题的最佳答案:

When to encode space to plus (+) or %20?

【讨论】:

以上是关于为啥 PHP 将 $_COOKIE 中的加号替换为空格?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要一个句号,“。”而不是加号“+”,用于 PHP 中的字符串连接?

PHP Json_encode 将空格更改为加号 +

php base64处理

js将所有的空格替换成加号(+)

URL中的空格、加号究竟应该使用何种方式编码

PHP使用urlencode对中文编码时空格加号的问题