8000 Extracted code to expand an URI to `UriExpanderTrait` · symfony/symfony@f37f128 · GitHub
[go: up one dir, main page]

Skip to content

Commit f37f128

Browse files
committed
Extracted code to expand an URI to UriExpanderTrait
1 parent 07818f2 commit f37f128

File tree

4 files changed

+228
-72
lines changed

4 files changed

+228
-72
lines changed

src/Symfony/Component/DomCrawler/AbstractUriElement.php

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -80,46 +80,7 @@ public function getMethod()
8080
*/
8181
public function getUri()
8282
{
83-
$uri = trim($this->getRawUri());
84-
85-
// absolute URL?
86-
if (null !== parse_url($uri, PHP_URL_SCHEME)) {
87-
return $uri;
88-
}
89-
90-
// empty URI
91-
if (!$uri) {
92-
return $this->currentUri;
93-
}
94-
95-
// an anchor
96-
if ('#' === $uri[0]) {
97-
return $this->cleanupAnchor($this->currentUri).$uri;
98-
}
99-
100-
$baseUri = $this->cleanupUri($this->currentUri);
101-
102-
if ('?' === $uri[0]) {
103-
return $baseUri.$uri;
104-
}
105-
106-
// absolute URL with relative schema
107-
if (0 === strpos($uri, '//')) {
108-
return preg_replace('#^([^/]*)//.*$#', '$1', $baseUri).$uri;
109-
}
110-
111-
$baseUri = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUri);
112-
113-
// absolute path
114-
if ('/' === $uri[0]) {
115-
return $baseUri.$uri;
116-
}
117-
118-
// relative path
119-
$path = parse_url(substr($this->currentUri, \strlen($baseUri)), PHP_URL_PATH);
120-
$path = $this->canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri);
121-
122-
return $baseUri.('' === $path || '/' !== $path[0] ? '/' : '').$path;
83+
return UriExpander::expandUri($this->getRawUri(), $this->currentUri);
12384
}
12485

12586
/**
@@ -167,36 +128,4 @@ protected function canonicalizePath(string $path)
167128
* @throws \LogicException If given node is not an anchor
168129
*/
169130
abstract protected function setNode(\DOMElement $node);
170-
171-
/**
172-
* Removes the query string and the anchor from the given uri.
173-
*/
174-
private function cleanupUri(string $uri): string
175-
{
176-
return $this->cleanupQuery($this->cleanupAnchor($uri));
177-
}
178-
179-
/**
180-
* Remove the query string from the uri.
181-
*/
182-
private function cleanupQuery(string $uri): string
183-
{
184-
if (false !== $pos = strpos($uri, '?')) {
185-
return substr($uri, 0, $pos);
186-
}
187-
188-
return $uri;
189-
}
190-
191-
/**
192-
* Remove the anchor from the uri.
193-
*/
194-
private function cleanupAnchor(string $uri): string
195-
{
196-
if (false !== $pos = strpos($uri, '#')) {
197-
return substr($uri, 0, $pos);
198-
}
199-
200-
return $uri;
201-
}
202131
}

src/Symfony/Component/DomCrawler/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.1.0
5+
-----
6+
7+
* Added `UriExpander` to expand an URL according to another URL
8+
49
5.0.0
510
-----
611

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DomCrawler\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DomCrawler\UriExpander;
16+
17+
class UriExpanderTest extends TestCase
18+
{
19+
/**
20+
* @dataProvider provideExpandUriTests
21+
*/
22+
public function testExpandUri(string $uri, string $currentUri, string $expected)
23+
{
24+
$this->assertEquals($expected, UriExpander::expandUri($uri, $currentUri));
25+
}
26+
27+
public function provideExpandUriTests()
28+
{
29+
return [
30+
['/foo', 'http://localhost/bar/foo/', 'http://localhost/foo'],
31+
['/foo', 'http://localhost/bar/foo', 'http://localhost/foo'],
32+
['
33+
/foo', 'http://localhost/bar/foo/', 'http://localhost/foo'],
34+
['/foo
35+
', 'http://localhost/bar/foo', 'http://localhost/foo'],
36+
37+
['foo', 'http://localhost/bar/foo/', 'http://localhost/bar/foo/foo'],
38+
['foo', 'http://localhost/bar/foo', 'http://localhost/bar/foo'],
39+
40+
['', 'http://localhost/bar/', 'http://localhost/bar/'],
41+
['#', 'http://localhost/bar/', 'http://localhost/bar/#'],
42+
['#bar', 'http://localhost/bar?a=b', 'http://localhost/bar?a=b#bar'],
43+
['#bar', 'http://localhost/bar/#foo', 'http://localhost/bar/#bar'],
44+
['?a=b', 'http://localhost/bar#foo', 'http://localhost/bar?a=b'],
45+
['?a=b', 'http://localhost/bar/', 'http://localhost/bar/?a=b'],
46+
47+
['http://login.foo.com/foo', 'http://localhost/bar/', 'http://login.foo.com/foo'],
48+
['https://login.foo.com/foo', 'https://localhost/bar/', 'https://login.foo.com/foo'],
49+
['mailto:foo@bar.com', 'http://localhost/foo', 'mailto:foo@bar.com'],
50+
51+
// tests schema relative URL (issue #7169)
52+
['//login.foo.com/foo', 'http://localhost/bar/', 'http://login.foo.com/foo'],
53+
['//login.foo.com/foo', 'https://localhost/bar/', 'https://login.foo.com/foo'],
54+
55+
['?foo=2', 'http://localhost?foo=1', 'http://localhost?foo=2'],
56+
['?foo=2', 'http://localhost/?foo=1', 'http://localhost/?foo=2'],
57+
['?foo=2', 'http://localhost/bar?foo=1', 'http://localhost/bar?foo=2'],
58+
['?foo=2', 'http://localhost/bar/?foo=1', 'http://localhost/bar/?foo=2'],
59+
['?bar=2', 'http://localhost?foo=1', 'http://localhost?bar=2'],
60+
61+
['foo', 'http://login.foo.com/bar/baz?/query/string', 'http://login.foo.com/bar/foo'],
62+
63+
['.', 'http://localhost/foo/bar/baz', 'http://localhost/foo/bar/'],
64+
['./', 'http://localhost/foo/bar/baz', 'http://localhost/foo/bar/'],
65+
['./foo', 'http://localhost/foo/bar/baz', 'http://localhost/foo/bar/foo'],
66+
['..', 'http://localhost/foo/bar/baz', 'http://localhost/foo/'],
67+
['../', 'http://localhost/foo/bar/baz', 'http://localhost/foo/'],
68+
['../foo', 'http://localhost/foo/bar/baz', 'http://localhost/foo/foo'],
69+
['../..', 'http://localhost/foo/bar/baz', 'http://localhost/'],
70+
['../../', 'http://localhost/foo/bar/baz', 'http://localhost/'],
71+
['../../foo', 'http://localhost/foo/bar/baz', 'http://localhost/foo'],
72+
['../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'],
73+
['../bar/../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'],
74+
['../bar/./../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'],
75+
['../../', 'http://localhost/', 'http://localhost/'],
76+
['../../', 'http://localhost', 'http://localhost/'],
77+
78+
['/foo', 'http://localhost?bar=1', 'http://localhost/foo'],
79+
['/foo', 'http://localhost#bar', 'http://localhost/foo'],
80+
['/foo', 'file:///', 'file:///foo'],
81+
['/foo', 'file:///bar/baz', 'file:///foo'],
82+
['foo', 'file:///', 'file:///foo'],
83+
['foo', 'file:///bar/baz', 'file:///bar/foo'],
84+
];
85+
}
86+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DomCrawler;
13+
14+
/**
15+
* Expand an URI according a curr 10000 ent URI.
16+
*
17+
*
18+
* @author Fabien Potencier <fabien@symfony.com>
19+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
20+
*/
21+
trait UriExpander
22+
{
23+
/**
24+
* Expand an URI according to a current Uri.
25+
*
26+
* For example if $uri=/foo/bar and $currentUri=https://symfony.com it will
27+
* return https://symfony.com/foo/bar
28+
*
29+
* If the $uri is not absolute you must pass an absolute $currentUri
30+
*/
31+
public static function expandUri(string $uri, ?string $currentUri): string
32+
{
33+
$uri = trim($uri);
34+
35+
// absolute URL?
36+
if (null !== parse_url($uri, PHP_URL_SCHEME)) {
37+
return $uri;
38+
}
39+
40+
if (null === $currentUri) {
41+
throw new \InvalidArgumentException('The URI is relative, so you must define its base URI passing an absolute URL.');
42+
}
43+
44+
// empty URI
45+
if (!$uri) {
46+
return $currentUri;
47+
}
48+
49+
// an anchor
50+
if ('#' === $uri[0]) {
51+
return self::cleanupAnchor($currentUri).$uri;
52+
}
53+
54+
$baseUri = self::cleanupUri($currentUri);
55+
56+
if ('?' === $uri[0]) {
57+
return $baseUri.$uri;
58+
}
59+
60+
// absolute URL with relative schema
61+
if (0 === strpos($uri, '//')) {
62+
return preg_replace('#^([^/]*)//.*$#', '$1', $baseUri).$uri;
63+
}
64+
65+
$baseUri = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUri);
66+
67+
// absolute path
68+
if ('/' === $uri[0]) {
69+
return $baseUri.$uri;
70+
}
71+
72+
// relative path
73+
$path = parse_url(substr($currentUri, \strlen($baseUri)), PHP_URL_PATH);
74+
$path = self::canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri);
75+
76+
return $baseUri.('' === $path || '/' !== $path[0] ? '/' : '').$path;
77+
}
78+
79+
/**
80+
* Returns the canonicalized URI path (see RFC 3986, section 5.2.4).
81+
*/
82+
private static function canonicalizePath(string $path): string
83+
{
84+
if ('' === $path || '/' === $path) {
85+
return $path;
86+
}
87+
88+
if ('.' === substr($path, -1)) {
89+
$path .= '/';
90+
}
91+
92+
$output = [];
93+
94+
foreach (explode('/', $path) as $segment) {
95+
if ('..' === $segment) {
96+
array_pop($output);
97+
} elseif ('.' !== $segment) {
98+
$output[] = $segment;
99+
}
100+
}
101+
102+
return implode('/', $output);
103+
}
104+
105+
/**
106+
* Removes the query string and the anchor from the given uri.
107+
*/
108+
private static function cleanupUri(string $uri): string
109+
{
110+
return self::cleanupQuery(self::cleanupAnchor($uri));
111+
}
112+
113+
/**
114+
* Remove the query string from the uri.
115+
*/
116+
private static function cleanupQuery(string $uri): string
117+
{
118+
if (false !== $pos = strpos($uri, '?')) {
119+
return substr($uri, 0, $pos);
120+
}
121+
122+
return $uri;
123+
}
124+
125+
/**
126+
* Remove the anchor from the uri.
127+
*/
128+
private static function cleanupAnchor(string $uri): string
129+
{
130+
if (false !== $pos = strpos($uri, '#')) {
131+
return substr($uri, 0, $pos);
132+
}
133+
134+
return $uri;
135+
}
136+
}

0 commit comments

Comments
 (0)
0