26

Is there a way to build a query automatically with http_build_query using parameters with the same name?

If I do something like

array('foo' => 'x', 'foo' => 'y');

They are obviously overwritten within the array, but even if I do:

array('foo' => array('x', 'y'));

The function creates something like foo[0]=x&foo[1], which isn't what I want, since I need the parameters in this format foo=x&foo=y.

2 Answers 2

47

You can solve this by doing substitution on the result of http_build_query() where the [0], [1], …, suffixes are URL-encoded.

$vars = array('foo' => array('x', 'y'));
$query = http_build_query($vars);
# $query is now foo%5B0%5D=x&foo%5B1%5D=y (URL-encoded foo[0]=x&foo[1]=y)
$query = preg_replace('/%5B\d+%5D(?==)/', '', $query);
# $query is now foo=x&foo=y

The look-ahead ((?= … )) ensures it only replaces values at the end of a name because they are always followed by an =. PHP won't produce indices with leading zeroes, so \d+ (1 or more digits) is sufficient to detect them.

Some systems require the square brackets without indices inside them. In that case you can use this:

$query = preg_replace('/%5B\K\d+(?=%5D=)/', '', $query);
# $query is now foo%5B%5D=x&foo%5B%5D=y (URL-encoded foo[]=x&foo[]=y)
Sign up to request clarification or add additional context in comments.

Comments

7

Here is a function I created to build the query and preserve names. I created this to work with a third-party API that requires multiple query string parameters with the same name.

function custom_build_query(
    array|object $query_data,
    string $numeric_prefix = "",
    ?string $arg_separator = null,
    int $encoding_type = PHP_QUERY_RFC1738
): string {
    // Cast to array if object is supplied.
    $query_data = is_object($query_data) ? get_object_vars($query_data) : $query_data;
    
    // Use supplied arg_separator value, defaulting to the `arg_separator.output` php configuration.
    $arg_separator = $arg_separator ?? ini_get("arg_separator.output");
    
    // If PHP_QUERY_RFC3986 is specified, use rawurlencode to encode parameters.
    $encoding_function = $encoding_type === PHP_QUERY_RFC3986 ? "rawurlencode" : "urlencode";
    
    $query = [];
    foreach ($query_data as $name => $value) {
        $value = (array) $value;
        $name = is_int($name) ? $numeric_prefix . $name : $name;
        array_walk_recursive($value, function ($value) use (&$query, $name, $encoding_function) {
            $query[] = $encoding_function($name) . "=" . $encoding_function($value);
        });
    }
    return implode($arg_separator, $query);
}

Usage:

echo custom_build_query(['a' => 1, 'b' => 2, 'c' => [3, 4]]);

Output:

a=1&b=2&c=3&c=4

Note: The function's signature is fully compatible with http_build_query. The only difference is, of course, the function will not use brackets for sub-array parameters.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.