为啥 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,我使用 javascript 和 escape()
脚本来生成编码字符串。这可能是 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 中的加号替换为空格?的主要内容,如果未能解决你的问题,请参考以下文章