URL::setGetVar()   F
last analyzed

Complexity

Conditions 12
Paths 642

Size

Total Lines 37
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 17
c 0
b 0
f 0
dl 0
loc 37
rs 3.2972
cc 12
nc 642
nop 3

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 Lifeboat\Utils;
4
5
use Lifeboat\Exceptions\InvalidArgumentException;
6
7
/**
8
 * Class URL
9
 * @package Lifeboat\Utils
10
 */
11
class URL {
12
13
    /**
14
     * @param string $key
15
     * @param string $value
16
     * @param string $url
17
     * @return string
18
     * @throws InvalidArgumentException If URL is malformed
19
     */
20
    public static function setGetVar(string $key, string $value, string $url): string
21
    {
22
        if (!self::is_absolute_url($url)) {
23
            $url = 'http://dummy.com/' . ltrim($url, '/');
24
        }
25
26
        // try to parse uri
27
        $parts = parse_url($url);
28
        if (empty($parts)) {
29
            throw new InvalidArgumentException("Can't parse URL: " . $url);
30
        }
31
32
        // Parse params and add new variable
33
        $params = [];
34
        if (array_key_exists('query', $parts)) {
35
            parse_str($parts['query'], $params);
36
        }
37
38
        $params[$key] = $value;
39
40
        // Generate URI segments and formatting
41
        $scheme = (array_key_exists('scheme', $parts)) ? $parts['scheme'] : 'http';
42
        $user = (array_key_exists('user', $parts)) ? $parts['user'] : '';
43
        $port = (array_key_exists('port', $parts) && $parts['port']) ? ':' . $parts['port'] : '';
44
45
        if ($user != '') {
46
            // format in either user:[email protected] or [email protected]
47
            $user .= (array_key_exists('pass', $parts) && $parts['pass']) ? ':' . $parts['pass'] . '@' : '';
48
        }
49
50
        // handle URL params which are existing / new
51
        $params = ($params) ? '?' . http_build_query($params) : '';
52
53
        // Recompile URI segments
54
        $newUri = $scheme . '://' . $user . $parts['host'] . $port . ($parts['path'] ?? '') . $params;
55
56
        return str_replace('http://dummy.com', '', $newUri);
57
    }
58
59
    /**
60
     * @param string $url
61
     * @return bool
62
     */
63
    public static function is_absolute_url(string $url): bool
64
    {
65
        // Strip off the query and fragment parts of the URL before checking
66
        if (($queryPosition = strpos($url, '?')) !== false) {
67
            $url = substr($url, 0, $queryPosition - 1);
68
        }
69
        if (($hashPosition = strpos($url, '#')) !== false) {
70
            $url = substr($url, 0, $hashPosition - 1);
71
        }
72
        $colonPosition = strpos($url, ':');
73
        $slashPosition = strpos($url, '/');
74
        return (
75
            // Base check for existence of a host on a compliant URL
76
            parse_url($url, PHP_URL_HOST)
77
            // Check for more than one leading slash without a protocol.
78
            // While not a RFC compliant absolute URL, it is completed to a valid URL by some browsers,
79
            // and hence a potential security risk. Single leading slashes are not an issue though.
80
            || preg_match('%^\s*/{2,}%', $url)
81
            || (
82
                // If a colon is found, check if it's part of a valid scheme definition
83
                // (meaning its not preceded by a slash).
84
                $colonPosition !== false
85
                && ($slashPosition === false || $colonPosition < $slashPosition)
86
            )
87
        );
88
    }
89
}
90