optimize uri building

This commit is contained in:
Dennis Eichhorn 2020-07-30 21:26:30 +02:00
parent 2177024fdc
commit e736214417
2 changed files with 64 additions and 29 deletions

View File

@ -132,7 +132,7 @@ final class UriFactory
$data = $uri->getQueryArray();
foreach ($data as $key => $value) {
self::setQuery('?' . $key, $value);
self::setQuery('?' . $key, $value, true);
}
}
@ -192,36 +192,39 @@ final class UriFactory
*/
private static function unique(string $url) : string
{
$parts = \explode('&', \str_replace('?', '&', $url));
$query = '';
$partCount = \count($parts);
$fragment = '';
// handle edge cases / normalization
$url = \str_replace(
['=%', '=#', '=?'],
['=%25', '=%23', '=%3F'],
$url
);
if (($fragStart = \strripos($parts[$partCount - 1], '#')) !== false) {
$fragment = \substr($parts[$partCount - 1], $fragStart);
$parts[$partCount - 1] = \substr($parts[$partCount - 1], 0, $fragStart);
}
$urlStructure = \parse_url($url);
\parse_str($urlStructure['query'] ?? '', $urlStructure['query']);
if ($partCount > 1) {
$pars = \array_slice($parts, 1);
$length = \count($pars);
$url = $parts[0];
$keys = [];
$escaped =
(isset($urlStructure['scheme']) && !empty($urlStructure['scheme'])
? $urlStructure['scheme'] . '://' : '')
. (isset($urlStructure['username']) && !empty($urlStructure['username'])
? $urlStructure['username'] . ':' : '')
. (isset($urlStructure['password']) && !empty($urlStructure['password'])
? $urlStructure['password'] . '@' : '')
. (isset($urlStructure['host']) && !empty($urlStructure['host'])
? $urlStructure['host'] : '')
. (isset($urlStructure['port']) && !empty($urlStructure['port'])
? ':' . $urlStructure['port'] : '')
. (isset($urlStructure['path']) && !empty($urlStructure['path'])
? $urlStructure['path'] : '')
. (isset($urlStructure['query']) && !empty($urlStructure['query'])
? '?' . \http_build_query($urlStructure['query']) : '')
. (isset($urlStructure['fragment']) && !empty($urlStructure['fragment'])
? '#' . \str_replace('\#', '#', $urlStructure['fragment']) : '');
for ($i = $length - 1; $i > -1; --$i) {
$spl = \explode('=', $pars[$i]);
if (isset($spl[1]) && !\in_array($spl[0], $keys)) {
$keys[] = $spl[0];
if (!empty($spl[1])) {
$query = $spl[0] . '=' . \urlencode($spl[1]) . '&' . $query;
}
}
}
}
return $url . (!empty($query) ? '?' . \rtrim($query, '&') : '') . $fragment;
return \str_replace(
['%5C%7B', '%5C%7D', '%5C%3F', '%5C%23'],
['{', '}', '?', '#'],
$escaped
);
}
/**

View File

@ -172,7 +172,7 @@ class UriFactoryTest extends \PHPUnit\Framework\TestCase
self::assertTrue(UriFactory::setQuery('/valid2', 'query4'));
$expected = 'www.test-uri.com?id=1&test=someString&two=PATH&hash=test&none=%23none&found=%2Fnot&v=query4';
$expected = 'www.test-uri.com?id=1&test=someString&two=PATH&hash=test&none=%23none&found=%2Fnot%3Fv%3Dquery4';
self::assertEquals($expected, UriFactory::build($uri, $vars));
}
@ -193,4 +193,36 @@ class UriFactoryTest extends \PHPUnit\Framework\TestCase
self::assertEquals($uri, UriFactory::build('{%}'));
self::assertEquals($uri, UriFactory::build('{/base}{/rootPath}{/}?{?}#{#}'));
}
/**
* @testdox In case of duplicated query elements the last element is used
* @covers phpOMS\Uri\UriFactory
* @group framework
*/
public function testDuplicatedQueryElements() : void
{
$uri = 'http://www.test-uri.com/path/here?id=123&ab=c&id=456#fragi';
$expected = 'http://www.test-uri.com/path/here?id=456&ab=c#fragi';
UriFactory::setupUriBuilder(new HttpUri($uri));
self::assertEquals($expected, UriFactory::build('{/base}{/rootPath}{/}?id={?id}&ab={?ab}#{#}'));
}
/**
* @testdox The uri variables can be unescaped
* @covers phpOMS\Uri\UriFactory
* @group framework
*/
public function testVariableUnescape() : void
{
$uri = 'http://www.test-uri.com/path/here?id=123&ab=c#fragi';
$escaped = '{/base}{/rootPath}{/}?id=\{\?id\}&ab={?ab}#{#}';
$unescaped = 'http://www.test-uri.com/path/here?id={?id}&ab=c#fragi';
var_dump('TEST:');
UriFactory::setupUriBuilder(new HttpUri($uri));
self::assertEquals($unescaped, UriFactory::build($escaped));
}
}