Completed
Push — master ( 6b8416...c520c0 )
by Filipe
02:12
created

Uri::__toString()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 16
nop 0
1
<?php
2
3
/**
4
 * This file is part of slick/http
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Http\Message;
11
12
use Psr\Http\Message\UriInterface;
13
use Slick\Http\Message\Exception\InvalidArgumentException;
14
15
/**
16
 * Uri
17
 *
18
 * @package Slick\Http\Message
19
*/
20
class Uri implements UriInterface
21
{
22
23
    private $defaultPorts = [
24
        'http' => 80,
25
        'https' => 443
26
    ];
27
28
    /**
29
     * @var string
30
     */
31
    private $scheme;
32
33
    /**
34
     * @var string
35
     */
36
    private $host;
37
38
    /**
39
     * @var string
40
     */
41
    private $port;
42
43
    /**
44
     * @var string
45
     */
46
    private $user;
47
48
    /**
49
     * @var string
50
     */
51
    private $pass;
52
53
    /**
54
     * @var string
55
     */
56
    private $path;
57
58
    /**
59
     * @var string
60
     */
61
    private $query;
62
63
    /**
64
     * @var string
65
     */
66
    private $fragment;
67
68
    /**
69
     * Creates an URI
70
     *
71
     * @param string $url
72
     *
73
     * @throws InvalidArgumentException if provided URL is not a valid URL
74
     *      according to PHP FILTER_VALIDATE_URL
75
     * @see http://php.net/manual/en/filter.filters.validate.php
76
     */
77
    public function __construct($url)
78
    {
79
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
80
            throw new InvalidArgumentException(
81
                "The URL entered is invalid. URI cannot be created."
82
            );
83
        }
84
85
        foreach (parse_url($url) as $property => $value) {
0 ignored issues
show
Bug introduced by
The expression parse_url($url) of type array<string,string>|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
86
            $this->$property = $value;
87
        }
88
    }
89
90
    /**
91
     * Retrieve the scheme component of the URI.
92
     *
93
     * @see https://tools.ietf.org/html/rfc3986#section-3.1
94
     * @return string The URI scheme.
95
     */
96
    public function getScheme()
97
    {
98
        return strtolower($this->scheme);
99
    }
100
101
    /**
102
     * Retrieve the authority component of the URI.
103
     *
104
     * @return string The URI authority, in "[user-info@]host[:port]" format.
105
     */
106
    public function getAuthority()
107
    {
108
        $authority = $this->getUserInfo() !== ''
109
            ? "{$this->getUserInfo()}@{$this->getHost()}"
110
            : "{$this->getHost()}";
111
        return $this->getPort() ? "{$authority}:{$this->getPort()}" : $authority;
112
    }
113
114
    /**
115
     * Retrieve the user information component of the URI.
116
     *
117
     * @return string The URI user information, in "username[:password]" format.
118
     */
119
    public function getUserInfo()
120
    {
121
        $userInfo = $this->user ? $this->user : '';
122
        return $this->pass ? "{$userInfo}:{$this->pass}" : $userInfo;
123
    }
124
125
    /**
126
     * Retrieve the host component of the URI.
127
     *
128
     * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
129
     * @return string The URI host.
130
     */
131
    public function getHost()
132
    {
133
        return strtolower($this->host);
134
    }
135
136
    /**
137
     * Retrieve the port component of the URI.
138
     *
139
     * @return null|int The URI port.
140
     */
141
    public function getPort()
142
    {
143
        $default = array_key_exists($this->getScheme(), $this->defaultPorts)
144
            ? $this->defaultPorts[$this->getScheme()]
145
            : -1;
146
147
        if ($default === $this->port) {
148
            return null;
149
        }
150
151
        return (int) $this->port;
152
    }
153
154
    /**
155
     * Retrieve the path component of the URI.
156
     *
157
     * @see https://tools.ietf.org/html/rfc3986#section-2
158
     * @see https://tools.ietf.org/html/rfc3986#section-3.3
159
     * @return string The URI path.
160
     */
161
    public function getPath()
162
    {
163
        return $this->path;
164
    }
165
166
    /**
167
     * Retrieve the query string of the URI.
168
     *
169
     * @see https://tools.ietf.org/html/rfc3986#section-2
170
     * @see https://tools.ietf.org/html/rfc3986#section-3.4
171
     * @return string The URI query string.
172
     */
173
    public function getQuery()
174
    {
175
        return $this->query;
176
    }
177
178
    /**
179
     * Retrieve the fragment component of the URI.
180
     *
181
     * @see https://tools.ietf.org/html/rfc3986#section-2
182
     * @see https://tools.ietf.org/html/rfc3986#section-3.5
183
     * @return string The URI fragment.
184
     */
185
    public function getFragment()
186
    {
187
        return $this->fragment ? $this->fragment : '';
188
    }
189
190
    /**
191
     * Return an instance with the specified scheme.
192
     *
193
     * @param string $scheme The scheme to use with the new instance.
194
     * @return static A new instance with the specified scheme.
195
     * @throws \InvalidArgumentException for invalid or unsupported schemes.
196
     */
197
    public function withScheme($scheme)
198
    {
199
        $this->validateCharacters($scheme);
200
201
        $uri = clone $this;
202
        $uri->scheme = $scheme;
203
        return $uri;
204
    }
205
206
    /**
207
     * Return an instance with the specified user information.
208
     *
209
     * @param string $user The user name to use for authority.
210
     * @param null|string $password The password associated with $user.
211
     * @return static A new instance with the specified user information.
212
     */
213
    public function withUserInfo($user, $password = null)
214
    {
215
        $uri = clone $this;
216
        $uri->user = $user;
217
        $uri->pass = $password;
218
        return $uri;
219
    }
220
221
    /**
222
     * Return an instance with the specified host.
223
     *
224
     * @param string $host The hostname to use with the new instance.
225
     * @return static A new instance with the specified host.
226
     * @throws \InvalidArgumentException for invalid hostnames.
227
     */
228
    public function withHost($host)
229
    {
230
        $this->validateCharacters($host);
231
232
        $uri = clone $this;
233
        $uri->host = $host;
234
        return $uri;
235
    }
236
237
    /**
238
     * Return an instance with the specified port.
239
     *
240
     * @param null|int $port The port to use with the new instance; a null value
241
     *     removes the port information.
242
     * @return static A new instance with the specified port.
243
     * @throws \InvalidArgumentException for invalid ports.
244
     */
245
    public function withPort($port)
246
    {
247
        $uri = clone $this;
248
        $uri->port = (int) $port;
0 ignored issues
show
Documentation Bug introduced by
The property $port was declared of type string, but (int) $port is of type integer. 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...
249
        return $uri;
250
    }
251
252
    /**
253
     * Return an instance with the specified path.
254
     *
255
     * @param string $path The path to use with the new instance.
256
     * @return static A new instance with the specified path.
257
     * @throws \InvalidArgumentException for invalid paths.
258
     */
259
    public function withPath($path)
260
    {
261
        $uri = clone $this;
262
        $uri->path = $path;
263
        return $uri;
264
    }
265
266
    /**
267
     * Return an instance with the specified query string.
268
     *
269
     * An empty query string value is equivalent to removing the query string.
270
     *
271
     * @param string $query The query string to use with the new instance.
272
     * @return static A new instance with the specified query string.
273
     * @throws \InvalidArgumentException for invalid query strings.
274
     */
275
    public function withQuery($query)
276
    {
277
        $uri = clone $this;
278
        $uri->query = $query;
279
        return $uri;
280
    }
281
282
    /**
283
     * Return an instance with the specified URI fragment.
284
     *
285
     * An empty fragment value is equivalent to removing the fragment.
286
     *
287
     * @param string $fragment The fragment to use with the new instance.
288
     * @return static A new instance with the specified fragment.
289
     */
290
    public function withFragment($fragment)
291
    {
292
        $uri = clone $this;
293
        $uri->fragment = $fragment;
294
        return $uri;
295
    }
296
297
    /**
298
     * Return the string representation as a URI reference.
299
     *
300
     * @see http://tools.ietf.org/html/rfc3986#section-4.1
301
     * @return string
302
     */
303
    public function __toString()
304
    {
305
        $text  = $this->scheme ? "{$this->getScheme()}:" : '';
306
        $text .= $this->getAuthority() !== ''
307
            ? "//{$this->getAuthority()}"
308
            : '';
309
        $text .= '/'. ltrim($this->getPath(), '/');
310
        $text .= strlen($this->query) > 0 ? "?{$this->query}" : '';
311
        $text .= strlen($this->fragment) > 0 ? "#{$this->fragment}" : '';
312
        return $text;
313
    }
314
315
    /**
316
     * Check the provided text for invalid characters
317
     *
318
     * @param string $text
319
     */
320
    private function validateCharacters($text)
321
    {
322
        $regex = '/^[a-z]{1}[a-z0-9\.\+\-]*/i';
323
        if ($text !== '' && ! preg_match($regex, $text)) {
324
            throw new InvalidArgumentException(
325
                "Invalid characters used in URI."
326
            );
327
        }
328
    }
329
}