Completed
Pull Request — master (#572)
by Frédéric
01:32
created

Uri::parseUri()   C

Complexity

Conditions 12
Paths 146

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 6.5833
c 0
b 0
f 0
cc 12
nc 146
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace OAuth\Common\Http\Uri;
4
5
use InvalidArgumentException;
6
7
/**
8
 * Standards-compliant URI class.
9
 */
10
class Uri implements UriInterface
11
{
12
    /**
13
     * @var string
14
     */
15
    private $scheme = 'http';
16
17
    /**
18
     * @var string
19
     */
20
    private $userInfo = '';
21
22
    /**
23
     * @var string
24
     */
25
    private $rawUserInfo = '';
26
27
    /**
28
     * @var string
29
     */
30
    private $host;
31
32
    /**
33
     * @var int
34
     */
35
    private $port = 80;
36
37
    /**
38
     * @var string
39
     */
40
    private $path = '/';
41
42
    /**
43
     * @var string
44
     */
45
    private $query = '';
46
47
    /**
48
     * @var string
49
     */
50
    private $fragment = '';
51
52
    /**
53
     * @var bool
54
     */
55
    private $explicitPortSpecified = false;
56
57
    /**
58
     * @var bool
59
     */
60
    private $explicitTrailingHostSlash = false;
61
62
    /**
63
     * @param string $uri
64
     */
65
    public function __construct($uri = null)
66
    {
67
        if (null !== $uri) {
68
            $this->parseUri($uri);
69
        }
70
    }
71
72
    /**
73
     * @param string $uri
74
     *
75
     * @throws \InvalidArgumentException
76
     */
77
    protected function parseUri($uri)
78
    {
79
        if (false === ($uriParts = parse_url($uri))) {
80
            // congratulations if you've managed to get parse_url to fail,
81
            // it seems to always return some semblance of a parsed url no matter what
82
            throw new InvalidArgumentException("Invalid URI: $uri");
83
        }
84
85
        if (!isset($uriParts['scheme'])) {
86
            throw new InvalidArgumentException('Invalid URI: http|https scheme required');
87
        }
88
89
        $this->scheme = $uriParts['scheme'];
90
        $this->host = $uriParts['host'];
91
92
        if (isset($uriParts['port'])) {
93
            $this->port = $uriParts['port'];
0 ignored issues
show
Documentation Bug introduced by
The property $port was declared of type integer, but $uriParts['port'] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
94
            $this->explicitPortSpecified = true;
95
        } else {
96
            $this->port = strcmp('https', $uriParts['scheme']) ? 80 : 443;
97
            $this->explicitPortSpecified = false;
98
        }
99
100
        if (isset($uriParts['path'])) {
101
            $this->path = $uriParts['path'];
102
            if ('/' === $uriParts['path']) {
103
                $this->explicitTrailingHostSlash = true;
104
            }
105
        } else {
106
            $this->path = '/';
107
        }
108
109
        $this->query = isset($uriParts['query']) ? $uriParts['query'] : '';
110
        $this->fragment = isset($uriParts['fragment']) ? $uriParts['fragment'] : '';
111
112
        $userInfo = '';
113
        if (!empty($uriParts['user'])) {
114
            $userInfo .= $uriParts['user'];
115
        }
116
        if ($userInfo && !empty($uriParts['pass'])) {
117
            $userInfo .= ':' . $uriParts['pass'];
118
        }
119
120
        $this->setUserInfo($userInfo);
121
    }
122
123
    /**
124
     * @param string $rawUserInfo
125
     *
126
     * @return string
127
     */
128
    protected function protectUserInfo($rawUserInfo)
129
    {
130
        $colonPos = strpos($rawUserInfo, ':');
131
132
        // rfc3986-3.2.1 | http://tools.ietf.org/html/rfc3986#section-3.2
133
        // "Applications should not render as clear text any data
134
        // after the first colon (":") character found within a userinfo
135
        // subcomponent unless the data after the colon is the empty string
136
        // (indicating no password)"
137
        if ($colonPos !== false && strlen($rawUserInfo)-1 > $colonPos) {
138
            return substr($rawUserInfo, 0, $colonPos) . ':********';
139
        } else {
140
            return $rawUserInfo;
141
        }
142
    }
143
144
    /**
145
     * @return string
146
     */
147
    public function getScheme()
148
    {
149
        return $this->scheme;
150
    }
151
152
    /**
153
     * @return string
154
     */
155
    public function getUserInfo()
156
    {
157
        return $this->userInfo;
158
    }
159
160
    /**
161
     * @return string
162
     */
163
    public function getRawUserInfo()
164
    {
165
        return $this->rawUserInfo;
166
    }
167
168
    /**
169
     * @return string
170
     */
171
    public function getHost()
172
    {
173
        return $this->host;
174
    }
175
176
    /**
177
     * @return int
178
     */
179
    public function getPort()
180
    {
181
        return $this->port;
182
    }
183
184
    /**
185
     * @return string
186
     */
187
    public function getPath()
188
    {
189
        return $this->path;
190
    }
191
192
    /**
193
     * @return string
194
     */
195
    public function getQuery()
196
    {
197
        return $this->query;
198
    }
199
200
    /**
201
     * @return string
202
     */
203
    public function getFragment()
204
    {
205
        return $this->fragment;
206
    }
207
208
    /**
209
     * Uses protected user info by default as per rfc3986-3.2.1
210
     * Uri::getRawAuthority() is available if plain-text password information is desirable.
211
     *
212
     * @return string
213
     */
214
    public function getAuthority()
215
    {
216
        $authority = $this->userInfo ? $this->userInfo.'@' : '';
217
        $authority .= $this->host;
218
219
        if ($this->explicitPortSpecified) {
220
            $authority .= ":{$this->port}";
221
        }
222
223
        return $authority;
224
    }
225
226
    /**
227
     * @return string
228
     */
229
    public function getRawAuthority()
230
    {
231
        $authority = $this->rawUserInfo ? $this->rawUserInfo.'@' : '';
232
        $authority .= $this->host;
233
234
        if ($this->explicitPortSpecified) {
235
            $authority .= ":{$this->port}";
236
        }
237
238
        return $authority;
239
    }
240
241
    /**
242
     * @return string
243
     */
244
    public function getAbsoluteUri()
245
    {
246
        $uri = $this->scheme . '://' . $this->getRawAuthority();
247
248
        if ('/' === $this->path) {
249
            $uri .= $this->explicitTrailingHostSlash ? '/' : '';
250
        } else {
251
            $uri .= $this->path;
252
        }
253
254
        if (!empty($this->query)) {
255
            $uri .= "?{$this->query}";
256
        }
257
258
        if (!empty($this->fragment)) {
259
            $uri .= "#{$this->fragment}";
260
        }
261
262
        return $uri;
263
    }
264
265
    /**
266
     * @return string
267
     */
268
    public function getRelativeUri()
269
    {
270
        $uri = '';
271
272
        if ('/' === $this->path) {
273
            $uri .= $this->explicitTrailingHostSlash ? '/' : '';
274
        } else {
275
            $uri .= $this->path;
276
        }
277
278
        return $uri;
279
    }
280
281
    /**
282
     * Uses protected user info by default as per rfc3986-3.2.1
283
     * Uri::getAbsoluteUri() is available if plain-text password information is desirable.
284
     *
285
     * @return string
286
     */
287
    public function __toString()
288
    {
289
        $uri = $this->scheme . '://' . $this->getAuthority();
290
291
        if ('/' === $this->path) {
292
            $uri .= $this->explicitTrailingHostSlash ? '/' : '';
293
        } else {
294
            $uri .= $this->path;
295
        }
296
297
        if (!empty($this->query)) {
298
            $uri .= "?{$this->query}";
299
        }
300
301
        if (!empty($this->fragment)) {
302
            $uri .= "#{$this->fragment}";
303
        }
304
305
        return $uri;
306
    }
307
308
    /**
309
     * @param $path
310
     */
311
    public function setPath($path)
312
    {
313
        if (empty($path)) {
314
            $this->path = '/';
315
            $this->explicitTrailingHostSlash = false;
316
        } else {
317
            $this->path = $path;
318
            if ('/' === $this->path) {
319
                $this->explicitTrailingHostSlash = true;
320
            }
321
        }
322
    }
323
324
    /**
325
     * @param string $query
326
     */
327
    public function setQuery($query)
328
    {
329
        $this->query = $query;
330
    }
331
332
    /**
333
     * @param string $var
334
     * @param string $val
335
     */
336
    public function addToQuery($var, $val)
337
    {
338
        if (strlen($this->query) > 0) {
339
            $this->query .= '&';
340
        }
341
        $this->query .= http_build_query(array($var => $val), '', '&');
342
    }
343
344
    /**
345
     * @param string $fragment
346
     */
347
    public function setFragment($fragment)
348
    {
349
        $this->fragment = $fragment;
350
    }
351
352
    /**
353
     * @param string $scheme
354
     */
355
    public function setScheme($scheme)
356
    {
357
        $this->scheme = $scheme;
358
    }
359
360
361
    /**
362
     * @param string $userInfo
363
     */
364
    public function setUserInfo($userInfo)
365
    {
366
        $this->userInfo = $userInfo ? $this->protectUserInfo($userInfo) : '';
367
        $this->rawUserInfo = $userInfo;
368
    }
369
370
371
    /**
372
     * @param int $port
373
     */
374
    public function setPort($port)
375
    {
376
        $this->port = intval($port);
377
378
        if (('https' === $this->scheme && $this->port === 443) || ('http' === $this->scheme && $this->port === 80)) {
379
            $this->explicitPortSpecified = false;
380
        } else {
381
            $this->explicitPortSpecified = true;
382
        }
383
    }
384
385
    /**
386
     * @param string $host
387
     */
388
    public function setHost($host)
389
    {
390
        $this->host = $host;
391
    }
392
393
    /**
394
     * @return bool
395
     */
396
    public function hasExplicitTrailingHostSlash()
397
    {
398
        return $this->explicitTrailingHostSlash;
399
    }
400
401
    /**
402
     * @return bool
403
     */
404
    public function hasExplicitPortSpecified()
405
    {
406
        return $this->explicitPortSpecified;
407
    }
408
}
409