HttpImmutable   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 63
dl 0
loc 271
rs 10
c 0
b 0
f 0
wmc 27

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getScheme() 0 3 1
A getPort() 0 3 2
A getUser() 0 3 1
B setAuthority() 0 28 7
A getPathBag() 0 3 1
B __construct() 0 27 7
A getPassword() 0 3 1
A getFragment() 0 3 1
A all() 0 12 2
A getQueryBag() 0 3 1
A getAuthority() 0 3 1
A raw() 0 3 1
A getHost() 0 3 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Keppler\Url\Scheme\Schemes\Http;
5
6
use Keppler\Url\Interfaces\Immutable\ImmutableSchemeInterface;
7
use Keppler\Url\Scheme\Schemes\AbstractImmutable;
8
use Keppler\Url\Scheme\Schemes\Http\Bags\HttpImmutablePath;
9
use Keppler\Url\Scheme\Schemes\Http\Bags\HttpImmutableQuery;
10
11
/**
12
 * Note that the following class makes no assumption regarding url encoding
13
 * the https url is taken AS IS and will not be decoded or encoded
14
 * url encoded strings WILL result in errors
15
 *
16
 *  userinfo     host        port
17
 * ┌─┴────┐ ┌────┴────────┐ ┌┴┐
18
 *  https://[email protected]:123/forum/questions/?tag=networking&order=newest#top
19
 *  └─┬─┘ └───────┬────────────────────┘└─┬─────────────┘└──┬───────────────────────┘└┬─┘
20
 * scheme     authority                 path              query                      fragment
21
 *
22
 * @see https://tools.ietf.org/html/rfc3986#page-16
23
 *
24
 * Class HttpImmutable
25
 *
26
 * @package Keppler\Url\Schemes\Http
27
 */
28
class HttpImmutable extends AbstractImmutable implements ImmutableSchemeInterface
29
{
30
    /**
31
     * The default scheme for this class
32
     *
33
     * @var string
34
     */
35
    const SCHEME = 'http';
36
37
    /**
38
     * authority = [ userinfo "@" ] host [ ":" port ]
39
     *
40
     * -- An optional authority component preceded by two slashes (//), comprising:
41
     *
42
     *   - An optional userinfo subcomponent that may consist of a user name and an optional password preceded
43
     *  by a colon (:), followed by an at symbol (@). Use of the format username:password in the userinfo
44
     *  subcomponent is deprecated for security reasons. Applications should not render as clear text any data
45
     *  after the first colon (:) found within a userinfo subcomponent unless the data after the colon
46
     *  is the empty string (indicating no password).
47
     *
48
     *  - An optional host subcomponent, consisting of either a registered name (including but not limited to a hostname),
49
     *  or an IP address. IPv4 addresses must be in dot-decimal notation, and IPv6 addresses must be enclosed in brackets ([]).[10][c]
50
     *
51
     *   - An optional port subcomponent preceded by a colon (:).
52
     *
53
     * @var string
54
     */
55
    private $authority = '';
56
57
    /**
58
     * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
59
     *
60
     * @var string
61
     */
62
    private $user = '';
63
64
    /**
65
     * Usage is highly discouraged
66
     *
67
     * @var string
68
     */
69
    private $password = '';
70
71
    /**
72
     * host = IP-literal / IPv4address / reg-name
73
     *
74
     * @var string
75
     */
76
    private $host = '';
77
78
    /**
79
     * port = *DIGIT
80
     *
81
     * Ports can't be negative, -1 should be considered the default value and ignored
82
     *
83
     * INVALID-PORT
84
     *  Either the local or foreign port was improperly
85
     *  specified.  This should be returned if either or
86
     *  both of the port ids were out of range (TCP port
87
     *  numbers are from 1-65535), negative integers, reals or
88
     *  in any fashion not recognized as a non-negative integer.
89
     *
90
     * @see https://www.ietf.org/rfc/rfc1413.txt
91
     * @var int
92
     */
93
    private $port = -1;
94
95
    /**
96
     * fragment = *( pchar / "/" / "?" )
97
     *
98
     * @var string
99
     */
100
    private $fragment = '';
101
102
    /**
103
     * @var HttpImmutableQuery
104
     */
105
    private $queryBag;
106
107
    /**
108
     * @var HttpImmutablePath
109
     */
110
    private $pathBag;
111
112
    /**
113
     * @var string
114
     */
115
    private $raw = '';
116
117
    /**
118
     * MailtoImmutable constructor.
119
     * @param $url
120
     */
121
    public function __construct(string $url)
122
    {
123
        $this->raw = $url;
124
125
        $parsedUrl = parse_url($url);
126
127
        $this->setAuthority($parsedUrl);
128
129
        if (isset($parsedUrl['fragment'])) {
130
            if (false !== strpos($parsedUrl['fragment'], '#')) {
131
                // get only the first fragment
132
                $this->fragment = explode('#', $parsedUrl['fragment'])[0];
133
            } else {
134
                $this->fragment = $parsedUrl['fragment'];
135
            }
136
        }
137
138
        if (isset($parsedUrl['query']) && !empty($parsedUrl['query'])) {
139
            $this->queryBag = new HttpImmutableQuery($parsedUrl['query']);
140
        } else {
141
            $this->queryBag = new HttpImmutableQuery();
142
        }
143
144
        if (isset($parsedUrl['path']) && !empty($parsedUrl['path'])) {
145
            $this->pathBag = new HttpImmutablePath($parsedUrl['path']);
146
        } else {
147
            $this->pathBag = new HttpImmutablePath();
148
        }
149
    }
150
151
///////////////////////////
152
/// PRIVATE FUNCTIONS  ///
153
/////////////////////////
154
155
    /**
156
     * @param array $parsedUrl
157
     */
158
    private function setAuthority(array $parsedUrl)
159
    {
160
        $authority = '';
161
162
        if (isset($parsedUrl['user'])) {
163
            $authority .= $parsedUrl['user'];
164
            $this->user = $parsedUrl['user'];
165
        }
166
167
        if (isset($parsedUrl['pass'])) {
168
            $authority .= ':'.$parsedUrl['pass'];
169
            $this->password = $parsedUrl['pass'];
170
        }
171
172
        if (isset($parsedUrl['host'])) {
173
            if (!empty($this->user) || !empty($this->password)) {
174
                $authority .= '@';
175
            }
176
            $authority .= $parsedUrl['host'];
177
            $this->host = $parsedUrl['host'];
178
        }
179
180
        if (isset($parsedUrl['port'])) {
181
            $authority .= ':'.$parsedUrl['port'];
182
            $this->port = $parsedUrl['port'];
183
        }
184
185
        $this->authority = $authority;
186
    }
187
188
//////////////////////////
189
/// GETTER FUNCTIONS  ///
190
////////////////////////
191
192
    /**
193
     * @return string
194
     */
195
    public function getAuthority(): string
196
    {
197
        return $this->authority;
198
    }
199
200
    /**
201
     * @return string
202
     */
203
    public function getUser(): string
204
    {
205
        return $this->user;
206
    }
207
208
    /**
209
     * @return string
210
     */
211
    public function getPassword(): string
212
    {
213
        return $this->password;
214
    }
215
216
    /**
217
     * @return string
218
     */
219
    public function getHost(): string
220
    {
221
        return $this->host;
222
    }
223
224
    /**
225
     * @return int|null
226
     */
227
    public function getPort(): ?int
228
    {
229
        return -1 === $this->port ? null : $this->port;
230
    }
231
232
    /**
233
     * @return string
234
     */
235
    public function getFragment(): string
236
    {
237
        return $this->fragment;
238
    }
239
240
    /**
241
     * @return HttpImmutableQuery
242
     */
243
    public function getQueryBag(): HttpImmutableQuery
244
    {
245
        return $this->queryBag;
246
    }
247
248
    /**
249
     * @return HttpImmutablePath
250
     */
251
    public function getPathBag(): HttpImmutablePath
252
    {
253
        return $this->pathBag;
254
    }
255
256
/////////////////////////////////
257
/// INTERFACE IMPLEMENTATION  ///
258
/////////////////////////////////
259
260
    /**
261
     * Returns all the components of the scheme including
262
     *  any bags in the form of an array
263
     *
264
     * @return array
265
     */
266
    public function all(): array
267
    {
268
        return [
269
            'scheme' => self::SCHEME,
270
            'authority' => $this->authority,
271
            'user' => $this->user,
272
            'password' => $this->password,
273
            'host' => $this->host,
274
            'port' => $this->port === -1 ? null : $this->port,
275
            'query' => $this->queryBag->all(),
276
            'path' => $this->pathBag->all(),
277
            'fragment' => $this->fragment,
278
        ];
279
    }
280
281
    /**
282
     * Return the raw unaltered url
283
     *
284
     * @return string
285
     */
286
    public function raw(): string
287
    {
288
        return $this->raw;
289
    }
290
291
    /**
292
     * Returns the scheme associated with the class
293
     *
294
     * @return string
295
     */
296
    public function getScheme(): string
297
    {
298
        return self::SCHEME;
299
    }
300
}
301
302