Если я хочу создать URL-адрес с помощью переменной, у меня есть два варианта кодирования строки. urlencode()
и rawurlencode()
.
Какие именно различия и что предпочтительнее?
Если я хочу создать URL-адрес с помощью переменной, у меня есть два варианта кодирования строки. urlencode()
и rawurlencode()
.
Какие именно различия и что предпочтительнее?
Это будет зависеть от вашей цели. Если совместимость с другими системами важна, то похоже, что rawurlencode - это то, что вам нужно. Единственным исключением являются устаревшие системы, которые ожидают, что строка запроса будет следовать стилю кодирования формы пробелов, закодированных как + вместо% 20 (в этом случае вам нужен urlencode).
rawurlencode следует за RFC 1738 до PHP 5.3.0 и RFC 3986 после него (см. http://us2.php.net/manual/en/function.rawurlencode.php)
Возвращает строку, в которой все не буквенно-цифровые символы, кроме -_. ~, Были заменены знаком процента (%), за которым следуют две шестнадцатеричные цифры. Это кодировка, описанная в »RFC 3986 для защиты буквенных символов от интерпретации как специальных разделителей URL-адресов и для защиты URL-адресов от искажения средствами передачи с преобразованием символов (например, в некоторых системах электронной почты).
Примечание относительно RFC 3986 и 1738. rawurlencode до php 5.3 кодировал символ тильды (~
) в соответствии с RFC 1738. Однако, начиная с PHP 5.3, rawurlencode следует RFC 3986, который не требует кодирования символов тильды.
urlencode кодирует пробелы как знаки плюса (а не как %20
, как в rawurlencode) (см. http://us2.php.net/manual/en/function.urlencode.php)
Возвращает строку, в которой все не буквенно-цифровые символы, кроме -_. были заменены знаком процента (%), за которым следуют две шестнадцатеричные цифры и пробелы, закодированные как знаки плюс (+). Он кодируется так же, как и отправленные данные из формы WWW, то есть так же, как в типе мультимедиа application / x-www-form-urlencoded. Это отличается от кодировки »RFC 3986 (см. Rawurlencode ()) тем, что по историческим причинам пробелы кодируются как знаки плюса (+).
Это соответствует определению application / x-www-form-urlencoded в RFC 1866.
Дополнительная литература:
Вы также можете увидеть обсуждение на http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode.
Также стоит обратить внимание на RFC 2396. RFC 2396 определяет допустимый синтаксис URI. Основная часть, которая нас интересует, взята из 3.4 Query Component:
В компоненте запроса символы
";", "/", "?", ":", "@",
зарезервированы.
"&", "=", "+", ",", and "$"
Как видите, +
- это зарезервированный символ в строке запроса, поэтому его необходимо закодировать в соответствии с RFC 3986 (как в rawurlencode).
Доказательство находится в исходном коде PHP.
Я расскажу вам, как самостоятельно узнавать подобные вещи в будущем в любое удобное для вас время. Потерпите меня, будет много исходного кода C, который вы можете просмотреть (я это объясняю). Если вы хотите освежить немного знаний о C, хорошее место для начала - наша вики SO.
Загрузите исходный код (или используйте http://lxr.php.net/, чтобы просмотреть его в Интернете), grep all файлы для имени функции, вы найдете что-то вроде этого:
PHP 5.3.6 (самый последний на момент написания) описывает две функции в их собственном коде C в файле url.c.
RawUrlEncode ()
PHP_FUNCTION(rawurlencode)
{
char *in_str, *out_str;
int in_str_len, out_str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
&in_str_len) == FAILURE) {
return;
}
out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
RETURN_STRINGL(out_str, out_str_len, 0);
}
UrlEncode ()
PHP_FUNCTION(urlencode)
{
char *in_str, *out_str;
int in_str_len, out_str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
&in_str_len) == FAILURE) {
return;
}
out_str = php_url_encode(in_str, in_str_len, &out_str_len);
RETURN_STRINGL(out_str, out_str_len, 0);
}
Хорошо, так что здесь другого?
По сути, они обе вызывают две разные внутренние функции соответственно: php_raw_url_encode и php_url_encode.
Так что ищите эти функции!
PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
{
register int x, y;
unsigned char *str;
str = (unsigned char *) safe_emalloc(3, len, 1);
for (x = 0, y = 0; len--; x++, y++) {
str[y] = (unsigned char) s[x];
#ifndef CHARSET_EBCDIC
if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
(str[y] < 'A' && str[y] > '9') ||
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
(str[y] > 'z' && str[y] != '~')) {
str[y++] = '%';
str[y++] = hexchars[(unsigned char) s[x] >> 4];
str[y] = hexchars[(unsigned char) s[x] & 15];
#else /*CHARSET_EBCDIC*/
if (!isalnum(str[y]) && strchr("_-.~", str[y]) != NULL) {
str[y++] = '%';
str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
#endif /*CHARSET_EBCDIC*/
}
}
str[y] = '\0';
if (new_length) {
*new_length = y;
}
return ((char *) str);
}
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 - это еще один набор символов, похожий на ASCII, но тотальный конкурент. PHP пытается справиться с обоими. Но в основном это означает, что байт EBCDIC 0x4c - это не L
в ASCII, это на самом деле <
. Я уверен, что вы видите здесь путаницу.
Обе эти функции управляют 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.
URLENCODE:
+
.isalnum(c)
), а также не является символом _
, -
или .
, тогда мы выводим знак %
в позицию 0 массива, выполняем поиск массива до массива hexchars
для поиска массива os_toascii
(массив из Apache, который переводит char в шестнадцатеричный код) для ключа c
(текущий символ), затем мы выполняем побитовый сдвиг вправо на 4, присваиваем это значение символу 1, а позиции 2 присваиваем то же самое поиск, за исключением того, что мы предварительно формируем логическое и проверяем, равно ли значение 15 (0xF), и возвращаем 1 в этом случае или 0 в противном случае. В конце концов, вы получите что-то закодированное._-.
символов, он выводит именно то, что есть.RAWURLENCODE:
Примечание. Многие программисты, вероятно, никогда не видели, чтобы цикл for выполнялся таким образом, это несколько хакерский и не стандартное соглашение, используемое с большинством циклов for, обратите внимание, оно присваивает x
и y
, проверяет выход при len
достигает 0 и увеличивает как x
, так и y
. Я знаю, это не то, что вы ожидаете, но это правильный код.
str
._-.
символов, и если это не так, мы выполняем почти то же назначение, что и с URLENCODE, где он выполняет поиск, однако мы увеличиваем по-разному, используя y++
, а не to[1]
, это потому что струны строятся по-разному, но в конце концов достигают одной и той же цели.\0
.Различия:
\0
строке, RawUrlEncode делает (это может быть спорным вопросом)В основном они повторяются по-разному, один присваивает знак + в случае ASCII 20.
URLENCODE:
0
, за исключением того, что он .
или -
, OR меньше A
, но больше char 9
, OR больше Z
и меньше, чем a
, но не _
. ИЛИ больше, чем z
(да, EBCDIC немного запутался при работе). Если он совпадает с любым из них, выполните поиск, аналогичный поиску в версии ASCII (это просто не требует поиска в os_toascii).RAWURLENCODE:
z
, оно исключает ~
из кодирования URL-адресов.\0
байт к строке перед возвратом.~
, чего не делает UrlEncode (это проблема, о которой сообщалось). Стоит отметить, что ASCII и EBCDIC 0x20 являются пробелами.+
, RawUrlEncode делает пробел в %20
с помощью поиска в массиве.Отказ от ответственности: я не прикасался к C в течение многих лет, и я не смотрел на EBCDIC действительно очень долгое время. Если я где-то ошибаюсь, дайте мне знать.
Исходя из всего этого, в большинстве случаев используется rawurlencode. Как вы видите в ответе Джонатана Фингланда, в большинстве случаев придерживайтесь его. Он имеет дело с современной схемой для компонентов URI, где urlencode работает по старинке, где + означает «пробел».
Если вы пытаетесь выполнить преобразование между старым форматом и новым форматом, убедитесь, что ваш код не дает сбоев и не превращает то, что является декодированным знаком +, в пробел путем случайного двойного кодирования или аналогичными сценариями «упс» вокруг этого пробел / 20% / + проблема.
Если вы работаете в более старой системе со старым программным обеспечением, которое не предпочитает новый формат, придерживайтесь urlencode, однако я считаю, что% 20 на самом деле будет обратно совместим, поскольку при старом стандарте% 20 работал, просто не был предпочтительнее. Попробуйте, если вы готовы поиграть, дайте нам знать, как это сработало для вас.
По сути, вам следует придерживаться raw, если только ваша система EBCDIC действительно вас не ненавидит. Большинство программистов никогда не столкнутся с EBCDIC ни в одной системе, выпущенной после 2000, может быть, даже 1990 года (это подталкивает, но все же, на мой взгляд, вероятно).
echo rawurlencode('http://www.google.com/index.html?id=asd asd');
дает
http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd%20asd
пока
echo urlencode('http://www.google.com/index.html?id=asd asd');
дает
http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd+asd
Разница в том, что asd%20asd
против asd+asd
urlencode отличается от RFC 1738 тем, что пробелы кодируются как +
вместо %20
Одна из практических причин выбрать одно из них - если вы собираетесь использовать результат в другой среде, например, в JavaScript.
В PHP urlencode('test 1')
возвращает 'test+1'
, а rawurlencode('test 1')
возвращает 'test%201'
в качестве результата.
Но если вам нужно «декодировать» это в JavaScript с помощью функции decodeURI (), тогда decodeURI("test+1")
даст вам "test+1"
, а decodeURI("test%201")
даст вам "test 1"
в качестве результата.
Другими словами, пробел (""), закодированный с помощью urlencode на плюс ("+") в PHP, не будет должным образом декодирован с помощью decodeURI в JavaScript.
В таких случаях следует использовать функцию PHP rawurlencode.
json_encode
и JSON.parse
для этой цели.
- person Fabrício Matté; 05.02.2013
Я считаю, что пробелы должны быть закодированы как:
%20
при использовании внутри компонента пути URL+
при использовании внутри компонента строки запроса URL или данных формы (см. 17.13.4 Типы содержимого форм)В следующем примере показано правильное использование rawurlencode
и _ 4_:
echo "http://example.com"
. "/category/" . rawurlencode("latest songs")
. "/search?q=" . urlencode("lady gaga");
Вывод:
http://example.com/category/latest%20songs/search?q=lady+gaga
Что произойдет, если вы закодируете компоненты пути и строки запроса наоборот? Для следующего примера:
http://example.com/category/latest+songs/search?q=lady%20gaga
latest+songs
вместо latest songs
q
будет содержать lady gaga
q
будет содержать lady gaga
Что еще он мог бы содержать в противном случае? Параметр запроса q
, похоже, имеет одно и то же значение, переданное в массив $_GET
, независимо от использования rawurlencode
или urlencode
в PHP 5.2+. Хотя urlencode
кодируется в формате application/x-www-form-urlencoded
, который используется по умолчанию для запросов GET, поэтому я придерживаюсь вашего подхода. +1
- person Fabrício Matté; 05.02.2013
+
, и %20
декодируются как пробелы при использовании в строках запроса.
- person Salman A; 05.02.2013
Единственная разница в том, как обрабатываются пробелы:
urlencode - на основе устаревшей реализации преобразует пробелы в +
rawurlencode - на основе RFC 1738 переводит пробелы в% 20
Причина разницы в том, что + зарезервирован и действителен (не закодирован) в URL-адресах.
Я действительно хотел бы увидеть несколько причин для выбора одного из них ... Я хочу иметь возможность просто выбрать один и использовать его вечно с наименьшими усилиями.
Честно говоря, у меня есть простая стратегия, которой я придерживаюсь при принятии этих решений, и я поделюсь с вами в надежде, что она может помочь.
Я думаю, это была спецификация HTTP / 1.1 RFC 2616, которая требовала "
Клиенты ДОЛЖНЫ быть терпимыми при анализе строки состояния, а серверы - терпимыми при анализе строки запроса.
Когда вы сталкиваетесь с подобными вопросами, лучшая стратегия - всегда потреблять как можно больше и производить то, что соответствует стандартам.
Поэтому я советую использовать rawurlencode
для создания строк в кодировке RFC 1738, соответствующих стандартам, и использовать urldecode
для обеспечения обратной совместимости и размещения всего, что вам может понадобиться.
Поверьте мне на слово, но давайте докажем, что ...
php > $url = <<<'EOD'
<<< > "Which, % of Alice's tasks saw $s @ earnings?"
<<< > EOD;
php > echo $url, PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > echo urlencode($url), PHP_EOL;
%22Which%2C+%25+of+Alice%27s+tasks+saw+%24s+%40+earnings%3F%22
php > echo rawurlencode($url), PHP_EOL;
%22Which%2C%20%25%20of%20Alice%27s%20tasks%20saw%20%24s%20%40%20earnings%3F%22
php > echo rawurldecode(urlencode($url)), PHP_EOL;
"Which,+%+of+Alice's+tasks+saw+$s+@+earnings?"
php > // oops that's not right???
php > echo urldecode(rawurlencode($url)), PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > // now that's more like it
Похоже, что PHP имел в виду именно это, хотя я никогда не встречал никого, кто отказывался бы от любого из двух форматов, я не могу придумать лучшую стратегию, которую можно было бы принять в качестве своей стратегии де-факто, не так ли?
nJoy!
Разница заключается в возвращаемых значениях, то есть:
Возвращает строку, в которой все не буквенно-цифровые символы, кроме -_. были заменены знаком процента (%), за которым следуют две шестнадцатеричные цифры и пробелы, закодированные как знаки плюс (+). Он кодируется так же, как и отправленные данные из формы WWW, то есть так же, как в типе мультимедиа application / x-www-form-urlencoded. Это отличается от кодировки »RFC 1738 (см. Rawurlencode ()) тем, что по историческим причинам пробелы кодируются как знаки плюса (+).
Возвращает строку, в которой все не буквенно-цифровые символы, кроме -_. были заменены знаком процента (%), за которым следуют две шестнадцатеричные цифры. Это кодировка, описанная в »RFC 1738 для защиты буквенных символов от интерпретации как специальных разделителей URL-адресов и для защиты URL-адресов от искажения средствами передачи с преобразованием символов (например, в некоторых системах электронной почты).
Эти два очень похожи, но последний (rawurlencode) заменит пробелы на '%' и двумя шестнадцатеричными цифрами, что подходит для кодирования паролей или чего-то подобного, где '+' не является, например:
echo '<a href="ftp://user:', rawurlencode('foo @+%/'),
'@ftp.example.com/x.txt">';
//Outputs <a href="ftp://user:foo%20%40%2B%25%[email protected]/x.txt">
urlencode: отличается от кодировки »RFC 1738 (см. rawurlencode ( )) в том смысле, что по историческим причинам пробелы кодируются как знаки плюс (+).
%20
vs. +
Самая большая причина, по которой я использовал rawurlencode()
в большинстве случаев, заключается в том, что urlencode
кодирует текстовые пространства как +
(знаки плюс), где rawurlencode
кодирует их как часто встречающиеся %20
:
echo urlencode("red shirt");
// red+shirt
echo rawurlencode("red shirt");
// red%20shirt
Я специально видел определенные конечные точки API, которые принимают закодированные текстовые запросы, ожидают увидеть %20
в качестве пробела и, как результат, терпят неудачу, если вместо этого используется знак плюса. Очевидно, что это будет отличаться между реализациями API, и ваш опыт может отличаться.
Я считаю, что urlencode предназначен для параметров запроса, а rawurlencode - для сегментов пути. В основном это связано с %20
для сегментов пути и +
для параметров запроса. См. Этот ответ, в котором говорится о пробелах: Когда кодировать пробел в плюс ( +) или% 20?
Однако %20
теперь работает и с параметрами запроса, поэтому rawurlencode всегда безопаснее. Однако знак плюса обычно используется там, где важны удобство редактирования и удобочитаемость параметров запроса.
Обратите внимание, что это означает, что rawurldecode
не декодирует +
в пробелы (http://au2.php.net/manual/en/function.rawurldecode.php). Вот почему $ _GET всегда автоматически передается через urldecode
, что означает, что +
и %20
оба декодируются в пробелы.
Если вы хотите, чтобы кодирование и декодирование между входами и выходами было согласованным, и вы выбрали всегда использовать +
, а не %20
для параметров запроса, то urlencode
подходит для параметров запроса (ключ и значение).
Вывод такой:
Сегменты пути - всегда используйте rawurlencode / rawurldecode
Параметры запроса - для декодирования всегда используйте urldecode (выполняется автоматически), для кодирования подходят как rawurlencode, так и urlencode, просто выберите один, который будет согласованным, особенно при сравнении URL-адресов.
simple * rawurlencode путь - путь - это часть перед знаком "?" - пробелы должны быть закодированы как% 20 * urlencode строка запроса - Строка запроса - это часть после "?" -пространства лучше кодируются как "+" = rawurlencode обычно более совместим
rawurlencode
. Вы редко встретите систему, которая задыхается, когда заданы пробелы, закодированные как%20
, в то время как системы, которые задыхаются от пробелов, закодированных как+
, более распространены. - person Anomie   schedule 04.08.2011