Signature
mb_parse_str(string $string, array &$result): boolPurpose
mb_parse_str() decodes a URL-encoded query string, such as a=1&b=2, into a PHP array. It differs from plain parse_str() in that it also detects the character encoding of the decoded bytes and converts the values to PHP's multibyte internal encoding. This matters when a query string was percent-encoded from non-ASCII text and you want the resulting strings in a known encoding.
The manual describes it as a function for GET, POST and cookie style data. PHP does not expose raw POST or cookie bodies to it, so in practice it is used on query-string-shaped text that you already hold in a variable.
Signature
Parameters and defaults
$string: the URL-encoded data to parse. Percent escapes and+as a space are decoded. Bracket syntax such astags[]=aoruser[name]=Linbuilds nested arrays.$result: a variable passed by reference. On success it holds the decoded and converted values as an array.
Neither parameter has a default. The changelog notes that the second parameter became required in PHP 8.0.0, after calling the function without it was deprecated in 7.2.0. In PHP 8.4 you must always pass a result variable.
Return value and failure cases
The function returns true on success and false on failure. The decoded data is not returned directly; read it from $result. Check the return value before trusting the array. Values are always strings or nested arrays of strings, never integers or booleans.
Example 1: basic query data
A simple query string becomes an associative array. Repeated [] keys become a list. Numbers stay as strings.
$ok = mb_parse_str('name=Ada&langs[]=php&langs[]=js&page=2', $result);
echo json_encode(['ok' => $ok, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"ok":true,"result":{"name":"Ada","langs":["php","js"],"page":"2"}}
Notice that page is the string "2". Cast it yourself if you need an integer.
Example 2: percent-encoded UTF-8
Here the bytes for ü arrive as %C3%BC. Setting the internal and detection encodings explicitly keeps the example independent of configuration.
mb_internal_encoding('UTF-8');
mb_detect_order(['UTF-8']);
$ok = mb_parse_str('city=M%C3%BCnchen¬e=hello+world', $result);
echo json_encode(['ok' => $ok, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"ok":true,"result":{"city":"München","note":"hello world"}}
The + becomes a space, and the percent-encoded bytes become the UTF-8 string München.
Example 3: nested keys and empty values
Bracket names create nested structures. A key with an equals sign and nothing after it, or a key with no equals sign at all, produces an empty string.
$ok = mb_parse_str('user[name]=Lin&user[tags][]=a&flag=&empty', $result);
echo json_encode(['ok' => $ok, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"ok":true,"result":{"user":{"name":"Lin","tags":["a"]},"flag":"","empty":""}}
Edge cases
- Encoding detection depends on configuration. The function uses the detection order (see
mb_detect_order()) to guess the source encoding and converts to the internal encoding (seemb_internal_encoding()). Short or ambiguous byte sequences can be guessed wrongly, so set both explicitly when the input encoding is known. - Pass the query part only. A leading
?or a full URL is not stripped. The first key would contain that extra text. Extract the query withparse_url()first, then parse it. - Keys follow request-variable rules. Names are processed like PHP request variables, which can differ from the raw key text. Test unusual key characters before depending on them.
- The result is an array, not global variables. Older PHP code used one-argument forms that created globals. That form is gone in PHP 8.
Common mistakes
- Omitting the second argument. This is an error in PHP 8.4. Always pass a variable for
$result. - Using the return value as the data. The return value is only a success flag.
- Expecting typed values.
age=30yields"30", andok=trueyields"true". - Assuming it reads the current request. It parses only the string you give it. Use
$_GETfor the actual request data. - Ignoring encoding setup. If your application depends on a particular internal encoding, configure it deliberately rather than relying on defaults.
Related functions
parse_str(): parses query strings without the encoding detection and conversion step.mb_detect_order(): sets or reads the encoding detection order that influences parsing.mb_internal_encoding(): sets or reads the encoding the values are converted to.mb_convert_encoding(): converts a string between encodings directly.http_build_query(): builds a query string from an array, the reverse direction.parse_url(): splits a URL so you can pass only its query part.
Recap
mb_parse_str() decodes URL-encoded text into the by-reference $result array, handles nested bracket keys and converts the decoded values to the internal encoding. It returns true or false, always needs both arguments in PHP 8.4, and produces string values. Strip the leading ? yourself, and set the detection order and internal encoding explicitly whenever the input encoding matters.
Tested examples
$ok = mb_parse_str('name=Ada&langs[]=php&langs[]=js&page=2', $result);
echo json_encode(['ok' => $ok, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"ok":true,"result":{"name":"Ada","langs":["php","js"],"page":"2"}}
mb_internal_encoding('UTF-8');
mb_detect_order(['UTF-8']);
$ok = mb_parse_str('city=M%C3%BCnchen¬e=hello+world', $result);
echo json_encode(['ok' => $ok, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"ok":true,"result":{"city":"München","note":"hello world"}}
$ok = mb_parse_str('user[name]=Lin&user[tags][]=a&flag=&empty', $result);
echo json_encode(['ok' => $ok, 'result' => $result], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"ok":true,"result":{"user":{"name":"Lin","tags":["a"]},"flag":"","empty":""}}