ClientIp::scanIps()   D
last analyzed

Complexity

Conditions 9
Paths 20

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 4.909
c 0
b 0
f 0
cc 9
eloc 14
nc 20
nop 1
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Utils;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * Middleware returns the client ip.
11
 */
12
class ClientIp
13
{
14
    use Utils\AttributeTrait;
15
16
    const KEY = 'CLIENT_IPS';
17
18
    /**
19
     * @var bool
20
     */
21
    private $remote = false;
22
23
    /**
24
     * @var array The trusted headers
25
     */
26
    private $headers = [];
27
28
    /**
29
     * Returns all ips found.
30
     *
31
     * @param ServerRequestInterface $request
32
     *
33
     * @return array|null
34
     */
35
    public static function getIps(ServerRequestInterface $request)
36
    {
37
        return self::getAttribute($request, self::KEY);
38
    }
39
40
    /**
41
     * Return the client ip.
42
     *
43
     * @param ServerRequestInterface $request
44
     *
45
     * @return string|null
46
     */
47
    public static function getIp(ServerRequestInterface $request)
48
    {
49
        $ips = self::getIps($request);
50
51
        return isset($ips[0]) ? $ips[0] : null;
52
    }
53
54
    /**
55
     * Constructor. Defines de trusted headers.
56
     *
57
     * @param null|array $headers
58
     */
59
    public function __construct(array $headers = null)
60
    {
61
        if ($headers !== null) {
62
            $this->headers($headers);
63
        } else {
64
            $this->headers();
65
        }
66
    }
67
68
    /**
69
     * Configure the trusted headers.
70
     *
71
     * @param array $headers
72
     *
73
     * @return self
74
     */
75
    public function headers(array $headers = ['Forwarded', 'Forwarded-For', 'Client-Ip', 'X-Forwarded', 'X-Forwarded-For', 'X-Cluster-Client-Ip'])
76
    {
77
        $this->headers = $headers;
78
79
        return $this;
80
    }
81
82
    /**
83
     * To get the ip from a remote service.
84
     * Useful for testing purposes on localhost.
85
     *
86
     * @param bool $remote
87
     *
88
     * @return self
89
     */
90
    public function remote($remote = true)
91
    {
92
        $this->remote = $remote;
93
94
        return $this;
95
    }
96
97
    /**
98
     * Execute the middleware.
99
     *
100
     * @param ServerRequestInterface $request
101
     * @param ResponseInterface      $response
102
     * @param callable               $next
103
     *
104
     * @return ResponseInterface
105
     */
106
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
107
    {
108
        $request = self::setAttribute($request, self::KEY, $this->scanIps($request));
109
110
        return $next($request, $response);
111
    }
112
113
    /**
114
     * Detect and return all ips found.
115
     *
116
     * @param ServerRequestInterface $request
117
     *
118
     * @return array
119
     */
120
    private function scanIps(ServerRequestInterface $request)
121
    {
122
        $server = $request->getServerParams();
123
        $ips = [];
124
125
        if ($this->remote) {
126
            $ips[] = file_get_contents('http://ipecho.net/plain');
127
        }
128
129
        foreach ($this->headers as $name) {
130
            $header = $request->getHeaderLine($name);
131
132
            if (!empty($header)) {
133
                foreach (array_map('trim', explode(',', $header)) as $ip) {
134
                    if ((array_search($ip, $ips) === false) && filter_var($ip, FILTER_VALIDATE_IP)) {
135
                        $ips[] = $ip;
136
                    }
137
                }
138
            }
139
        }
140
141
        if (!empty($server['REMOTE_ADDR']) && filter_var($server['REMOTE_ADDR'], FILTER_VALIDATE_IP)) {
142
            $ips[] = $server['REMOTE_ADDR'];
143
        }
144
145
        return $ips;
146
    }
147
}
148