Skip to content

Commit 60209fc

Browse files
committed
Url: optimized unescape() performance
1 parent 88784b1 commit 60209fc

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

src/Http/Url.php

+9-8
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ public function __toString()
451451

452452

453453
/**
454-
* Similar to rawurldecode, but preserve reserved chars encoded.
454+
* Similar to rawurldecode, but preserves reserved chars encoded.
455455
* @param string to decode
456456
* @param string reserved characters
457457
* @return string
@@ -461,14 +461,15 @@ public static function unescape($s, $reserved = '%;/?:@&=+$,')
461461
// reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
462462
// within a path segment, the characters "/", ";", "=", "?" are reserved
463463
// within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved.
464-
preg_match_all('#(?<=%)[a-f0-9][a-f0-9]#i', $s, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
465-
foreach (array_reverse($matches) as $match) {
466-
$ch = chr(hexdec($match[0][0]));
467-
if (strpos($reserved, $ch) === FALSE) {
468-
$s = substr_replace($s, $ch, $match[0][1] - 1, 3);
469-
}
464+
if ($reserved === '') {
465+
return rawurldecode($s);
466+
}
467+
$pattern = '#((?:%(?:' . implode('|', str_split(bin2hex($reserved), 2)) . '))++)#i';
468+
$parts = preg_split($pattern, $s, -1, PREG_SPLIT_DELIM_CAPTURE);
469+
for ($i = 0; $i < count($parts); $i += 2) {
470+
$parts[$i] = rawurldecode($parts[$i]);
470471
}
471-
return $s;
472+
return implode('', $parts);
472473
}
473474

474475
}

tests/Http/Url.unescape.phpt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\Http\Url unescape.
5+
*/
6+
7+
use Nette\Http\Url,
8+
Tester\Assert;
9+
10+
11+
require __DIR__ . '/../bootstrap.php';
12+
13+
14+
Assert::same( 'foo + bar', Url::unescape('foo + bar') );
15+
Assert::same( 'foo + bar', Url::unescape('foo + bar', '') );
16+
Assert::same( 'foo', Url::unescape('%66%6F%6F', '') );
17+
Assert::same( 'f%6F%6F', Url::unescape('%66%6F%6F', 'o') );
18+
Assert::same( '%66oo', Url::unescape('%66%6F%6F', 'f') );
19+
Assert::same( '%66%6F%6F', Url::unescape('%66%6F%6F', 'fo') );
20+
Assert::same( '%66%6f%6f', Url::unescape('%66%6f%6f', 'fo') );
21+
Assert::same( "%00\x01%02", Url::unescape('%00%01%02', "\x00\x02") );

0 commit comments

Comments
 (0)