urlencode () символ 'звездочка' (звезда?)

Я тестирую PHP urlencode() сравнению с Java java.net.URLEncoder.encode() .

Ява

 String all = ""; for (int i = 32; i < 256; ++i) { all += (char) i; } System.out.println("All characters: -||" + all + "||-"); try { System.out.println("Encoded characters: -||" + URLEncoder.encode(all, "utf8") + "||-"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } 

PHP

 $all = ""; for($i = 32; $i < 256; ++$i) { $all = $all.chr($i); } echo($all.PHP_EOL); echo(urlencode(utf8_encode($all)).PHP_EOL); 

Все символы, похоже, кодируются одинаково с обеими функциями, за исключением символа «звездочки», который не закодирован Java, и переводится на% 2A с помощью PHP. Какое поведение должно быть «правильным», если оно есть?

Примечание. Я тоже попытался с rawurlencode() – не повезло.

Это нормально иметь * в URL-адресе (но это также нормально иметь его в его закодированной форме).

RFC1738: Единые указатели ресурсов (URL) указывают следующее:

Зарезервированный:

[…]

Обычно URL-адрес имеет ту же интерпретацию, когда октет представлен символом и когда он кодируется. Однако это не относится к зарезервированным символам: кодировка символа, зарезервированного для конкретной схемы, может изменить семантику URL-адреса.

Таким образом, только буквенно-цифровые символы, специальные символы "$-_.+!*'()," И зарезервированные символы, используемые для их зарезервированных целей, могут использоваться в незашифрованном URL-адресе.

С другой стороны, символы, которые не должны быть закодированы (в том числе буквенно-цифровые), могут быть закодированы в определенной части схемы URL-адреса, если они не используются для зарезервированных целей.

Википедия предполагает, что * является зарезервированным символом, когда речь заходит о URI, и что он должен быть закодирован, если не используется для зарезервированной цели. Согласно RFC3986 , страницы 12-13:

URI включают компоненты и подкомпоненты, которые ограничены символами в «зарезервированном» наборе. Эти символы называются «зарезервированными», потому что они могут (или не могут) быть определены как разделители общим синтаксисом, каждым синтаксисом конкретной схемы или специфичным для реализации синтаксисом алгоритма разыменования URI. Если данные для компонента URI будут конфликтовать с целью зарезервированного символа в качестве разделителя, тогда конфликтующие данные должны быть закодированы до кодирования URI.

  reserved = gen-delims / sub-delims gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" 

(Тот факт, что URL-адрес RFC по- прежнему позволяет символу * не кодироваться, – это то, что у него нет зарезервированных URL-адресов i и, следовательно, не нужно кодировать. Так что вам нужно его закодировать или нет, зависит от какой URI вы создаете.)

Javadoc URLEncoder относится к спецификации HTML:

Этот класс содержит статические методы для преобразования String в формат MIME application/x-www-form-urlencoded . Для получения дополнительной информации о кодировании HTML-формы обратитесь к спецификации HTML.

HTML4 довольно неясен в отношении этого вопроса и относится к RFC1738 , который цитируется aioobe:

Управляющие имена и значения экранируются. Символы пробела заменяются на «+», а затем зарезервированные символы экранируются, как описано в [RFC1738], раздел 2.2: Номера буквенно-цифровых символов заменяются на «% HH», знак процента и две шестнадцатеричные цифры, представляющие код ASCII персонаж. Разрывы строк представлены как пары «CR LF» (т.е. «% 0D% 0A»).

Однако HTML5 прямо утверждает, что * не следует кодировать:

  • Если символ не находится в диапазоне U + 0020, U + 002A , U + 002D, U + 002E, U + 0030 до U + 0039, U + 0041 – U + 005A, U + 005F, U + 0061 – U + 007A
    Замените символ строкой, сформированной следующим образом:
  • В противном случае
    Оставьте символ как есть.