http_build_query
Builds a URL-encoded query string from an array or object of parameters.
http_build_query(array|object $data, string $numeric_prefix = "", ?string $arg_separator = null, int $encoding_type = PHP_QUERY_RFC1738): string- Added in PHP 5.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$data | array|object | An array, or an object whose public properties are used. May be nested. |
$numeric_prefixoptional | string= "" | Prepended to numeric keys of the top-level array only, so the result yields valid variable names. |
$arg_separatoroptional | ?string= null | Separator between pairs. When null, the arg_separator.output ini setting is used. |
$encoding_typeoptional | int= PHP_QUERY_RFC1738 | PHP_QUERY_RFC1738 encodes spaces as +, PHP_QUERY_RFC3986 encodes them as %20. |
Return value
stringA URL-encoded query string, without a leading ? character.
Errors
Raises a TypeError if data is neither an array nor an object.
Changelog
- PHP 8.4.0BackedEnum properties of data are converted to their scalar equivalents instead of being treated as objects.
- PHP 8.0.0arg_separator is now nullable.
http_build_query() is the correct way to assemble a query string. Concatenating "?q=$term&page=$n" by hand breaks the moment a value contains a space, an ampersand or a plus sign; this function encodes every key and value for you.
Nested data
Nested arrays become bracketed keys: ['tags' => ['a','b']] produces tags%5B0%5D=a&tags%5B1%5D=b, which PHP and most frameworks parse straight back into a nested array. Objects contribute only their public properties; private and protected ones are silently skipped.
Value conversion
Booleans become 1 and 0, not true and false. Entries whose value is null are omitted entirely, which is handy for optional filters but surprising if you expected an empty parameter.
Which encoding
The default PHP_QUERY_RFC1738 matches HTML form submission and encodes spaces as +. Pass PHP_QUERY_RFC3986 when a stricter consumer — an OAuth signature base string, an AWS request, a JavaScript URLSearchParams round-trip — expects %20. The return value never includes a leading ?, so add it yourself, and check whether the base URL already has one.
Example
When to use it
- Assemble a paginated, filtered search URL without hand-escaping user input
- Build an application/x-www-form-urlencoded POST body for a cURL or stream request
- Regenerate the current URL with one query parameter changed for a sort link
- Produce the RFC 3986 parameter string needed for an OAuth 1.0 signature
Frequently asked questions
Does http_build_query add a question mark?
No, it returns only the parameter string. Prepend '?' yourself, or '&' if the base URL already has a query.
How do I get %20 instead of + for spaces?
Pass PHP_QUERY_RFC3986 as the fourth argument. The default PHP_QUERY_RFC1738 uses + because that is what HTML forms send.
Why are some of my parameters missing from the query string?
Values that are null are skipped completely. Use an empty string if you want the parameter present with no value.
More examples
Nulls, booleans and the round trip
The output is active=1&archived=0&since=2026-01-01: the null author vanished, and the booleans became 1 and 0. Note what parse_str gives back — the strings "1" and "0", not real booleans, so a query string round trip does not preserve types.
<?php
$filters = [
'active' => true,
'archived'=> false,
'author' => null,
'since' => '2026-01-01',
];
$query = http_build_query($filters);
echo $query, "\n";
parse_str($query, $back);
print_r($back);Numeric prefix for list arrays
A bare list produces 0=17&1=42&2=99, whose numeric keys are awkward on the receiving side. The prefix turns them into id_0=17&id_1=42&id_2=99, while nesting the list under a key gives the more common id%5B0%5D=17 bracket form.
<?php
$ids = [17, 42, 99];
echo http_build_query($ids), "\n";
echo http_build_query($ids, 'id_'), "\n";
echo http_build_query(['id' => $ids]), "\n";Objects and a form-encoded request body
Only the public properties appear: email and plan. The protected $secret is skipped entirely, and the space in "pro tier" is encoded as +, giving a body ready to send with an application/x-www-form-urlencoded Content-Type.
<?php
class Signup {
public string $email = '[email protected]';
public string $plan = 'pro tier';
protected string $secret = 'hidden';
}
$body = http_build_query(new Signup());
echo $body, "\n";
echo 'Content-Length: ' . strlen($body), "\n";
Discussion