Completed
Push — master ( a58e9f...ade25e )
by Derek
02:18
created

Uri::getPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.4285
cc 2
eloc 8
nc 2
nop 0
crap 2
1
<?php
2
namespace Subreality\Dilmun\Anshar\Http;
3
4
use Psr\Http\Message\UriInterface;
5
use Subreality\Dilmun\Anshar\Http\UriParts\Authority;
6
use Subreality\Dilmun\Anshar\Http\UriParts\Fragment;
7
use Subreality\Dilmun\Anshar\Http\UriParts\Host;
8
use Subreality\Dilmun\Anshar\Http\UriParts\Port;
9
use Subreality\Dilmun\Anshar\Http\UriParts\Query;
10
use Subreality\Dilmun\Anshar\Http\UriParts\Scheme;
11
use Subreality\Dilmun\Anshar\Http\UriParts\UserInfo;
12
use Subreality\Dilmun\Anshar\Utils\ArrayHelper;
13
use Subreality\Dilmun\Anshar\Utils\StringHelper;
14
15
/**
16
 * Class Uri
17
 * @package Subreality\Dilmun\Anshar\Http
18
 */
19
class Uri implements UriInterface
20
{
21
    use SchemePortsTrait;
22
23
    protected $uri_parts = array(
24
        "scheme"    => "",
25
        "hier_part" => "",
26
        "authority" => "",
27
        "user_info" => "",
28
        "host"      => "",
29
        "port"      => null,
30
        "path"      => "",
31
        "query"     => "",
32
        "fragment"  => "",
33
    );
34
35
    /** @var  Scheme */
36
    protected $scheme;
37
    /** @var  Authority */
38
    protected $authority;
39
    /** @var  UserInfo */
40
    protected $user_info;
41
    /** @var  Host */
42
    protected $host;
43
    /** @var  Port */
44
    protected $port;
45
    /** @var  Query */
46
    protected $query;
47
    /** @var  Fragment */
48
    protected $fragment;
49
50
    protected $sub_delims = array(
51
        "!",
52
        "$",
53
        "&",
54
        "'",
55
        "(",
56
        ")",
57
        "*",
58
        "+",
59
        ",",
60
        ";",
61
        "=",
62
    );
63
64
    protected $pchar_unencoded = array(
65
        ":",
66
        "@",
67
    );
68
69
    /**
70
     * Uri constructor.  Accepts a string representing a URI and parses the string into the URI's component parts.
71
     *
72
     * @throws \InvalidArgumentException    Throws an \InvalidArgumentException when its parameter is not a string
73
     * @param string $uri
74
     */
75 101
    public function __construct($uri)
76
    {
77 101
        if (!is_string($uri)) {
78 6
            throw new \InvalidArgumentException("New Uri objects must be constructed with a string URI");
79
        }
80
81 95
        $this->explodeUri($uri);
82 95
    }
83
84
    /**
85
     * Retrieve the parsed components of the URI string.
86
     *
87
     * If the class was provided an invalid or empty URI string, URI components will be empty strings, except port,
88
     * which will be null
89
     *
90
     * @return mixed[]
91
     */
92 55
    public function getParsedUri()
93
    {
94 55
        return $this->uri_parts;
95
    }
96
97
    /**
98
     * Retrieve the scheme component of the URI.
99
     *
100
     * If no scheme is present, this method MUST return an empty string.
101
     *
102
     * The value returned MUST be normalized to lowercase, per RFC 3986
103
     * Section 3.1.
104
     *
105
     * The trailing ":" character is not part of the scheme and MUST NOT be
106
     * added.
107
     *
108
     * @see https://tools.ietf.org/html/rfc3986#section-3.1
109
     * @return string The URI scheme.
110
     */
111 3
    public function getScheme()
112
    {
113 3
        return (string) $this->scheme;
114
    }
115
116
    /**
117
     * Retrieve the authority component of the URI.
118
     *
119
     * If no authority information is present, this method MUST return an empty
120
     * string.
121
     *
122
     * The authority syntax of the URI is:
123
     *
124
     * <pre>
125
     * [user-info@]host[:port]
126
     * </pre>
127
     *
128
     * If the port component is not set or is the standard port for the current
129
     * scheme, it SHOULD NOT be included.
130
     *
131
     * @see https://tools.ietf.org/html/rfc3986#section-3.2
132
     * @return string The URI authority, in "[user-info@]host[:port]" format.
133
     */
134 4
    public function getAuthority()
135
    {
136 4
        return $this->user_info->toUriString() . $this->host->toUriString() . $this->port->toUriString($this->scheme);
137
    }
138
139
    /**
140
     * Retrieve the user information component of the URI.
141
     *
142
     * If no user information is present, this method MUST return an empty
143
     * string.
144
     *
145
     * If a user is present in the URI, this will return that value;
146
     * additionally, if the password is also present, it will be appended to the
147
     * user value, with a colon (":") separating the values.
148
     *
149
     * The trailing "@" character is not part of the user information and MUST
150
     * NOT be added.
151
     *
152
     * @return string The URI user information, in "username[:password]" format.
153
     */
154 2
    public function getUserInfo()
155
    {
156 2
        return (string) $this->user_info;
157
    }
158
159
    /**
160
     * Retrieve the host component of the URI.
161
     *
162
     * If no host is present, this method MUST return an empty string.
163
     *
164
     * The value returned MUST be normalized to lowercase, per RFC 3986
165
     * Section 3.2.2.
166
     *
167
     * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
168
     * @return string The URI host.
169
     */
170 3
    public function getHost()
171
    {
172 3
        return (string) $this->host;
173
    }
174
175
    /**
176
     * Retrieve the port component of the URI.
177
     *
178
     * If a port is present, and it is non-standard for the current scheme,
179
     * this method MUST return it as an integer. If the port is the standard port
180
     * used with the current scheme, this method SHOULD return null.
181
     *
182
     * If no port is present, and no scheme is present, this method MUST return
183
     * a null value.
184
     *
185
     * If no port is present, but a scheme is present, this method MAY return
186
     * the standard port for that scheme, but SHOULD return null.
187
     *
188
     * @return null|int The URI port.
189
     */
190 4
    public function getPort()
191
    {
192 4
        $normalized_port = $this->port->normalizePortAgainstScheme($this->scheme);
193
194 4
        return $normalized_port;
195
    }
196
197
    /**
198
     * Retrieve the path component of the URI.
199
     *
200
     * The path can either be empty or absolute (starting with a slash) or
201
     * rootless (not starting with a slash). Implementations MUST support all
202
     * three syntaxes.
203
     *
204
     * Normally, the empty path "" and absolute path "/" are considered equal as
205
     * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
206
     * do this normalization because in contexts with a trimmed base path, e.g.
207
     * the front controller, this difference becomes significant. It's the task
208
     * of the user to handle both "" and "/".
209
     *
210
     * The value returned MUST be percent-encoded, but MUST NOT double-encode
211
     * any characters. To determine what characters to encode, please refer to
212
     * RFC 3986, Sections 2 and 3.3.
213
     *
214
     * As an example, if the value should include a slash ("/") not intended as
215
     * delimiter between path segments, that value MUST be passed in encoded
216
     * form (e.g., "%2F") to the instance.
217
     *
218
     * @see https://tools.ietf.org/html/rfc3986#section-2
219
     * @see https://tools.ietf.org/html/rfc3986#section-3.3
220
     * @return string The URI path.
221
     */
222 8
    public function getPath()
223
    {
224 8
        $path_unencoded = array("/");
225 8
        $allowed        = implode($this->pchar_unencoded) . implode($this->sub_delims) . implode($path_unencoded);
226
227 8
        if ($this->containsUnallowedUriCharacters($this->uri_parts["path"], $allowed)) {
228 4
            $encoded_string = $this->encodeComponent($this->uri_parts["path"], $path_unencoded);
229
230 4
            return $encoded_string;
231
        } else {
232 4
            return $this->uri_parts["path"];
233
        }
234
    }
235
236
    /**
237
     * Retrieve the query string of the URI.
238
     *
239
     * If no query string is present, this method MUST return an empty string.
240
     *
241
     * The leading "?" character is not part of the query and MUST NOT be
242
     * added.
243
     *
244
     * The value returned MUST be percent-encoded, but MUST NOT double-encode
245
     * any characters. To determine what characters to encode, please refer to
246
     * RFC 3986, Sections 2 and 3.4.
247
     *
248
     * As an example, if a value in a key/value pair of the query string should
249
     * include an ampersand ("&") not intended as a delimiter between values,
250
     * that value MUST be passed in encoded form (e.g., "%26") to the instance.
251
     *
252
     * @see https://tools.ietf.org/html/rfc3986#section-2
253
     * @see https://tools.ietf.org/html/rfc3986#section-3.4
254
     * @return string The URI query string.
255
     */
256 4
    public function getQuery()
257
    {
258 4
        return (string) $this->query;
259
    }
260
261
    /**
262
     * Retrieve the fragment component of the URI.
263
     *
264
     * If no fragment is present, this method MUST return an empty string.
265
     *
266
     * The leading "#" character is not part of the fragment and MUST NOT be
267
     * added.
268
     *
269
     * The value returned MUST be percent-encoded, but MUST NOT double-encode
270
     * any characters. To determine what characters to encode, please refer to
271
     * RFC 3986, Sections 2 and 3.5.
272
     *
273
     * @see https://tools.ietf.org/html/rfc3986#section-2
274
     * @see https://tools.ietf.org/html/rfc3986#section-3.5
275
     * @return string The URI fragment.
276
     */
277 4
    public function getFragment()
278
    {
279 4
        return (string) $this->fragment;
280
    }
281
282
    /**
283
     * Return an instance with the specified scheme.
284
     *
285
     * This method MUST retain the state of the current instance, and return
286
     * an instance that contains the specified scheme.
287
     *
288
     * Implementations MUST support the schemes "http" and "https" case
289
     * insensitively, and MAY accommodate other schemes if required.
290
     *
291
     * An empty scheme is equivalent to removing the scheme.
292
     *
293
     * @param string $scheme The scheme to use with the new instance.
294
     * @return static A new instance with the specified scheme.
0 ignored issues
show
Documentation introduced by
Should the return type not be Uri|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
295
     * @throws \InvalidArgumentException for invalid or unsupported schemes.
296
     */
297
    public function withScheme($scheme)
298
    {
299
        // TODO: Implement withScheme() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
300
    }
301
302
    /**
303
     * Return an instance with the specified authority.
304
     *
305
     * This method MUST retain the state of the current instance, and return
306
     * an instance that contains the specified authority.
307
     *
308
     * Replacing the authority is equivalent to replacing or removing all authority components depending upon the
309
     * composition of the authority.
310
     *
311
     * An empty authority is equivalent to removing the authority and all authority components.
312
     *
313
     * @param string $authority The scheme to use with the new instance.
314
     * @return static A new instance with the specified authority.
315
     * @throws \InvalidArgumentException for invalid authorities.
316
     */
317 21
    public function withAuthority($authority)
318
    {
319 21
        $with_authority = new Authority($authority);
320
321 15
        $uri_parts              = $this->uri_parts;
322 15
        $uri_parts["authority"] = (string) $with_authority;
323
324 15
        $new_authority_string = $this->toString($uri_parts);
325
326 15
        $new_authority_uri = new Uri($new_authority_string);
327
328 15
        return $new_authority_uri;
329
    }
330
331
    /**
332
     * Return an instance with the specified user information.
333
     *
334
     * This method MUST retain the state of the current instance, and return
335
     * an instance that contains the specified user information.
336
     *
337
     * Password is optional, but the user information MUST include the
338
     * user; an empty string for the user is equivalent to removing user
339
     * information.
340
     *
341
     * @param string $user The user name to use for authority.
342
     * @param null|string $password The password associated with $user.
343
     * @return static A new instance with the specified user information.
0 ignored issues
show
Documentation introduced by
Should the return type not be Uri|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
344
     */
345
    public function withUserInfo($user, $password = null)
346
    {
347
        // TODO: Implement withUserInfo() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
348
    }
349
350
    /**
351
     * Return an instance with the specified host.
352
     *
353
     * This method MUST retain the state of the current instance, and return
354
     * an instance that contains the specified host.
355
     *
356
     * An empty host value is equivalent to removing the host.
357
     *
358
     * @param string $host The hostname to use with the new instance.
359
     * @return static A new instance with the specified host.
0 ignored issues
show
Documentation introduced by
Should the return type not be Uri|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
360
     * @throws \InvalidArgumentException for invalid hostnames.
361
     */
362
    public function withHost($host)
363
    {
364
        // TODO: Implement withHost() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
365
    }
366
367
    /**
368
     * Return an instance with the specified port.
369
     *
370
     * This method MUST retain the state of the current instance, and return
371
     * an instance that contains the specified port.
372
     *
373
     * Implementations MUST raise an exception for ports outside the
374
     * established TCP and UDP port ranges.
375
     *
376
     * A null value provided for the port is equivalent to removing the port
377
     * information.
378
     *
379
     * @param null|int $port The port to use with the new instance; a null value
380
     *     removes the port information.
381
     * @return static A new instance with the specified port.
0 ignored issues
show
Documentation introduced by
Should the return type not be Uri|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
382
     * @throws \InvalidArgumentException for invalid ports.
383
     */
384
    public function withPort($port)
385
    {
386
        // TODO: Implement withPort() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
387
    }
388
389
    /**
390
     * Return an instance with the specified path.
391
     *
392
     * This method MUST retain the state of the current instance, and return
393
     * an instance that contains the specified path.
394
     *
395
     * The path can either be empty or absolute (starting with a slash) or
396
     * rootless (not starting with a slash). Implementations MUST support all
397
     * three syntaxes.
398
     *
399
     * If the path is intended to be domain-relative rather than path relative then
400
     * it must begin with a slash ("/"). Paths not starting with a slash ("/")
401
     * are assumed to be relative to some base path known to the application or
402
     * consumer.
403
     *
404
     * Users can provide both encoded and decoded path characters.
405
     * Implementations ensure the correct encoding as outlined in getPath().
406
     *
407
     * @param string $path The path to use with the new instance.
408
     * @return static A new instance with the specified path.
409
     * @throws \InvalidArgumentException for invalid paths.
410
     */
411 18
    public function withPath($path)
412
    {
413 18
        if (!is_string($path)) {
414 6
            throw new \InvalidArgumentException("Supplied path must be a string");
415
        }
416
417 12
        $uri_parts          = $this->uri_parts;
418 12
        $uri_parts["path"]  = $path;
419 12
        $path_string_helper = new StringHelper($path);
420
421 12
        if (!empty($uri_parts["authority"]) && !empty($path) && !$path_string_helper->startsWith("/")) {
422 1
            throw new \InvalidArgumentException("Cannot create a URI with an authority given a rootless path");
423
        }
424
425 11
        $new_path_string = $this->toString($uri_parts);
426
427 11
        $new_path_uri = new Uri($new_path_string);
428
429 11
        return $new_path_uri;
430
    }
431
432
    /**
433
     * Return an instance with the specified query string.
434
     *
435
     * This method MUST retain the state of the current instance, and return
436
     * an instance that contains the specified query string.
437
     *
438
     * Users can provide both encoded and decoded query characters.
439
     * Implementations ensure the correct encoding as outlined in getQuery().
440
     *
441
     * An empty query string value is equivalent to removing the query string.
442
     *
443
     * @param string $query The query string to use with the new instance.
444
     * @return static A new instance with the specified query string.
0 ignored issues
show
Documentation introduced by
Should the return type not be Uri|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
445
     * @throws \InvalidArgumentException for invalid query strings.
446
     */
447
    public function withQuery($query)
448
    {
449
        // TODO: Implement withQuery() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
450
    }
451
452
    /**
453
     * Return an instance with the specified URI fragment.
454
     *
455
     * This method MUST retain the state of the current instance, and return
456
     * an instance that contains the specified URI fragment.
457
     *
458
     * Users can provide both encoded and decoded fragment characters.
459
     * Implementations ensure the correct encoding as outlined in getFragment().
460
     *
461
     * An empty fragment value is equivalent to removing the fragment.
462
     *
463
     * @param string $fragment The fragment to use with the new instance.
464
     * @return static A new instance with the specified fragment.
0 ignored issues
show
Documentation introduced by
Should the return type not be Uri|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
465
     */
466
    public function withFragment($fragment)
467
    {
468
        // TODO: Implement withFragment() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
469
    }
470
471
    /**
472
     * Return the string representation as a URI reference.
473
     *
474
     * Depending on which components of the URI are present, the resulting
475
     * string is either a full URI or relative reference according to RFC 3986,
476
     * Section 4.1. The method concatenates the various components of the URI,
477
     * using the appropriate delimiters:
478
     *
479
     * - If a scheme is present, it MUST be suffixed by ":".
480
     * - If an authority is present, it MUST be prefixed by "//".
481
     * - The path can be concatenated without delimiters. But there are two
482
     *   cases where the path has to be adjusted to make the URI reference
483
     *   valid as PHP does not allow to throw an exception in __toString():
484
     *     - If the path is rootless and an authority is present, the path MUST
485
     *       be prefixed by "/".
486
     *     - If the path is starting with more than one "/" and no authority is
487
     *       present, the starting slashes MUST be reduced to one.
488
     * - If a query is present, it MUST be prefixed by "?".
489
     * - If a fragment is present, it MUST be prefixed by "#".
490
     *
491
     * @see http://tools.ietf.org/html/rfc3986#section-4.1
492
     * @return string
493
     */
494 8
    public function __toString()
495
    {
496 8
        return $this->toString($this->uri_parts);
497
    }
498
499
    /**
500
     * @todo Maybe make static?
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
501
     * Converts a given array of URI parts to a string according to the specification of the __toString magic method
502
     *
503
     * @see Uri::__toString
504
     *
505
     * @param array $uri_parts  The URI parts to be combined into a string
506
     * @return string           The string combined from the array of URI parts
507
     */
508 31
    private function toString(array $uri_parts)
509
    {
510 31
        $uri_string = "";
511
512 31
        $uri_string .= $this->scheme->toUriString();
513
514 31
        $uri_string .= $this->authorityToString($uri_parts["authority"]);
515
516 31
        $uri_string .= $this->pathToString($uri_parts["path"], $uri_parts["authority"]);
517
518 31
        $uri_string .= $this->query->toUriString();
519
520 31
        $uri_string .= $this->fragment->toUriString();
521
522 31
        return $uri_string;
523
    }
524
525
    /**
526
     * Splits a string URI into its component parts, returning true if the URI string matches a valid URI's syntax
527
     * and false if the URI string does not
528
     *
529
     * @param string $uri   The URI string to be decomposed
530
     * @return bool         Returns true if the URI string matches a valid URI's syntax
531
     *                      Returns false otherwise
532
     */
533 95
    private function explodeUri($uri)
534
    {
535 95
        $reg_start     = '/^';
536 95
        $scheme_part   = '(?:(?\'scheme\'[A-Za-z0-9][^\/\?#:]+):)?';
537 95
        $hier_part     = '(?\'hier_part\'[^\?#]+)?';
538 95
        $query_part    = '(?:\?(?\'query\'[^#]*))?';
539 95
        $fragment_part = '(?:#(?\'fragment\'.*))?';
540 95
        $reg_end       = '/';
541
542 95
        $uri_syntax = $reg_start . $scheme_part . $hier_part . $query_part . $fragment_part . $reg_end;
543
544 95
        $uri_valid = preg_match($uri_syntax, $uri, $parts);
545
546 95
        $this->uri_parts = array_merge($this->uri_parts, $parts); //overwriting default values with matches
547
548 95
        $this->explodeHierParts($this->uri_parts["hier_part"]);
549
550 95
        $this->scheme    = new Scheme($this->uri_parts["scheme"]);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 4 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
551 95
        $this->query     = new Query($this->uri_parts["query"]);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 5 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
552 95
        $this->fragment  = new Fragment($this->uri_parts["fragment"]);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 1 space but found 2 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
553
554 95
        $this->sanitizeUriPartsArray();
555
556 95
        return (bool) $uri_valid;
557
    }
558
559
    /**
560
     * Splits URI hierarchy data into authority and path data.
561
     *
562
     * @param string $hier_part     The hierarchy part of a URI to be decomposed
563
     * @return void
564
     */
565 95
    private function explodeHierParts($hier_part)
566
    {
567
        $hier_parts      = array(
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 6 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
568 95
            "authority" => "",
569 95
            "path"      => "",
570 95
        );
571
572 95
        $reg_start      = '/^';
573 95
        $authority_part = '(?:(?:\/\/)(?\'authority\'.[^\/]+))?';
574 95
        $path_part      = '(?\'path\'.+)?';
575 95
        $reg_end        = '/';
576
577 95
        $hier_part_syntax = $reg_start . $authority_part . $path_part . $reg_end;
578
579 95
        preg_match($hier_part_syntax, $hier_part, $matches);
580
581 95
        $hier_parts = array_merge($hier_parts, $matches);
582
583 95
        $this->authority = new Authority($hier_parts["authority"]);
584 95
        $this->user_info = $this->authority->getUserInfo();
585 95
        $this->host = $this->authority->getHost();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
586 95
        $this->port = $this->authority->getPort();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
587
588 95
        $this->uri_parts["user_info"] = (string) $this->user_info;
589 95
        $this->uri_parts["host"] = (string) $this->host;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
590 95
        $this->uri_parts["port"] = $this->port->getPort();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
591
592 95
        $this->uri_parts = array_merge($this->uri_parts, $hier_parts);
593 95
    }
594
595
    /**
596
     * Sanitizes the URI component array by removing redundant key/value pairs
597
     *
598
     * @return void
599
     */
600 95
    private function sanitizeUriPartsArray()
601
    {
602 95
        $uri_part_array = new ArrayHelper($this->uri_parts);
603
604 95
        $this->uri_parts = $uri_part_array->removeNumericKeys();
605 95
    }
606
607
    /**
608
     * Percent encodes a component string except for sub-delims and unencoded pchar characters as defined by RFC 3986
609
     * in addition to any component-specific unencoded characters
610
     *
611
     * @param string $component_string          The string representing a URI component
612
     * @param string[] $component_unencoded     [OPTIONAL] Any additional unencoded characters specific to the component
613
     *
614
     * @return string                           The string with appropriate characters percent-encoded
615
     */
616 4
    private function encodeComponent($component_string, array $component_unencoded = array())
617
    {
618 4
        $uri_unencoded = array_merge($component_unencoded, $this->sub_delims, $this->pchar_unencoded);
619
620 4
        $string_helper = new StringHelper($component_string);
621
622 4
        $encoded_string = $string_helper->affectChunks("rawurlencode", ...$uri_unencoded);
623
624 4
        return $encoded_string;
625
    }
626
627
    /**
628
     * Determines whether a string contains unallowed URI characters, provided a string of allowed characters for a
629
     * given component.
630
     *
631
     * Note that a percent-encoded character (e.g. %20 for space) automatically counts as an allowed character, whereas
632
     * a percent sign not followed by two hex digits (e.g. %2X) does not count as an allowed character.
633
     *
634
     * @param string $string    The string to be checked for unallowed characters
635
     * @param string $allowed   A string containing all allowed characters for a given component
636
     *
637
     * @return bool             Returns true if the string contains unallowed characters
638
     *                          Returns false if the string contains only allowed characters (including percent-encoded
639
     *                          characters)
640
     */
641 8
    private function containsUnallowedUriCharacters($string, $allowed)
642
    {
643 8
        $allowed = preg_quote($allowed, "/");
644
645 8
        $pattern = "/^([0-9a-zA-Z\\.\\-_~{$allowed}]|%[0-9a-fA-F]{2})*\$/";
646
647 8
        $matches_allowed = preg_match($pattern, $string);
648
649 8
        return (bool) !$matches_allowed;
650
    }
651
652
    /**
653
     * Returns the appropriate authority string based upon __toString specification rules.
654
     *
655
     * @see Uri::__toString()
656
     *
657
     * @param string $authority     The authority to compile into a URI-friendly string
658
     *
659
     * @return string               The URI-friendly authority string
660
     */
661 31
    private function authorityToString($authority)
662
    {
663 31
        $authority_string = "";
664
665 31
        if (!empty($authority)) {
666 23
            $authority_string .= "//" . $authority;
667 23
        }
668
669 31
        return $authority_string;
670
    }
671
672
    /**
673
     * Returns the appropriate path string based upon __toString specification rules.
674
     *
675
     * @see Uri::__toString()
676
     *
677
     * @param string $path          The path to compile into a URI-friendly string
678
     * @param string $authority     [optional] The authority of the URI
679
     *
680
     * @return string               The URI-friendly path string
681
     */
682 31
    private function pathToString($path, $authority = "")
683
    {
684 31
        $path_string        = "";
685 31
        $path_string_helper = new StringHelper($path);
686
687 31
        if (empty($authority)) {
688 9
            $collapsed_slashes = $path_string_helper->collapseStartingRepetition("/");
689
690 9
            $path_string .= $collapsed_slashes;
691 31
        } elseif (!empty($path)) {
692 21
            if (!$path_string_helper->startsWith("/")) {
693 1
                $path_string .= "/" . $path;
694 1
            } else {
695 21
                $path_string .= $path;
696
            }
697 21
        }
698
699 31
        return $path_string;
700
    }
701
}
702