Issues (8)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/UrlComposer.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Retrinko\UrlComposer;
4
5
use Retrinko\UrlComposer\Exceptions\UrlException;
6
7
class UrlComposer
8
{
9
    const SCHEME_HTTP    = 'http';
10
    const PATH_SEPARATOR = '/';
11
12
    /**
13
     * @var string
14
     */
15
    protected $scheme = self::SCHEME_HTTP;
16
    /**
17
     * @var string
18
     */
19
    protected $user = '';
20
    /**
21
     * @var string
22
     */
23
    protected $pass = '';
24
    /**
25
     * @var string
26
     */
27
    protected $host = '';
28
    /**
29
     * @var int
30
     */
31
    protected $port;
32
    /**
33
     * @var array
34
     */
35
    protected $path = [];
36
    /**
37
     * @var array
38
     */
39
    protected $query = [];
40
    /**
41
     * @var string
42
     */
43
    protected $fragment = '';
44
45
    /**
46
     * Url constructor.
47
     *
48
     * @param string $url
49
     *
50
     * @throws UrlException
51
     */
52 13
    public function __construct($url = '')
53
    {
54 13 View Code Duplication
        if ('' != $url && false === filter_var($url, FILTER_VALIDATE_URL))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
55 13
        {
56 2
            throw new UrlException(sprintf('Invalid URL! (%s)', $url));
57
        }
58
59 11
        $this->parseUrlString($url);
60 11
    }
61
62
    /**
63
     * @param string $url
64
     */
65 11
    protected function parseUrlString($url)
66
    {
67
        // Parse URL
68 11
        $scheme = parse_url($url, PHP_URL_SCHEME);
69 11
        if (!is_null($scheme))
70 11
        {
71 8
            $this->scheme = $scheme;
0 ignored issues
show
Documentation Bug introduced by
It seems like $scheme can also be of type false. However, the property $scheme is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
72 8
        }
73
74 11
        $user = parse_url($url, PHP_URL_USER);
75 11
        if (!is_null($user))
76 11
        {
77
            $this->user = $user;
0 ignored issues
show
Documentation Bug introduced by
It seems like $user can also be of type false. However, the property $user is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
78
        }
79
80 11
        $pass = parse_url($url, PHP_URL_PASS);
81 11
        if (!is_null($pass))
82 11
        {
83
            $this->pass = $pass;
0 ignored issues
show
Documentation Bug introduced by
It seems like $pass can also be of type false. However, the property $pass is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
84
        }
85
86 11
        $host = parse_url($url, PHP_URL_HOST);
87 11
        if (!is_null($host))
88 11
        {
89 8
            $this->host = idn_to_utf8($host);
90 8
        }
91
92 11
        $this->port = parse_url($url, PHP_URL_PORT);
0 ignored issues
show
Documentation Bug introduced by
It seems like parse_url($url, PHP_URL_PORT) can also be of type false. However, the property $port is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
93
94 11
        $pathStr = parse_url($url, PHP_URL_PATH);
95 11
        if (!is_null($pathStr) && self::PATH_SEPARATOR != $pathStr)
96 11
        {
97 6
            $pathStr = trim($pathStr, self::PATH_SEPARATOR);
98 6
            $this->path = explode(self::PATH_SEPARATOR, $pathStr);
99 6
        }
100
101 11
        $queryStr = parse_url($url, PHP_URL_QUERY);
102 11
        if (!is_null($queryStr))
103 11
        {
104 1
            parse_str($queryStr, $query);
105 1
            $this->query = $query;
0 ignored issues
show
Documentation Bug introduced by
It seems like $query can be null. However, the property $query is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
106 1
        }
107
108 11
        $fragment = parse_url($url, PHP_URL_FRAGMENT);
109 11
        if (!is_null($fragment))
110 11
        {
111 1
            $this->fragment = $fragment;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fragment can also be of type false. However, the property $fragment is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
112 1
        }
113 11
    }
114
115
    /**
116
     * @param string $string
117
     *
118
     * @return $this
119
     * @throws UrlException
120
     */
121 3
    public function addToPath($string)
122
    {
123 3
        if (!is_string($string))
124 3
        {
125 1
            throw new UrlException('Invalid path part! Path part must be an string.');
126
        }
127
128 2
        $string = filter_var($string, FILTER_SANITIZE_ENCODED);
129 2
        if (false === $string)
130 2
        {
131
            throw new UrlException('Invalid URL chunck!');
132
        }
133
134 2
        if ('' == trim($string))
135 2
        {
136 1
            throw new UrlException('Path part can not be empty!');
137
        }
138
139 1
        $this->path[] = $string;
140
141 1
        return $this;
142
    }
143
144
    /**
145
     * @param string $key
146
     * @param string $value
147
     *
148
     * @return $this
149
     * @throws UrlException
150
     */
151 1
    public function addToQuery($key, $value)
152
    {
153 1
        if ('' == trim($key))
154 1
        {
155 1
            throw new UrlException('Query key can not be empty!');
156
        }
157
        $this->query[$key] = $value;
158
159
        return $this;
160
    }
161
162
    /**
163
     * @param $user
164
     * @param $pass
165
     *
166
     * @return $this
167
     */
168
    public function setUserInfo($user, $pass)
169
    {
170
        return $this->setUser($user)->setPass($pass);
171
    }
172
173
    /**
174
     * Reset auth, path, query & fragment
175
     * @return $this
176
     */
177
    public function reset()
178
    {
179
        $this->resetFragment();
180
        $this->resetPath();
181
        $this->resetQuery();
182
        $this->resetUserInfo();
183
184
        return $this;
185
    }
186
187
    /**
188
     * @return $this
189
     */
190
    public function resetFragment()
191
    {
192
        $this->fragment = null;
193
194
        return $this;
195
    }
196
197
    /**
198
     * @return $this
199
     */
200
    public function resetPath()
201
    {
202
        $this->path = [];
203
204
        return $this;
205
    }
206
207
    /**
208
     * @return $this
209
     */
210
    public function resetQuery()
211
    {
212
        $this->query = [];
213
214
        return $this;
215
    }
216
217
    /**
218
     * @return $this
219
     */
220
    public function resetUserInfo()
221
    {
222
        $this->user = null;
223
        $this->pass = null;
224
225
        return $this;
226
    }
227
228
    /**
229
     * @return string
230
     */
231 8
    public function getScheme()
232
    {
233 8
        return $this->scheme;
234
    }
235
236
    /**
237
     * @param string $scheme
238
     *
239
     * @return $this
240
     */
241 1
    public function setScheme($scheme)
242
    {
243 1
        $this->scheme = $scheme;
244
245 1
        return $this;
246
    }
247
248
    /**
249
     * @return string
250
     */
251 8
    public function getUserInfo()
252
    {
253 8
        if (!empty($this->getPass()) && !empty($this->getUser()))
254 8
        {
255 1
            $userInfo = sprintf('%s:%s', $this->getUser(), $this->getPass());
256 1
        }
257 7
        elseif (empty($this->getPass()) && !empty($this->getUser()))
258
        {
259
            $userInfo = $this->getUser();
260
        }
261
        else
262
        {
263 7
            $userInfo = '';
264
        }
265
266 8
        return $userInfo;
267
    }
268
269
    /**
270
     * @return string
271
     */
272 8
    public function getPass()
273
    {
274 8
        return $this->pass;
275
    }
276
277
    /**
278
     * @param string $pass
279
     *
280
     * @return $this
281
     */
282 1
    public function setPass($pass)
283
    {
284 1
        $this->pass = $pass;
285
286 1
        return $this;
287
    }
288
289
    /**
290
     * @return string
291
     */
292 8
    public function getUser()
293
    {
294 8
        return $this->user;
295
    }
296
297
    /**
298
     * @param string $user
299
     *
300
     * @return $this
301
     */
302 1
    public function setUser($user)
303
    {
304 1
        $this->user = $user;
305
306 1
        return $this;
307
    }
308
309
    /**
310
     * @return string
311
     */
312 8
    public function getHost()
313
    {
314 8
        return $this->host;
315
    }
316
317
    /**
318
     * @param string $host
319
     *
320
     * @return $this
321
     */
322 1
    public function setHost($host)
323
    {
324 1
        $this->host = idn_to_utf8($host);
325
326 1
        return $this;
327
    }
328
329
    /**
330
     * @return int
331
     */
332 8
    public function getPort()
333
    {
334 8
        return $this->port;
335
    }
336
337
    /**
338
     * @param int $port
339
     *
340
     * @return $this
341
     */
342 1
    public function setPort($port)
343
    {
344 1
        $this->port = $port;
345
346 1
        return $this;
347
    }
348
349
    /**
350
     * @param bool $asString
351
     *
352
     * @return array|string
353
     */
354 8
    public function getPath($asString = false)
355
    {
356 8
        $path = $this->path;
357 8
        if (true === $asString)
358 8
        {
359 8
            $path = implode(self::PATH_SEPARATOR, $path);
360 8
        }
361
362 8
        return $path;
363
    }
364
365
    /**
366
     * @param array $path
367
     *
368
     * @return $this
369
     */
370 1
    public function setPath(array $path)
371
    {
372 1
        $this->path = $path;
373
374 1
        return $this;
375
    }
376
377
    /**
378
     * @param bool $asString
379
     *
380
     * @return array|string
381
     */
382 8
    public function getQuery($asString = false)
383
    {
384 8
        $query = $this->query;
385 8
        if (true === $asString)
386 8
        {
387 8
            $query = http_build_query($query);
388 8
        }
389
390 8
        return $query;
391
    }
392
393
    /**
394
     * @param array $query Key-value array
395
     *
396
     * @return $this
397
     */
398 1
    public function setQuery(array $query)
399
    {
400 1
        $this->query = $query;
401
402 1
        return $this;
403
    }
404
405
    /**
406
     * @return string
407
     */
408 8
    public function getFragment()
409
    {
410 8
        return $this->fragment;
411
    }
412
413
    /**
414
     * @param string $fragment
415
     *
416
     * @return $this
417
     */
418 1
    public function setFragment($fragment)
419
    {
420 1
        $this->fragment = $fragment;
421
422 1
        return $this;
423
    }
424
425
    /**
426
     * @return string
427
     */
428 8
    protected function composeAuthority()
429
    {
430 8
        $userInfo = $this->getUserInfo();
431 8
        $port = $this->getPort();
432 8
        $host = $this->getHost();
433 8
        $authority = idn_to_ascii($host);
434 8
        if (!empty($userInfo))
435 8
        {
436 1
            $authority = sprintf('%s@%s', $userInfo, $authority);
437 1
        }
438 8
        if (!is_null($port))
439 8
        {
440 1
            $authority = sprintf('%s:%s', $authority, $port);
441 1
        }
442
443 8
        return $authority;
444
    }
445
446
    /**
447
     * @return string
448
     */
449 2
    public function __toString()
450
    {
451
        try
452
        {
453 2
            $url = $this->compose();
454
        }
455 2
        catch (\Exception $e)
456
        {
457 1
            $url = $e->getMessage();
458
        }
459
460 2
        return $url;
461
    }
462
463
    /**
464
     * @return string
465
     * @throws UrlException
466
     */
467 8
    public function compose()
468
    {
469 8
        $url = sprintf('%s://%s', $this->getScheme(), $this->composeAuthority());
470 8
        if (!empty($this->getPath(true)))
471 8
        {
472 4
            $url = sprintf('%s/%s', $url, $this->getPath(true));
473 4
        }
474 8
        if (!empty($this->getQuery(true)))
475 8
        {
476 2
            $url = sprintf('%s?%s', $url, $this->getQuery(true));
477 2
        }
478 8
        if (!empty($this->getFragment()))
479 8
        {
480 2
            $url = sprintf('%s#%s', $url, $this->getFragment());
481 2
        }
482
483 8 View Code Duplication
        if (false === filter_var($url, FILTER_VALIDATE_URL))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
484 8
        {
485 2
            throw new UrlException(sprintf('URL composition error! Please check your data. ' .
486 2
                                           'The composition result is an invalid URL: "%s"',
487 2
                                           $url));
488
        }
489
490 6
        return $url;
491
    }
492
}