diff --git a/src/Http/Url.php b/src/Http/Url.php index 3d58e975..994dec13 100644 --- a/src/Http/Url.php +++ b/src/Http/Url.php @@ -451,7 +451,7 @@ public function __toString() /** - * Similar to rawurldecode, but preserve reserved chars encoded. + * Similar to rawurldecode, but preserves reserved chars encoded. * @param string to decode * @param string reserved characters * @return string @@ -461,14 +461,11 @@ public static function unescape($s, $reserved = '%;/?:@&=+$,') // reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," // within a path segment, the characters "/", ";", "=", "?" are reserved // within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved. - preg_match_all('#(?<=%)[a-f0-9][a-f0-9]#i', $s, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); - foreach (array_reverse($matches) as $match) { - $ch = chr(hexdec($match[0][0])); - if (strpos($reserved, $ch) === FALSE) { - $s = substr_replace($s, $ch, $match[0][1] - 1, 3); - } - } - return $s; + return $reserved === '' ? rawurldecode($s) : preg_replace_callback( + '#(?:%(?!' . implode('|', str_split(bin2hex($reserved), 2)) . ')[0-9a-f]{2})++#i', + function($m) { return rawurldecode($m[0]); }, + $s + ); } } diff --git a/tests/Http/Url.unescape.phpt b/tests/Http/Url.unescape.phpt new file mode 100644 index 00000000..0f8f7af3 --- /dev/null +++ b/tests/Http/Url.unescape.phpt @@ -0,0 +1,21 @@ +