PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
{
register unsigned char c;
unsigned char *to, *start;
unsigned char const *from, *end;
from = (unsigned char *)s;
end = (unsigned char *)s + len;
start = to = (unsigned char *) safe_emalloc(3, len, 1);
while (from < end) {
c = *from++;
if (c == ' ') {
*to++ = '+';
#ifndef CHARSET_EBCDIC
} else if ((c < '0' && c != '-' && c != '.') ||
(c < 'A' && c > '9') ||
(c > 'Z' && c < 'a' && c != '_') ||
(c > 'z')) {
to[0] = '%';
to[1] = hexchars[c >> 4];
to[2] = hexchars[c & 15];
to += 3;
#else /*CHARSET_EBCDIC*/
} else if (!isalnum(c) && strchr("_-.", c) == NULL) {
/* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
to[0] = '%';
to[1] = hexchars[os_toascii[c] >> 4];
to[2] = hexchars[os_toascii[c] & 15];
to += 3;
#endif /*CHARSET_EBCDIC*/
} else {
*to++ = c;
}
}
*to = 0;
if (new_length) {
*new_length = to - start;
}
return (char *) start;
}
我前进之前的一点知识,EBCDIC is another character set,类似于ASCII,但总是竞争对手 . PHP试图解决这两个问题 . 但基本上,这意味着字节EBCDIC 0x4c字节不是ASCII中的 L ,它实际上是 < . 我相信你会看到这里的混乱 .
如果Web服务器已定义EBCDIC,则这两个函数都管理EBCDIC .
另外,它们都使用字符数组(想想字符串类型) hexchars 查找来获取一些值,数组描述如下:
/* rfc1738:
...The characters ";",
"/", "?", ":", "@", "=" and "&" are the characters which may be
reserved for special meaning within a scheme...
...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL...
For added safety, we only leave -_. unencoded.
*/
static unsigned char hexchars[] = "0123456789ABCDEF";
除此之外,功能确实不同,我将用ASCII和EBCDIC解释它们 .
ASCII的差异:
URLENCODE:
计算输入字符串的开始/结束长度,分配内存
走一个while循环,递增直到我们到达字符串的末尾
grab 现在的角色
如果字符等于ASCII字符0x20(即"space"),请在输出字符串中添加 + 符号 .
如果它's not a space, and it'也不是字母数字( isalnum(c) ),也不是和 _ , - 或 . 字符,那么我们输出一个 % 符号到数组位置0,做一个数组查找 hexchars 数组进行查找对于 os_toascii 数组(从Apache that translates字符到十六进制代码的数组),对于 c (当前字符)的键,我们然后按位向右移位4,将该值分配给字符1,到位置2我们分配相同的查找,除了我们预先形成一个逻辑并查看该值是否为15(0xF),并在这种情况下返回1,否则返回0 . 最后,你最终会得到编码的东西 .
如果它最终是's not a space, it'的字母数字或其中一个 _-. 字符,它会输出它的确切含义 .
RAWURLENCODE:
为字符串分配内存
根据函数调用中提供的长度对其进行迭代(不像URLENCODE那样计算) .
Note: 许多程序员可能从未见过以这种方式进行for循环迭代,这有点像hackish而不是大多数for循环使用的标准约定,注意,它指定 x 和 y ,检查退出 len 达到0,并递增 x 和 y . 我知道,它是's not what you'期待,但它是有效的代码 .
它检查当前char是否是 0 之前的char,除了 . 或 - , OR 小于 A 但大于char 9 , OR 大于 Z 且小于 a 但不是 _ . OR 大于 z (是的,EBCDIC有点搞砸了) . 如果它匹配其中任何一个,请执行与ASCII版本中相似的查找(它不需要在os_toascii中查找) .
RAWURLENCODE:
与ASCII相同的迭代设置
与URL编码的EBCDIC版本中描述的相同,但如果它大于 z ,则从URL编码中排除 ~ .
与ASCII RawUrlEncode相同的赋值
仍然在返回之前将 \0 字节附加到字符串 .
总结
两者都使用相同的十六进制查找表
URIEncode不会终止带有\ 0的字符串,raw会终止 .
如果你建议使用RawUrlEncode,因为它管理的是UrlEncode没有的 ~ (this is a reported issue) . 值得注意的是,ASCII和EBCDIC 0x20都是空格 .
11 回答
这取决于你的目的 . 如果与其他系统的互操作性很重要,那么看来rawurlencode就是最佳选择 . 一个例外是遗留系统,它期望查询字符串遵循编码为空格式的编码样式,而不是%20(在这种情况下,您需要urlencode) .
rawurlencode 之后是PHP 5.3.0之前的RFC 1738和之后的RFC 3986(参见http://us2.php.net/manual/en/function.rawurlencode.php)
关于RFC 3986 vs 1738的注释 . 在php 5.3之前的rawurlencode根据RFC 1738编码了波形符(
~
) . 但是,从PHP 5.3开始,rawurlencode遵循RFC 3986,不需要编码波形符 .urlencode 将空格编码为加号(而不是像rawurlencode中那样
%20
)(参见http://us2.php.net/manual/en/function.urlencode.php)这对应于RFC 1866中application / x-www-form-urlencoded的定义 .
Additional Reading:
您可能还希望在http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode看到讨论 .
另外,RFC 2396值得一看 . RFC 2396定义了有效的URI语法 . 我们感兴趣的主要部分来自3.4查询组件:
如您所见,
+
是查询字符串中的保留字符,因此需要根据RFC 3986进行编码(如rawurlencode中所示) .证明是PHP的源代码 .
我'll take you through a quick process of how to find out this sort of thing on your own in the future any time you want. Bear with me, there'将会有很多你可以浏览的C源代码(我解释一下) . If you want to brush up on some C, a good place to start is our SO wiki .
下载源代码(或使用http://lxr.php.net/在线浏览),grep函数名称的所有文件,你会发现如下内容:
PHP 5.3.6(最近编写本文时)在文件url.c中描述了本机C代码中的两个函数 .
RawUrlEncode()
UrlEncode()
好的,那么这里有什么不同?
它们本质上分别调用两个不同的内部函数: php_raw_url_encode 和 php_url_encode
所以去寻找那些功能吧!
让我们看看php_raw_url_encode
当然,php_url_encode:
我前进之前的一点知识,EBCDIC is another character set,类似于ASCII,但总是竞争对手 . PHP试图解决这两个问题 . 但基本上,这意味着字节EBCDIC 0x4c字节不是ASCII中的
L
,它实际上是<
. 我相信你会看到这里的混乱 .如果Web服务器已定义EBCDIC,则这两个函数都管理EBCDIC .
另外,它们都使用字符数组(想想字符串类型)
hexchars
查找来获取一些值,数组描述如下:除此之外,功能确实不同,我将用ASCII和EBCDIC解释它们 .
ASCII的差异:
URLENCODE:
计算输入字符串的开始/结束长度,分配内存
走一个while循环,递增直到我们到达字符串的末尾
grab 现在的角色
如果字符等于ASCII字符0x20(即"space"),请在输出字符串中添加
+
符号 .如果它's not a space, and it'也不是字母数字(
isalnum(c)
),也不是和_
,-
或.
字符,那么我们输出一个%
符号到数组位置0,做一个数组查找hexchars
数组进行查找对于os_toascii
数组(从Apache that translates字符到十六进制代码的数组),对于c
(当前字符)的键,我们然后按位向右移位4,将该值分配给字符1,到位置2我们分配相同的查找,除了我们预先形成一个逻辑并查看该值是否为15(0xF),并在这种情况下返回1,否则返回0 . 最后,你最终会得到编码的东西 .如果它最终是's not a space, it'的字母数字或其中一个
_-.
字符,它会输出它的确切含义 .RAWURLENCODE:
为字符串分配内存
根据函数调用中提供的长度对其进行迭代(不像URLENCODE那样计算) .
Note: 许多程序员可能从未见过以这种方式进行for循环迭代,这有点像hackish而不是大多数for循环使用的标准约定,注意,它指定
x
和y
,检查退出len
达到0,并递增x
和y
. 我知道,它是's not what you'期待,但它是有效的代码 .将当前字符分配给
str
中的匹配字符位置 .它检查当前字符是否为字母数字,或
_-.
字符之一,如果不是,我们执行与URLENCODE几乎相同的分配,它会预先形成查找,但是,我们使用y++
而不是to[1]
进行不同的增量,这是因为琴弦以不同的方式构建,但无论如何都达到了相同的目标 .当循环's done and the length'消失时,它实际上终止了字符串,分配
\0
字节 .它返回编码的字符串 .
Differences:
UrlEncode检查空间,分配符号,RawURLEncode没有 .
UrlEncode没有为字符串分配
\0
字节,RawUrlEncode确实如此(这可能是一个有争议的问题)他们迭代不同,一个人可能容易出现格式错误的字符串溢出,我是 merely suggesting 这个,我实际调查了 haven't .
它们基本上以不同的方式迭代,一个在ASCII 20事件中指定一个符号 .
EBCDIC的差异:
URLENCODE:
与ASCII相同的迭代设置
仍然将"space"字符翻译成符号 . 注意 - 我认为这需要在EBCDIC中编译,否则你最终会遇到错误?有人可以编辑并确认吗?
它检查当前char是否是
0
之前的char,除了.
或-
, OR 小于A
但大于char9
, OR 大于Z
且小于a
但不是_
. OR 大于z
(是的,EBCDIC有点搞砸了) . 如果它匹配其中任何一个,请执行与ASCII版本中相似的查找(它不需要在os_toascii中查找) .RAWURLENCODE:
与ASCII相同的迭代设置
与URL编码的EBCDIC版本中描述的相同,但如果它大于
z
,则从URL编码中排除~
.与ASCII RawUrlEncode相同的赋值
仍然在返回之前将
\0
字节附加到字符串 .总结
两者都使用相同的十六进制查找表
URIEncode不会终止带有\ 0的字符串,raw会终止 .
如果你建议使用RawUrlEncode,因为它管理的是UrlEncode没有的
~
(this is a reported issue) . 值得注意的是,ASCII和EBCDIC 0x20都是空格 .他们以不同的方式迭代,一个可能更快,一个可能倾向于内存或基于字符串的攻击 .
URIEncode在
+
中创建一个空格,RawUrlEncode通过数组查找在%20
中创建一个空格 .Disclaimer: 在很长一段时间里我没有看过EBCDIC . 如果我在某处错了,请告诉我 .
建议的实施
基于所有这些,rawurlencode是大多数时间的方式 . 正如你在Jonathan Fingland的回答中看到的那样,在大多数情况下坚持使用它 . 它涉及URI组件的现代方案,其中urlencode以旧学校的方式处理事物,其中意味着“空间” .
如果您尝试在旧格式和新格式之间进行转换,请确保您的代码没有搞砸,并通过意外双重编码或类似的“oops”场景将这些解码符号转换为空格/ 20%/问题 .
如果您正在使用较旧的软件而不喜欢新格式的旧系统,请坚持使用urlencode,但是,我认为%20实际上是向后兼容的,因为根据旧标准%20工作,只是不是首选 . 如果你想要玩,请试一试,让我们知道它是如何为你工作的 .
基本上,你应该坚持使用raw,除非你的EBCDIC系统真的很讨厌你 . 大多数程序员永远不会在2000年以后甚至1990年之后的任何系统上遇到EBCDIC(这是推动,但仍然可能在我看来) .
产量
而
产量
不同的是
asd%20asd
与asd+asd
urlencode与RFC 1738的不同之处在于将空格编码为
+
而不是%20
选择其中一个的一个实际原因是,如果您要在另一个环境中使用结果,例如JavaScript .
在PHP中
urlencode('test 1')
返回'test+1'
而rawurlencode('test 1')
返回'test%201'
作为结果 .但是如果你需要"decode"这在JavaScript中使用 decodeURI() 函数,那么
decodeURI("test+1")
会给你"test+1"
而decodeURI("test%201")
会给你"test 1"
作为结果 .换句话说,PHP中由 urlencode 编码的空间(" ")到_(#600554_)将无法由 decodeURI 正确解码 .
在这种情况下,应使用 rawurlencode PHP函数 .
我相信空间必须编码如:
在URL路径组件中使用
%20
+
在URL查询字符串组件或表单数据中使用时(请参阅17.13.4 Form content types)以下示例显示正确使用rawurlencode和urlencode:
输出:
如果您以相反的方式编码路径和查询字符串组件会发生什么?对于以下示例:
网络服务器将查找目录
latest+songs
而不是latest songs
查询字符串参数
q
将包含lady gaga
区别在于返回值,即:
urlencode():
rawurlencode():
两者非常相似,但后者(rawurlencode)将用'%'和两个十六进制数字替换空格,这适用于编码密码等,其中''不是例如:
1.究竟有什么区别和
唯一的区别在于处理空间的方式:
urlencode - 基于遗留实现将空格转换为
rawurlencode - 基于RFC 1738将空格转换为%20
造成这种差异的原因是因为在网址中保留并且有效(未编码) .
2.哪个更受欢迎?
很公平,我做出这些决定时会遵循一个简单的策略,我将与您分享,希望它可以提供帮助 .
我认为是HTTP / 1.1规范RFC 2616,它要求 "Tolerant applications"
When faced with questions like these the best strategy is always to consume as much as possible and produce what is standards compliant.
所以我的建议是使用
rawurlencode
生成符合标准的RFC 1738编码字符串,并使用urldecode
向后兼容并容纳您可能遇到的任何内容 .现在你可以接受我的话,但我们要证明它......
虽然我从来没有遇到任何人拒绝这两种格式中的任何一种,但我认为没有人会想到采用更好的策略来作为你的事实策略,你呢?
的nJoy!
我相信urlencode用于查询参数,而rawurlencode用于路径段 . 这主要是由于路径段的
%20
与查询参数的+
. 看到这个答案,讨论空格:When to encode space to plus (+) or %20?但是
%20
现在也适用于查询参数,这就是rawurlencode总是更安全的原因 . 但是,在编辑的用户体验和查询参数的可读性很重要的情况下,往往会使用加号 .请注意,这意味着
rawurldecode
不会将+
解码为空格(http://au2.php.net/manual/en/function.rawurldecode.php) . 这就是为什么$ _GET总是自动通过urldecode
,这意味着+
和%20
都被解码为空格 .如果您希望编码和解码在输入和输出之间保持一致,并且您已选择始终使用
+
而不是%20
作为查询参数,则urlencode
适用于查询参数(键和值) .结论是:
路径段 - 始终使用rawurlencode / rawurldecode
查询参数 - 用于解码总是使用urldecode(自动完成),对于编码,rawurlencode或urlencode都很好,只需选择一个是一致的,特别是在比较URL时 .
空格编码为%20 vs.
在大多数情况下,我看到使用
rawurlencode()
的最大原因是因为urlencode
将文本空间编码为+
(加号),其中rawurlencode
将它们编码为常见的%20
:我已经特别看到某些接受编码文本查询的API endpoints 期望查看空间的
%20
,因此如果使用加号则会失败 . 显然,这与API实现有所不同,您的里程可能会有所不同 .简单* rawurlencode路径 - 路径是“?”之前的部分 - 空格必须编码为%20 *urlencode查询字符串 - 查询字符串是“?”之后的部分 - 空格被更好地编码为“”= rawurlencode通常更兼容