Test Setup Failed
Push — master ( 82cb37...6102ab )
by mcfog
04:22
created

IpAddress::getIpAddress()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Lit\Middleware\IpAddress;
6
7
use Lit\Nimo\AbstractMiddleware;
8
use Lit\Nimo\Traits\MiddlewareTrait;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
12
class IpAddress extends AbstractMiddleware
13
{
14
    use MiddlewareTrait;
15
16
    /**
17
     * @var array
18
     */
19
    protected $trustedProxies;
20
    /**
21
     * @var array
22
     */
23
    protected $headers;
24
    /**
25
     * @var string
26
     */
27
    protected $ipAddress;
28
29 13
    public function __construct(
30
        array $trustedProxies = [],
31
        array $headers = []
32
    ) {
33 13
        $this->trustedProxies = $trustedProxies;
34 13
        $this->headers = $headers;
35 13
    }
36
37
    /**
38
     * @return string
39
     */
40 13
    public function getIpAddress(): ?string
41
    {
42 13
        return $this->ipAddress;
43
    }
44
45 13
    public static function getIpAddressFromRequest(
46
        ServerRequestInterface $request,
47
        array $trustedProxies = [],
48
        array $headers = []
49
    ): ?string {
50 13
        $headers = $headers ?: [
51 13
            'Forwarded',
52
            'X-Forwarded-For',
53
            'X-Forwarded',
54
            'X-Cluster-Client-Ip',
55
            'Client-Ip',
56
        ];
57
58 13
        $params = $request->getServerParams();
59
60 13
        $remoteAddr = $params['REMOTE_ADDR'] ?? '';
61 13
        if (!self::isValidIpAddress($remoteAddr)) {
62 1
            return null;
63
        }
64
65 12
        if (empty($trustedProxies) || !in_array($remoteAddr, $trustedProxies)) {
66 3
            return $remoteAddr;
67
        }
68
69 9
        $ip = self::getIpAddressFromHeaders($request, $headers);
70 9
        if (!empty($ip)) {
71 8
            return $ip;
72
        }
73
74 1
        return $remoteAddr;
75
    }
76
77 13
    protected function main(): ResponseInterface
78
    {
79 13
        $this->attachToRequest();
80 13
        $this->ipAddress = static::getIpAddressFromRequest($this->request, $this->trustedProxies, $this->headers);
81
82 13
        return $this->delegate();
83
    }
84
85 13
    protected static function isValidIpAddress(string $ip): bool
86
    {
87 13
        return false !== filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6);
88
    }
89
90
    /**
91
     * @param ServerRequestInterface $request
92
     * @param string[] $headers
93
     * @return null|string
94
     */
95 9
    protected static function getIpAddressFromHeaders(ServerRequestInterface $request, array $headers): ?string
96
    {
97 9
        foreach ($headers as $headerName) {
98 9
            $headerValue = trim(explode(',', $request->getHeaderLine($headerName))[0]);
99 9
            if (empty($headerValue)) {
100 5
                continue;
101
            }
102
103 9
            if (strtolower($headerName) == 'forwarded') {
104 3
                $headerValue = static::parseForwarded($headerValue);
105
            }
106
107 9
            if (static::isValidIpAddress($headerValue)) {
108 9
                return $headerValue;
109
            }
110
        }
111
112 1
        return null;
113
    }
114
115 3
    protected static function parseForwarded($headerValue): ?string
116
    {
117 3
        foreach (explode(';', $headerValue) as $headerPart) {
118 3
            if (strtolower(substr($headerPart, 0, 4)) == 'for=') {
119 3
                $for = explode(']', $headerPart);
120 3
                return trim(substr($for[0], 4), " \t\n\r\0\x0B\"[]");
121
            }
122
        }
123
124
        return null;
125
    }
126
}
127