Особенности http_build_query в PHP
Казалось бы http_build_query — простая функция, однако, имеет некоторые особенности. Нельзя однозначно сказать что это баг, скорее просто недокументированная фича, которую стоит учитывать при разработке.
Допустим, есть массив [‘page’ => 2, ‘hide’ => null]. Что же вернёт http_build_query в результате? Это будет просто page=2, аргумент hide был отброшен, т.к. он имеет значение null! Что будет, если передать массив, где все значения будут null? Функция вернёт строку нулевой длины.
Взаимосвязь parse_str и http_build_query
В документации PHP по функции http_build_query есть отсылка к другой функции — parse_str, которая делает обратное действие: возвращает массив [‘page’ => ‘2’, ‘hide’ => »] на основе строк ‘page=2&hide’ или ‘page=2&hide=’. Если этот массив прогнать обратно через http_build_query, то результат получится ‘page=2&hide=’, что для некоторых ситуаций будет детерминировано.
Влияние http_build_query на фреймворк Laravel
Однако, некоторые фреймворки, например, Laravel и, скорее всего Symfony, строку с параметрами ‘page=2&hide’ или ‘page=2&hide=’ парсят [‘page’ => ‘2’, ‘hide’ => null]. Самое странное, что обратно этот массив параметров они собирают с помощью всё той же http_build_query, в результате чего в урле теряется параметр hide.
Ещё одна ошибка, которая часть встречается в скриптах при формировании полного url. Вот пример из Laravel 5.6 из класса \Illuminate\Http\Request:
public function fullUrlWithQuery(array $query) < $question = $this->getBaseUrl().$this->getPathInfo() == '/' ? '/?' : '?'; return count($this->query()) > 0 ? $this->url().$question.http_build_query(array_merge($this->query(), $query)) : $this->fullUrl().$question.http_build_query($query); >
Что вернёт данный метод, если в query все значения будут null? Что-то вроде: «http://127.0.0.1:8000/?». Как видите, на конце появился не нужный знак вопроса, т.к. после него нет ни одного параметра. Это происходит из-за того, что считается количество элементов в массиве вместе с null значениями.
Однако, соседний метод \Illuminate\Http\Request::fullUrl() вернёт корректное значение: «http://127.0.0.1:8000/?hide=»
Проблема потери параметров в http_build_query
Казалось бы, нет проблемы, теряется параметр без значения. Однако, для внешних систем, параметр без значения может быть значимым и его потеря приведёт к непредвиденному результату. Например, это может быть какая-нибудь JS-библиотека, для которой параметр без значения так же важен как и параметр со значением. Проблемы также могут возникнуть в аналитических системах, при интеграции с другими сайтами и системами.
Не все веб-приложения работают на PHP, не все соблюдают стандарты и спецификации, особенно в других странах. И иногда потеря get-параметра без значения может обернуться серьёзной ошибкой для бизнес-логики.
А что, если не баг, а фича?
Однако, у этой особенности работы http_build_query есть и приятная сторона. Можно достаточно просто удалять ненужные параметры из строки запроса таким способом:
$query = ['page' => 2, 'hide' => 6, 'user' => 4, 'section' => 22]; $except = ['hide' => null, 'user' => null]; $new = http_build_query(array_merge($query, $except) );
В результате чего получится строка: page=2§ion=22.
Читайте также
Что не так с этим скриптом? Очень крутая задача, в которой не всё так просто, как кажется на первый взгляд. Попробуйте найти в ней 2 логические…
Что не так с функцией file_put_contents() в PHP? Если в кратце, то суть такая: file_put_contents() не атомарен и не гарантирует записи данных файл, а может вообще очистить его…
Cлучайные числа с плавающей точкой в PHP Стандартные библиотеки PHP умеют генерировать только целые случайные числа. Однако, возникают задачи где нужно не целое рандомное число с максимально…
http_build_str
Строит строку запроса из массива, содержащего переменные запроса. По действию эта функция противоположна функции parse_str() .
Список параметров
Ассоциативный массив с параметрами запроса
Используемый разделитель аргументов (по умолчанию используется значение INI директивы arg_separator.output, или «&», если ничего не указано.
Возвращаемые значения
Возвращает построенный запрос как строку в случае успеха или FALSE в случае возникновения ошибки.
Смотрите также
User Contributed Notes 1 note
For those who are using PECL pecl_http 2, you need to refer to HttpQueryString, which is now implemented under http namespace. Therefore,
- HTTP Функции
- http_cache_etag
- http_cache_last_modified
- http_chunked_decode
- http_deflate
- http_inflate
- http_build_cookie
- http_date
- http_get_request_body_stream
- http_get_request_body
- http_get_request_headers
- http_match_etag
- http_match_modified
- http_match_request_header
- http_support
- http_negotiate_charset
- http_negotiate_content_type
- http_negotiate_language
- ob_deflatehandler
- ob_etaghandler
- ob_inflatehandler
- http_parse_cookie
- http_parse_headers
- http_parse_message
- http_parse_params
- http_persistent_handles_clean
- http_persistent_handles_count
- http_persistent_handles_ident
- http_get
- http_head
- http_post_data
- http_post_fields
- http_put_data
- http_put_file
- http_put_stream
- http_request_body_encode
- http_request_method_exists
- http_request_method_name
- http_request_method_register
- http_request_method_unregister
- http_request
- http_redirect
- http_send_content_disposition
- http_send_content_type
- http_send_data
- http_send_file
- http_send_last_modified
- http_send_status
- http_send_stream
- http_throttle
- http_build_str
- http_build_url