Passed
Push — master ( 5615a0...6723a4 )
by Nico
02:32
created

URL::urlHasScheme()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
3
/**
4
 * @license  http://opensource.org/licenses/mit-license.php MIT
5
 * @link     https://github.com/nicoSWD
6
 * @author   Nicolas Oelgart <[email protected]>
7
 */
8
namespace nicoSWD\SecHeaderCheck\Domain\URL;
9
10
use nicoSWD\SecHeaderCheck\Domain\Header\HttpHeader;
11
12
final class URL
13
{
14
    private const SCHEME_HTTPS = 'https';
15
    private const SCHEME_HTTP = 'http';
16
17
    private const ALLOWED_SCHEMES = [
18
        self::SCHEME_HTTP,
19
        self::SCHEME_HTTPS,
20
    ];
21
22
    private $url = '';
23
    private $components = [];
24
25 2
    public function __construct(string $url)
26
    {
27 2
        if (!$this->urlHasScheme($url)) {
28
            $url = sprintf('http://%s', $url);
29
        }
30
31 2
        if (!$this->isValid($url)) {
32
            throw new Exception\InvalidUrlException();
33
        }
34
35 2
        $this->url = $url;
36 2
    }
37
38
    public function scheme(): string
39
    {
40
        return $this->components['scheme'];
41
    }
42
43
    public function isHttps(): bool
44
    {
45
        return $this->scheme() === self::SCHEME_HTTPS;
46
    }
47
48
    public function host(): string
49
    {
50
        return $this->components['host'];
51
    }
52
53
    public function path(): string
54
    {
55
        return $this->components['path'] ?? '/';
56
    }
57
58
    public function query(): string
59
    {
60
        return $this->components['query'] ?? '';
61
    }
62
63
    public function port(): int
64
    {
65
        if (empty($this->components['port'])) {
66
            return $this->scheme() === self::SCHEME_HTTPS ? 443 : 80;
67
        }
68
69
        return (int) $this->components['port'];
70
    }
71
72
    public function redirectTo(HttpHeader $locationHeader): self
73
    {
74
        $newLocation = $locationHeader->value();
75
76
        if (substr($newLocation, 0, 2) === '//') {
77
            $newLocation = sprintf('%s:%s', $this->scheme(), $newLocation);
78
        } elseif ($newLocation[0] === '/') {
79
            $newLocation = sprintf('%s://%s:%d%s', $this->scheme(), $this->host(), $this->port(), $newLocation);
80
        } elseif (!preg_match('~^https?://~', $newLocation)) {
81
            $newLocation = $this->url . $newLocation;
82
        }
83
84
        return new self($newLocation);
85
    }
86
87 2
    private function isValid(string $url): bool
88
    {
89 2
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
90
            return false;
91
        }
92
93 2
        $components = parse_url($url);
94
95 2
        if (!isset($components['host'], $components['scheme']) || !$this->isAllowedScheme($components['scheme'])) {
96
            return false;
97
        }
98
99 2
        $this->components = $components;
100
101 2
        return true;
102
    }
103
104 2
    private function isAllowedScheme(string $scheme): bool
105
    {
106 2
        return in_array($scheme, self::ALLOWED_SCHEMES, true);
107
    }
108
109 2
    private function urlHasScheme(string $url): bool
110
    {
111 2
        return preg_match('~^[a-z][a-z\d\-\.]*://~i', $url) === 1;
112
    }
113
}
114