чрезмерное urlencoding функции http_build_query

Почему при построении строки запроса с http_build_query функции http_build_query она ссылается на квадратные скобки [] вне значений и как избавиться от нее?

 $query = array("var" => array("foo" => "value", "bar" => "encodedBracket[")); $queryString = http_build_query($query, "", "&"); var_dump($queryString); var_dump("urldecoded: " . urldecode($queryString)); 

выходы:

 var%5Bfoo%5D=value&var%5Bbar%5D=encodedBracket%5B urldecoded: var[foo]=value&var[bar]=encodedBracket[ 

Функция правильно urlencoded a [ в encodedBracket[ в первой строке вывода, но в чем причина кодирования квадратных скобок в var[foo]= и var[bar]= ? Как вы можете видеть, urldecoding строки также декодировал зарезервированные символы в значениях, encodedBracket%5B должен был оставаться таким, как если бы строка запроса была правильной и не стала encodedBracket[ .

Согласно разделу 2.2 Зарезервированные символы унифицированного идентификатора ресурса (URI): общий синтаксис

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

reserved = gen-delims / sub-delims

gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"

sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" знак равно

Так не должно ли http_build_query создавать более читаемый вывод с такими символами, как [] urlencoded только там, где это необходимо? Как я могу сделать такой вывод?

Здесь я нашел следующее «исправление»:

[…] работоспособное «исправление», которое я использовал, – это выполнить postprocess http_build_query () вывод со следующим: «решение», из-за которого моя скин сканирует немного:

 function http_build_query_unborker($s) { return preg_replace_callback('#%5[bd](?=[^&]*=)#i', function($match) { return urldecode($match[0]); }, $s); } 

Так что теперь это станет:

 $query = array("var" => array("foo" => "value", "bar" => "encodedBracket[")); $queryString = http_build_query_unborker(http_build_query($query, "", "&")); var_dump($queryString); var_dump("urldecoded: " . urldecode($queryString)); // var[foo]=value&var[bar]=encodedBracket%5B 

У вас здесь много вопросов. Выступая в RFC-условиях, вы должны прочитать свои собственные вопросы на этих же условиях. Я беру ваши вопросы сверху вниз:

Как я могу сделать такой вывод?

Используя другой кодировщик, Net_URL2 ( груша / упаковщик ), например:

 $vars = array("var" => array("foo" => "value", "bar" => "encodedBracket[")); $url = new Net_URL2(''); $url->setQueryVariables($vars); $query = $url->getQuery(); var_dump($query); // string(41) "var[foo]=value&var[bar]=encodedBracket%5B" 

Так не должно ли http_build_query really создавать более читаемый вывод с такими символами, как [] urlencoded только там, где это необходимо?

Нет, не должно. Даже не требуется кодировать квадратные скобки внутри части запроса, рекомендуется. То, что рекомендуется, должно быть сделано.

Кроме того, http_build_query() не http_build_query() созданием «более читаемого вывода» . Речь идет только о создании запроса URI HTTP. Для такой части запроса квадратные скобки должны быть закодированы в процентах. Это зарезервированные символы, которые специально не разрешены для запроса.

В чем причина кодирования квадратных скобок в var[foo]= и var[bar]= ?

Причиной для кодирования квадратных скобок является та же самая причина для кодирования квадратных скобок в encodedBracket[ . Дифференциация, которую вы делаете между этими частями в своем вопросе, является чисто синтаксической по своему усмотрению, в URI эти части рассматриваются равными. В URI нет частей части запроса. Поэтому различие между скобкой var[ или скобкой encodedBracket[ абсолютно не связано с кодировкой URI части запроса).

Как вы говорите, процентное кодирование encodedBracket[ в encodedBracket%5B является правильным и, поскольку оно принадлежит к той же части URI (часть запроса), логика требует, чтобы вы приняли эту кодировку скобки в var[ to var%5B одинаково корректно с точки зрения кодирования URI. Такая же часть URI, такое же кодирование. Единственным конечным разделителем, который имеет часть запроса, является « # ».

Кроме того, ваши рассуждения показывают недоразумение в этой части:

Как вы можете видеть, urldecoding строки также декодировал зарезервированные символы в значениях, encodedBracket%5B должен был оставаться таким, как если бы строка запроса была правильной и не стала encodedBracket[ .

Если вы urldecode, все процентные кодированные последовательности будут декодированы – независимо от того, представляет ли процентная кодировка зарезервированный символ или нет. С точки зрения правильности, это противоположно тому, что вы заявили: %5B должен быть декодирован до [ независимо от того, был ли он в начале, в середине или в конце строки.

Почему при построении строки запроса с http_build_query функции http_build_query она ссылается на квадратные скобки [] вне значений и как избавиться от нее?

Легче ответить на вторую часть, см. В начале ответа, это уже ответили.

О том, почему это, возможно, может быть не сразу видно, особенно, поскольку вы, возможно, обнаружили, что сам PHP принимает процентные и стенографические квадратные скобки в запросе (даже смешанные) без каких-либо проблем.

Почему возникают различия и почему это так? Действительно ли это так просто, как вы изложите это в своем вопросе? Это только косметическая разница?

Прежде всего, не кодирование квадратных скобок в части запроса запроса URI нарушает RFC3986 в том смысле, что часть запроса не должна содержать скобки из символов gen-delims, не кодированных. Квадратные скобки без процентного кодирования не могут быть частью запроса в соответствии с ABNF:

  query = *( pchar / "/" / "?" ) pchar = unreserved / pct-encoded / sub-delims / ":" / "@" unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" pct-encoded = "%" HEXDIG HEXDI sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" 

Избавиться от них поэтому не предлагается (по крайней мере, для целей кодирования в соответствии со стандартом), поскольку это изменит URI:

URI, которые отличаются заменой зарезервированного символа его соответствующим процентным октетом, не эквивалентны.

Это уже хороший намек на то, что для URI, который вы запрашиваете, он имеет другое значение, чем URI PHP создает через встроенную функцию.

И далее:

Приложения, создающие URI, должны иметь октеты данных с процентным кодированием, которые соответствуют символам зарезервированного набора, если только эти символы не разрешены схемой URI для представления данных в этом компоненте.

Это не относится ко всем символам в gen-delims, но для ABNF:

 "/" / "?" / ":" / "@" 

Поэтому он выглядит так, что http_build_query() отправил маршрут в квадратные скобки с процентом-кодированием, поскольку они зарезервированы и не разрешены с помощью схемы URI для этой части (запроса). В принципе, ничего плохого в этом нет, это следует за рекомендацией RFC3986. И это не говорит о другом значении для тех частей запроса.

Однако вы четко говорите, что технически эти скобки не являются разделителями в запросе. И да, это правда:

Компонент запроса обозначается символом первого символа вопроса («?») И заканчивается символом номера («#») или к концу URI.

Таким образом, по сравнению с тем, что было идентифицировано ранее, поскольку зарезервированные символы специально не разрешены:

 "#" / "[" / "]" 

(уже довольно маленький список) должно быть ясно, что « # » должно оставаться в резервном порядке, иначе URI будет разорван (истинный разделительный разделитель в конце запроса), но квадратные скобки не должны быть специально разрешены при представлении неравного URI без потери данных и сохранения всех разделителей URI:

Если зарезервированный символ найден в компоненте URI, и для этого символа не определена роль разграничения, тогда его следует интерпретировать как представляющий октет данных, соответствующий кодировке этого символа в US-ASCII.

Поэтому, если вы все еще можете следовать за мной, возможно, вам захочется фактически сделать то, что вы просите: Создание URI, в котором квадратные скобки означают как разделитель (например, представляющий часть определения массива), но не имеющие этого в качестве данных. Хотя данные символа сохраняются на RFC 3986.

Поэтому технически возможно создать URI с квадратными скобками, а не процентами, закодированными в запросе. Технически даже внутри значений, например, это будет синтаксическая разница вне значений, это лишь другое синтаксическое различие внутри значений.

Это также является причиной того, что браузеры сохраняют состояние квадратных скобок в запросе, когда вы вводите их в свой браузер. Процент закодирован или нет – браузер передает эту часть URI как есть на сервер, так что базовые процессы на сервере могут извлечь выгоду из синтаксических различий, которые могли быть выражены этим.

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

Одна из причин, которую вы называете в своем вопросе, – читаемость. Это особенно важно при написании URL-адресов, например, на листе бумаги. Я не уверен, что квадратная скобка является таким хорошо различимым символом, и если процентное кодирование даже не помогает с удобочитаемостью. Но я не пробовал. PHP будет принимать оба способа. Но тогда вам не нужно будет делать это программно. Поэтому, возможно, читаемость не была в вашем случае.