Skip to content

Commit a4edd89

Browse files
authored
Merge pull request #4644 from MGatner/uri-dots
URI::removeDotSegments()
2 parents 5cbf51c + 0275e69 commit a4edd89

File tree

2 files changed

+138
-116
lines changed

2 files changed

+138
-116
lines changed

system/HTTP/URI.php

Lines changed: 109 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,113 @@ class URI
142142

143143
//--------------------------------------------------------------------
144144

145+
/**
146+
* Builds a representation of the string from the component parts.
147+
*
148+
* @param string $scheme
149+
* @param string $authority
150+
* @param string $path
151+
* @param string $query
152+
* @param string $fragment
153+
*
154+
* @return string
155+
*/
156+
public static function createURIString(string $scheme = null, string $authority = null, string $path = null, string $query = null, string $fragment = null): string
157+
{
158+
$uri = '';
159+
if (! empty($scheme))
160+
{
161+
$uri .= $scheme . '://';
162+
}
163+
164+
if (! empty($authority))
165+
{
166+
$uri .= $authority;
167+
}
168+
169+
if ($path !== '')
170+
{
171+
$uri .= substr($uri, -1, 1) !== '/' ? '/' . ltrim($path, '/') : ltrim($path, '/');
172+
}
173+
174+
if ($query)
175+
{
176+
$uri .= '?' . $query;
177+
}
178+
179+
if ($fragment)
180+
{
181+
$uri .= '#' . $fragment;
182+
}
183+
184+
return $uri;
185+
}
186+
187+
/**
188+
* Used when resolving and merging paths to correctly interpret and
189+
* remove single and double dot segments from the path per
190+
* RFC 3986 Section 5.2.4
191+
*
192+
* @see http://tools.ietf.org/html/rfc3986#section-5.2.4
193+
*
194+
* @param string $path
195+
*
196+
* @return string
197+
* @internal
198+
*/
199+
public static function removeDotSegments(string $path): string
200+
{
201+
if ($path === '' || $path === '/')
202+
{
203+
return $path;
204+
}
205+
206+
$output = [];
207+
208+
$input = explode('/', $path);
209+
210+
if ($input[0] === '')
211+
{
212+
unset($input[0]);
213+
$input = array_values($input);
214+
}
215+
216+
// This is not a perfect representation of the
217+
// RFC, but matches most cases and is pretty
218+
// much what Guzzle uses. Should be good enough
219+
// for almost every real use case.
220+
foreach ($input as $segment)
221+
{
222+
if ($segment === '..')
223+
{
224+
array_pop($output);
225+
}
226+
elseif ($segment !== '.' && $segment !== '')
227+
{
228+
$output[] = $segment;
229+
}
230+
}
231+
232+
$output = implode('/', $output);
233+
$output = trim($output, '/ ');
234+
235+
// Add leading slash if necessary
236+
if (strpos($path, '/') === 0)
237+
{
238+
$output = '/' . $output;
239+
}
240+
241+
// Add trailing slash if necessary
242+
if ($output !== '/' && substr($path, -1, 1) === '/')
243+
{
244+
$output .= '/';
245+
}
246+
247+
return $output;
248+
}
249+
250+
//--------------------------------------------------------------------
251+
145252
/**
146253
* Constructor.
147254
*
@@ -592,51 +699,7 @@ public function __toString(): string
592699
//--------------------------------------------------------------------
593700

594701
/**
595-
* Builds a representation of the string from the component parts.
596-
*
597-
* @param string $scheme
598-
* @param string $authority
599-
* @param string $path
600-
* @param string $query
601-
* @param string $fragment
602-
*
603-
* @return string
604-
*/
605-
public static function createURIString(string $scheme = null, string $authority = null, string $path = null, string $query = null, string $fragment = null): string
606-
{
607-
$uri = '';
608-
if (! empty($scheme))
609-
{
610-
$uri .= $scheme . '://';
611-
}
612-
613-
if (! empty($authority))
614-
{
615-
$uri .= $authority;
616-
}
617-
618-
if ($path !== '')
619-
{
620-
$uri .= substr($uri, -1, 1) !== '/' ? '/' . ltrim($path, '/') : ltrim($path, '/');
621-
}
622-
623-
if ($query)
624-
{
625-
$uri .= '?' . $query;
626-
}
627-
628-
if ($fragment)
629-
{
630-
$uri .= '#' . $fragment;
631-
}
632-
633-
return $uri;
634-
}
635-
636-
//--------------------------------------------------------------------
637-
638-
/**
639-
* Parses the given string an saves the appropriate authority pieces.
702+
* Parses the given string and saves the appropriate authority pieces.
640703
*
641704
* @param string $str
642705
*
@@ -947,7 +1010,7 @@ protected function filterPath(string $path = null): string
9471010
$path = urldecode($path);
9481011

9491012
// Remove dot segments
950-
$path = $this->removeDotSegments($path);
1013+
$path = self::removeDotSegments($path);
9511014

9521015
// Fix up some leading slash edge cases...
9531016
if (strpos($orig, './') === 0)
@@ -1140,74 +1203,6 @@ protected function mergePaths(URI $base, URI $reference): string
11401203

11411204
//--------------------------------------------------------------------
11421205

1143-
/**
1144-
* Used when resolving and merging paths to correctly interpret and
1145-
* remove single and double dot segments from the path per
1146-
* RFC 3986 Section 5.2.4
1147-
*
1148-
* @see http://tools.ietf.org/html/rfc3986#section-5.2.4
1149-
*
1150-
* @param string $path
1151-
*
1152-
* @return string
1153-
* @internal param \CodeIgniter\HTTP\URI $uri
1154-
*/
1155-
public function removeDotSegments(string $path): string
1156-
{
1157-
if ($path === '' || $path === '/')
1158-
{
1159-
return $path;
1160-
}
1161-
1162-
$output = [];
1163-
1164-
$input = explode('/', $path);
1165-
1166-
if ($input[0] === '')
1167-
{
1168-
unset($input[0]);
1169-
$input = array_values($input);
1170-
}
1171-
1172-
// This is not a perfect representation of the
1173-
// RFC, but matches most cases and is pretty
1174-
// much what Guzzle uses. Should be good enough
1175-
// for almost every real use case.
1176-
foreach ($input as $segment)
1177-
{
1178-
if ($segment === '..')
1179-
{
1180-
array_pop($output);
1181-
}
1182-
elseif ($segment !== '.' && $segment !== '')
1183-
{
1184-
$output[] = $segment;
1185-
}
1186-
}
1187-
1188-
$output = implode('/', $output);
1189-
$output = ltrim($output, '/ ');
1190-
1191-
if ($output !== '/')
1192-
{
1193-
// Add leading slash if necessary
1194-
if (strpos($path, '/') === 0)
1195-
{
1196-
$output = '/' . $output;
1197-
}
1198-
1199-
// Add trailing slash if necessary
1200-
if (substr($path, -1, 1) === '/')
1201-
{
1202-
$output .= '/';
1203-
}
1204-
}
1205-
1206-
return $output;
1207-
}
1208-
1209-
//--------------------------------------------------------------------
1210-
12111206
/**
12121207
* This is equivalent to the native PHP parse_str() function.
12131208
* This version allows the dot to be used as a key of the query string.

tests/system/HTTP/URITest.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,34 @@ public function testSetAuthorityReconstitutes()
567567
public function defaultDots()
568568
{
569569
return [
570+
[
571+
'',
572+
'',
573+
],
574+
[
575+
'/',
576+
'/',
577+
],
578+
[
579+
'.',
580+
'',
581+
],
582+
[
583+
'..',
584+
'',
585+
],
586+
[
587+
'/.',
588+
'/',
589+
],
590+
[
591+
'/..',
592+
'/',
593+
],
594+
[
595+
'//',
596+
'/',
597+
],
570598
[
571599
'/foo/..',
572600
'/',
@@ -641,8 +669,7 @@ public function defaultDots()
641669
*/
642670
public function testRemoveDotSegments($path, $expected)
643671
{
644-
$uri = new URI();
645-
$this->assertEquals($expected, $uri->removeDotSegments($path));
672+
$this->assertEquals($expected, URI::removeDotSegments($path));
646673
}
647674

648675
//--------------------------------------------------------------------

0 commit comments

Comments
 (0)