mirror of
https://github.com/codeigniter4/CodeIgniter4.git
synced 2025-02-20 11:44:28 +08:00
Get merging relative URL into a base URI working in the URI class.
This commit is contained in:
parent
a40317fb9c
commit
5fa6238e2e
@ -473,7 +473,15 @@ class URI
|
|||||||
{
|
{
|
||||||
$parts = parse_url($str);
|
$parts = parse_url($str);
|
||||||
|
|
||||||
|
if (empty($parts['host']) && ! empty($parts['path']))
|
||||||
|
{
|
||||||
|
$parts['host'] = $parts['path'];
|
||||||
|
unset($parts['path']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->applyParts($parts);
|
$this->applyParts($parts);
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
@ -706,14 +714,18 @@ class URI
|
|||||||
*/
|
*/
|
||||||
protected function filterPath($path)
|
protected function filterPath($path)
|
||||||
{
|
{
|
||||||
|
$orig = $path;
|
||||||
|
|
||||||
// Decode/normalize percent-encoded chars so
|
// Decode/normalize percent-encoded chars so
|
||||||
// we can always have matching for Routes, etc.
|
// we can always have matching for Routes, etc.
|
||||||
$path = urldecode($path);
|
$path = urldecode($path);
|
||||||
|
|
||||||
// Remove dot segments
|
// Remove dot segments
|
||||||
$path = str_replace('../', '/', $path);
|
$path = $this->removeDotSegments($path);
|
||||||
$path = str_replace('./', '/', $path);
|
|
||||||
$path = str_replace('//', '/', $path);
|
// Fix up some leading slash edge cases...
|
||||||
|
if (strpos($orig, './') === 0) $path = '/'. $path;
|
||||||
|
if (strpos($orig, '../') === 0) $path = '/'. $path;
|
||||||
|
|
||||||
// Encode characters
|
// Encode characters
|
||||||
$path = preg_replace_callback(
|
$path = preg_replace_callback(
|
||||||
@ -739,11 +751,11 @@ class URI
|
|||||||
*/
|
*/
|
||||||
protected function applyParts($parts)
|
protected function applyParts($parts)
|
||||||
{
|
{
|
||||||
$this->host = isset($parts['host']) ? $parts['host'] : '';
|
if (! empty($parts['host'])) $this->host = $parts['host'];
|
||||||
$this->user = isset($parts['user']) ? $parts['user'] : '';
|
if (! empty($parts['user'])) $this->user = $parts['user'];
|
||||||
$this->path = isset($parts['path']) ? $this->filterPath($parts['path']) : '';
|
if (! empty($parts['path'])) $this->path = $this->filterPath($parts['path']);
|
||||||
$this->query = isset($parts['query']) ? $this->filterQuery($parts['query']) : '';
|
if (! empty($parts['query'])) $this->query = $this->filterQuery($parts['query']);
|
||||||
$this->fragment = isset($parts['fragment']) ? $this->filterQuery($parts['fragment']) : '';
|
if (! empty($parts['fragment'])) $this->fragment = $this->filterQuery($parts['fragment']);
|
||||||
|
|
||||||
// Scheme
|
// Scheme
|
||||||
if (isset($parts['scheme']))
|
if (isset($parts['scheme']))
|
||||||
@ -791,21 +803,158 @@ class URI
|
|||||||
*/
|
*/
|
||||||
public function resolveRelativeURI(string $uri)
|
public function resolveRelativeURI(string $uri)
|
||||||
{
|
{
|
||||||
$relative = new URI($uri);
|
/*
|
||||||
|
* NOTE: We don't use removeDotSegments in this
|
||||||
|
* algorithm since it's already done by this line!
|
||||||
|
*/
|
||||||
|
$relative = new URI();
|
||||||
|
$relative->setURI($uri);
|
||||||
|
|
||||||
if ($relative->scheme() == $this->scheme())
|
if ($relative->scheme() == $this->scheme())
|
||||||
{
|
{
|
||||||
$relative->setScheme('');
|
$relative->setScheme('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$transformed = clone $relative;
|
||||||
|
|
||||||
// 5.2.2 Transform References
|
// 5.2.2 Transform References
|
||||||
if (! empty($relative->scheme()))
|
if (! empty($relative->scheme()))
|
||||||
{
|
{
|
||||||
$transformed->setScheme($relative->scheme())
|
$transformed->setScheme($relative->scheme())
|
||||||
->setAuth;
|
->setAuthority($relative->authority())
|
||||||
|
->setPath($relative->path())
|
||||||
|
->setQuery($relative->query());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! empty($relative->authority()))
|
||||||
|
{
|
||||||
|
$transformed->setAuthority($relative->authority())
|
||||||
|
->setPath($relative->path())
|
||||||
|
->setQuery($relative->query());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($relative->path() == '')
|
||||||
|
{
|
||||||
|
$transformed->setPath($this->path());
|
||||||
|
|
||||||
|
if (! is_null($relative->query()))
|
||||||
|
{
|
||||||
|
$transformed->setQuery($relative->query());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$transformed->setQuery($this->query());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (substr($relative->path(), 0, 1) == '/')
|
||||||
|
{
|
||||||
|
$transformed->setPath($relative->path());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$transformed->setPath($this->mergePaths($this, $relative));
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed->setQuery($relative->query());
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed->setAuthority($this->authority());
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed->setScheme($this->scheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
die((string)$relative ."\n");
|
$transformed->setFragment($relative->fragment());
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given 2 paths, will merge them according to rules set out in RFC 2986,
|
||||||
|
* Section 5.2
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc3986#section-5.2.3
|
||||||
|
*
|
||||||
|
* @param $path1
|
||||||
|
* @param $path2
|
||||||
|
*/
|
||||||
|
protected function mergePaths(URI $base, URI $reference)
|
||||||
|
{
|
||||||
|
if (! empty($base->authority()) && empty($base->path()))
|
||||||
|
{
|
||||||
|
return '/'. ltrim($base->path(), '/ ');
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = explode('/', $base->path());
|
||||||
|
|
||||||
|
if (empty($path[0])) unset($path[0]);
|
||||||
|
|
||||||
|
array_pop($path);
|
||||||
|
array_push($path, $reference->path());
|
||||||
|
|
||||||
|
return implode('/', $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when resolving and merging paths to correctly interpret and
|
||||||
|
* remove single and double dot segments from the path per
|
||||||
|
* RFC 3986 Section 5.2.4
|
||||||
|
*
|
||||||
|
* @see http://tools.ietf.org/html/rfc3986#section-5.2.4
|
||||||
|
*
|
||||||
|
* @param URI $uri
|
||||||
|
*/
|
||||||
|
public function removeDotSegments(string $path): string
|
||||||
|
{
|
||||||
|
if (empty($path) || $path == '/') return $path;
|
||||||
|
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
$input = explode('/', $path);
|
||||||
|
|
||||||
|
if (empty($input[0]))
|
||||||
|
{
|
||||||
|
unset($input[0]);
|
||||||
|
$input = array_values($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not a perfect representation of the
|
||||||
|
// RFC, but matches most cases and is pretty
|
||||||
|
// much what Guzzle uses. Should be good enough
|
||||||
|
// for almost every real use case.
|
||||||
|
foreach ($input as $segment)
|
||||||
|
{
|
||||||
|
if ($segment == '..')
|
||||||
|
{
|
||||||
|
array_pop($output);
|
||||||
|
}
|
||||||
|
else if ($segment != '.' && $segment != '')
|
||||||
|
{
|
||||||
|
array_push($output, $segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = implode('/', $output);
|
||||||
|
$output = ltrim($output, '/ ');
|
||||||
|
|
||||||
|
if ($output != '/')
|
||||||
|
{
|
||||||
|
// Add leading slash if necessary
|
||||||
|
if (substr($path, 0, 1) == '/') $output = '/'. $output;
|
||||||
|
|
||||||
|
// Add trailing slash if necessary
|
||||||
|
if (substr($path, -1, 1) == '/') $output .= '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
@ -316,15 +316,6 @@ class URITest extends PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
public function defaultResolutions()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'replace_last' => ['q', 'http://a/b/c/q']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
public function testSetAuthorityReconstitutes()
|
public function testSetAuthorityReconstitutes()
|
||||||
{
|
{
|
||||||
$authority = 'me@foo.com:3000';
|
$authority = 'me@foo.com:3000';
|
||||||
@ -337,19 +328,66 @@ class URITest extends PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function defaultDots()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('/foo/..', '/'),
|
||||||
|
array('//foo//..', '/'),
|
||||||
|
array('/foo/../..', '/'),
|
||||||
|
array('/foo/../.', '/'),
|
||||||
|
array('/./foo/..', '/'),
|
||||||
|
array('/./foo', '/foo'),
|
||||||
|
array('/./foo/', '/foo/'),
|
||||||
|
array('/./foo/bar/baz/pho/../..', '/foo/bar'),
|
||||||
|
array('*', '*'),
|
||||||
|
array('/foo', '/foo'),
|
||||||
|
array('/abc/123/../foo/', '/abc/foo/'),
|
||||||
|
array('/a/b/c/./../../g', '/a/g'),
|
||||||
|
array('/b/c/./../../g', '/g'),
|
||||||
|
array('/b/c/./../../g', '/g'),
|
||||||
|
array('/c/./../../g', '/g'),
|
||||||
|
array('/./../../g', '/g'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider defaultDots
|
||||||
|
*/
|
||||||
|
public function testRemoveDotSegments($path, $expected)
|
||||||
|
{
|
||||||
|
$uri = new URI();
|
||||||
|
$this->assertEquals($expected, $uri->removeDotSegments($path));
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function defaultResolutions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['g', 'http://a/b/c/g'],
|
||||||
|
['g/', 'http://a/b/c/g/'],
|
||||||
|
['/g', 'http://a/g'],
|
||||||
|
['#s', 'http://a/b/c/d#s'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider defaultResolutions
|
* @dataProvider defaultResolutions
|
||||||
|
* @group single
|
||||||
*/
|
*/
|
||||||
public function testResolveRelativeURI($rel, $expected)
|
public function testResolveRelativeURI($rel, $expected)
|
||||||
{
|
{
|
||||||
// $base = 'http://a/b/c/d;p?q';
|
$base = 'http://a/b/c/d';
|
||||||
//
|
|
||||||
// $uri = new URI($base);
|
$uri = new URI($base);
|
||||||
//
|
|
||||||
// $uri->resolveRelativeURI($rel);
|
$new = $uri->resolveRelativeURI($rel);
|
||||||
//
|
|
||||||
// $this->assertEquals($expected, (string)$uri);
|
$this->assertEquals($expected, (string)$new);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user