Completed
Pull Request — master (#125)
by
unknown
02:04
created

BasicNetworkResolver::getServerRequest()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3.1406

Importance

Changes 0
Metric Value
cc 3
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 6
ccs 3
cts 4
cp 0.75
crap 3.1406
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace Yiisoft\Yii\Web\NetworkResolver;
5
6
use Psr\Http\Message\ServerRequestInterface;
7
8
/**
9
 * Basic network resolver
10
 *
11
 * It can be used in the following cases:
12
 * - not required IP resolve to access the user's IP
13
 * - user's IP is already resolved (eg ngx_http_realip_module or similar)
14
 *
15
 * @package Yiisoft\Yii\Web\NetworkResolver
16
 */
17
class BasicNetworkResolver implements NetworkResolverInterface
18
{
19
    protected const SCHEME_HTTPS = 'https';
20
21
    /**
22
     * @var ServerRequestInterface|null
23
     */
24
    private $serverRequest;
25
26
    private $protocolHeaders = [];
27
28
    public function getRemoteIp(): string
29
    {
30
        $ip = $this->getServerRequest()->getServerParams()['REMOTE_ADDR'] ?? null;
31
        if ($ip === null) {
32
            throw new \RuntimeException('Remote IP is not available!');
33
        }
34
        return (string)$ip;
35
    }
36
37
    public function getUserIp(): string
38
    {
39
        return $this->getRemoteIp();
40
    }
41
42
    /**
43
     * User's request scheme
44
     */
45 9
    public function getRequestScheme(): string
46
    {
47 9
        $request = $this->getServerRequest();
48 9
        foreach ($this->protocolHeaders as $header => $data) {
49 7
            if (!$request->hasHeader($header)) {
50 1
                continue;
51
            }
52 6
            $headerValues = $request->getHeader($header);
53 6
            if (is_callable($data)) {
54 1
                return call_user_func($data, $headerValues, $header, $request);
55
            }
56 5
            $headerValue = strtolower($headerValues[0]);
57 5
            foreach ($data as $protocol => $acceptedValues) {
58 5
                if (!in_array($headerValue, $acceptedValues)) {
59 1
                    continue;
60
                }
61 4
                return $protocol;
62
            }
63
        }
64 4
        return $request->getUri()->getScheme();
65
    }
66
67
    /**
68
     * User's connection security
69
     */
70
    public function isSecureConnection(): bool
71
    {
72
        return $this->getRequestScheme() === self::SCHEME_HTTPS;
73
    }
74
75 9
    public function withServerRequest(ServerRequestInterface $serverRequest)
76
    {
77 9
        $new = clone $this;
78 9
        $new->serverRequest = $serverRequest;
79 9
        return $new;
80
    }
81
82
    /**
83
     * @TODO: documentation
84
     * @param callable|array $protocolAndAcceptedValues
85
     * @return static
86
     */
87 7
    public function withNewProtocolHeader(string $header, $protocolAndAcceptedValues)
88
    {
89 7
        $new = clone $this;
90 7
        if (is_callable($protocolAndAcceptedValues)) {
91 1
            $new->protocolHeaders[$header] = $protocolAndAcceptedValues;
92 6
        } elseif (!is_array($protocolAndAcceptedValues)) {
93
            throw new \RuntimeException('$protocolAndAcceptedValues is not array nor callable!');
94 6
        } elseif (is_array($protocolAndAcceptedValues) && count($protocolAndAcceptedValues) === 0) {
95
            throw new \RuntimeException('$protocolAndAcceptedValues cannot be an empty array!');
96
        } else {
97 6
            $new->protocolHeaders[$header] = [];
98 6
            foreach ($protocolAndAcceptedValues as $protocol => $acceptedValues) {
99 6
                if (!is_string($protocol)) {
100
                    throw new \RuntimeException('The protocol must be type of string!');
101
                }
102 6
                $new->protocolHeaders[$header][$protocol] = array_map('strtolower', (array)$acceptedValues);
103
            }
104
        }
105 7
        return $new;
106
    }
107
108 9
    protected function getServerRequest(bool $throwIfNull = true): ?ServerRequestInterface
109
    {
110 9
        if ($this->serverRequest === null && $throwIfNull) {
111
            throw new \RuntimeException('The server request object is not set!');
112
        }
113 9
        return $this->serverRequest;
114
    }
115
}
116