Uri::getAuthority()   A
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 9
cts 9
cp 1
rs 9.584
c 0
b 0
f 0
cc 4
nc 5
nop 0
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Aidphp\Http;
6
7
use Psr\Http\Message\UriInterface;
8
use InvalidArgumentException;
9
10
class Uri implements UriInterface
11
{
12
    private $scheme   = '';
13
    private $userInfo = '';
14
    private $host     = '';
15
    private $port;
16
    private $path     = '';
17
    private $query    = '';
18
    private $fragment = '';
19
20
    private static $schemes = [
21
        'http'  => 80,
22
        'https' => 443,
23
    ];
24
25 160
    public function __construct(string $uri = '')
26
    {
27 160
        if ('' !== $uri)
28
        {
29 135
            $this->parseUri($uri);
30
        }
31 140
    }
32
33 6
    public function getScheme(): string
34
    {
35 6
        return $this->scheme;
36
    }
37
38 88
    public function getAuthority(): string
39
    {
40 88
        $authority = '';
41
42 88
        if ($this->host)
43
        {
44 75
            $authority .= $this->host;
45
46 75
            if ($this->userInfo)
47
            {
48 27
                $authority = $this->userInfo . '@' . $authority;
49
            }
50
51 75
            if ($this->port)
52
            {
53 23
                $authority .= ':' . $this->port;
54
            }
55
        }
56
57 88
        return $authority;
58
    }
59
60 6
    public function getUserInfo(): string
61
    {
62 6
        return $this->userInfo;
63
    }
64
65 39
    public function getHost(): string
66
    {
67 39
        return $this->host;
68
    }
69
70 38
    public function getPort(): ?int
71
    {
72 38
        return $this->port;
73
    }
74
75 13
    public function getPath(): string
76
    {
77 13
        return $this->path;
78
    }
79
80 19
    public function getQuery(): string
81
    {
82 19
        return $this->query;
83
    }
84
85 6
    public function getFragment(): string
86
    {
87 6
        return $this->fragment;
88
    }
89
90 8
    public function withScheme($scheme): self
91
    {
92 8
        $scheme = $this->filterScheme($scheme);
93 4
        if ($this->scheme === $scheme)
94
        {
95 1
            return $this;
96
        }
97
98 3
        $new = clone $this;
99 3
        $new->scheme = $scheme;
100 3
        $new->port = $new->filterPort($new->port);
101 3
        return $new;
102
    }
103
104 4
    public function withUserInfo($user, $password = null): self
105
    {
106 4
        $info = $user;
107 4
        if ('' != $password)
108
        {
109 3
            $info .= ':' . $password;
110
        }
111
112 4
        if ($this->userInfo === $info)
113
        {
114 1
            return $this;
115
        }
116
117 3
        $new = clone $this;
118 3
        $new->userInfo = $info;
119 3
        return $new;
120
    }
121
122 3
    public function withHost($host): self
123
    {
124 3
        $host = $this->filterHost($host);
125 3
        if ($this->host === $host)
126
        {
127 1
            return $this;
128
        }
129
130 2
        $new = clone $this;
131 2
        $new->host = $host;
132 2
        return $new;
133
    }
134
135 5
    public function withPort($port): self
136
    {
137 5
        $port = $this->filterPort($port);
138 3
        if ($this->port === $port)
139
        {
140 1
            return $this;
141
        }
142
143 2
        $new = clone $this;
144 2
        $new->port = $port;
145 2
        return $new;
146
    }
147
148 2
    public function withPath($path): self
149
    {
150 2
        $path = $this->filterPath($path);
151 2
        if ($this->path === $path)
152
        {
153 1
            return $this;
154
        }
155
156 1
        $new = clone $this;
157 1
        $new->path = $path;
158 1
        return $new;
159
    }
160
161 16
    public function withQuery($query): self
162
    {
163 16
        $query = $this->filterQueryOrFragment($query);
164 16
        if ($this->query === $query)
165
        {
166 1
            return $this;
167
        }
168
169 15
        $new = clone $this;
170 15
        $new->query = $query;
171 15
        return $new;
172
    }
173
174 4
    public function withFragment($fragment): self
175
    {
176 4
        $fragment = $this->filterQueryOrFragment($fragment);
177 4
        if ($this->fragment === $fragment)
178
        {
179 1
            return $this;
180
        }
181
182 3
        $new = clone $this;
183 3
        $new->fragment = $fragment;
184 3
        return $new;
185
    }
186
187 79
    public function __toString()
188
    {
189 79
        $uri = '';
190
191 79
        if ($this->scheme)
192
        {
193 64
            $uri .= $this->scheme . ':';
194
        }
195
196 79
        $authority = $this->getAuthority();
197
198 79
        if ($authority)
199
        {
200 68
            $uri .= '//' . $authority;
201
        }
202
203 79
        $uri .= $this->path;
204
205 79
        if ($this->query)
206
        {
207 34
            $uri .= '?' . $this->query;
208
        }
209
210 79
        if ($this->fragment)
211
        {
212 19
            $uri .= '#' . $this->fragment;
213
        }
214
215 79
        return $uri;
216
    }
217
218 135
    private function parseUri(string $uri): void
219
    {
220 135
        $parts = parse_url($uri);
221 135
        if (false === $parts)
222
        {
223 15
            throw new InvalidArgumentException('Unable to parse URI');
224
        }
225
226 120
        $this->scheme   = isset($parts['scheme']) ? $this->filterScheme($parts['scheme']) : '';
227 115
        $this->userInfo = isset($parts['user']) ? $parts['user'] : '';
228 115
        $this->host     = isset($parts['host']) ? $this->filterHost($parts['host']) : '';
229 115
        $this->port     = isset($parts['port']) ? $this->filterPort($parts['port']) : null;
230 115
        $this->path     = isset($parts['path']) ? $this->filterPath($parts['path']) : '';
231 115
        $this->query    = isset($parts['query']) ? $this->filterQueryOrFragment($parts['query']) : '';
232 115
        $this->fragment = isset($parts['fragment']) ? $this->filterQueryOrFragment($parts['fragment']) : '';
233
234 115
        if (isset($parts['pass']))
235
        {
236 21
            $this->userInfo .= ':' . $parts['pass'];
237
        }
238 115
    }
239
240 104
    private function filterScheme(string $scheme): string
241
    {
242 104
        $scheme = strtolower($scheme);
243
244 104
        if ('http' !== $scheme && 'https' !== $scheme)
245
        {
246 5
            throw new InvalidArgumentException('Invalid HTTP scheme "' . $scheme . '" provided');
247
        }
248
249 99
        return $scheme;
250
    }
251
252 104
    private function filterHost(string $host): string
253
    {
254 104
        return strtolower($host);
255
    }
256
257 49
    private function filterPort(?int $port): ?int
258
    {
259 49
        if (null === $port)
260
        {
261 2
            return null;
262
        }
263
264 48
        if (1 > $port || 0xffff < $port)
265
        {
266 2
            throw new InvalidArgumentException('Invalid HTTP port "' . $port . '". Must be between 1 and 65535');
267
        }
268
269 46
        return (! isset(self::$schemes[$this->scheme]) || $port !== self::$schemes[$this->scheme]) ? $port : null;
270
    }
271
272 83
    private function filterPath(string $path): string
273
    {
274 83
        return preg_replace_callback('#(?:[^a-zA-Z0-9_\-\.~\pL\)\(:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))#u', [$this, 'urlEncode'], $path);
275
    }
276
277 64
    private function filterQueryOrFragment(string $str): string
278
    {
279 64
        return preg_replace_callback('#(?:[^a-zA-Z0-9_\-\.~\pL!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))#u', [$this, 'urlEncode'], $str);
280
    }
281
282 7
    private function urlEncode(array $matches): string
283
    {
284 7
        return rawurlencode($matches[0]);
285
    }
286
}