urldecode

Decodes a URL-encoded string, converting plus signs back into spaces.

Signature
urldecode(string $string): string
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$stringstringThe string to be decoded.

Return value

stringThe decoded string, with %XX sequences and + characters resolved.

Errors

Does not throw. Invalid escape sequences are left as literal text.

urldecode() reverses urlencode(): it resolves every %XX escape and, unlike rawurldecode(), it also turns + into a space. That makes it the decoder for query strings and form bodies, and the wrong decoder for path segments.

The dangerous mistake

$_GET, $_POST and $_REQUEST arrive already decoded. Calling urldecode() on them decodes a second time, so a user who submits %252F gets %2F after PHP's pass and a real / after yours. That is how directory traversal and filter bypasses get in. The manual warns about this explicitly; treat any urldecode($_GET[...]) in a codebase as a bug.

Where it is genuinely useful

Decoding a raw query string you read yourself — from a stored URL, a log line, a Referer header, or the string parse_url() hands back. Even there, parse_str() is usually better, because it splits the pairs and decodes them in one step.

Decoding is byte-oriented and never fails: '50% off' comes back unchanged rather than raising an error, so it cannot be used to check that a string was validly encoded.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Decode a single value pulled out of a query string you parsed by hand
  • Read parameters from a URL stored in a log file or database column
  • Recover the original search term from a Referer header
  • Decode form-encoded data received in a raw request body

Frequently asked questions

Do I need to call urldecode on $_GET values?

No, and you should not. PHP decodes $_GET, $_POST and $_REQUEST for you, and decoding twice can turn user-supplied escapes into real slashes or dots.

What is the difference between urldecode and rawurldecode?

urldecode converts + into a space as well as resolving %XX escapes; rawurldecode leaves + alone. Use urldecode for query strings and form data, rawurldecode for path segments.

How do I decode a whole query string into an array?

Use parse_str($query, $params), which splits the pairs and decodes keys and values in one step, including bracketed array notation.

More examples

Parsing a query string by hand, and the better way

Both approaches give are = "green and red" and note = "a&b". Splitting on '=' with a limit of 2 is essential, since a decoded value may itself contain '='. parse_str does the same work in one call and handles bracketed array keys too.

Example · php
<?php
$query = 'my=apples&are=green+and+red&note=a%26b';

foreach (explode('&', $query) as $chunk) {
    [$k, $v] = array_pad(explode('=', $chunk, 2), 2, '');
    printf("%s = %s\n", urldecode($k), urldecode($v));
}

parse_str($query, $params);
print_r($params);

Double decoding is a security bug

After PHP's own decoding the value is still the harmless literal %2e%2e%2fetc. One extra urldecode turns it into ../etc, a real traversal sequence — which is exactly why you must not decode superglobals again.

Example · php
<?php
// What the browser sent: file=%252e%252e%252fetc
$fromPhp = '%2e%2e%2fetc';   // PHP already decoded once

echo "safe   : $fromPhp\n";
echo "decoded: " . urldecode($fromPhp) . "\n";
echo "basename of decoded: " . basename(urldecode($fromPhp)) . "\n";

Choosing the matching decoder

The first is correct: urldecode restores "C++ notes". The second shows the mismatch — rawurldecode decodes the two %2B escapes but leaves the separator + in place, giving "C+++notes" with no space at all. The third pairing is also correct because %20 needs no plus handling.

Example · php
<?php
$name = 'C++ notes';

$formStyle = urlencode($name);      // C%2B%2B+notes
$pathStyle = rawurlencode($name);   // C%2B%2B%20notes

var_dump(urldecode($formStyle));
var_dump(rawurldecode($formStyle));
var_dump(rawurldecode($pathStyle));

Discussion

  • Be the first to comment on this lesson.