RemoteAddress::setUseProxy()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
/*
3
* File: RemoteAddress.php
4
* Category: -
5
* Author: M.Goldenbaum
6
* Created: 17.10.20 23:21
7
* Updated: -
8
*
9
* Description:
10
*  -
11
*/
12
13
/**
14
 * @see       https://github.com/zendframework/zend-http for the canonical source repository
15
 * @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
16
 * @license   https://github.com/zendframework/zend-http/blob/master/LICENSE.md New BSD License
17
 */
18
19
namespace Webklex\GeoIP;
20
21
22
/**
23
 * Class RemoteAddress
24
 *
25
 * @package App\Libraries\Analyzer
26
 */
27
class RemoteAddress {
28
29
    /**
30
     * Whether to use proxy addresses or not.
31
     *
32
     * As default this setting is disabled - IP address is mostly needed to increase
33
     * security. HTTP_* are not reliable since can easily be spoofed. It can be enabled
34
     * just for more flexibility, but if user uses proxy to connect to trusted services
35
     * it's his/her own risk, only reliable field for IP address is $_SERVER['REMOTE_ADDR'].
36
     *
37
     * @var bool
38
     */
39
    protected $useProxy = false;
40
41
    /**
42
     * List of trusted proxy IP addresses
43
     *
44
     * @var array
45
     */
46
    protected $trustedProxies = [];
47
48
    /**
49
     * HTTP header to introspect for proxies
50
     *
51
     * @var string
52
     */
53
    protected $proxyHeader = 'HTTP_X_FORWARDED_FOR';
54
55
    /**
56
     * Changes proxy handling setting.
57
     *
58
     * This must be static method, since validators are recovered automatically
59
     * at session read, so this is the only way to switch setting.
60
     *
61
     * @param  bool $useProxy Whether to check also proxied IP addresses.
62
     * @return RemoteAddress
63
     */
64
    public function setUseProxy($useProxy = true) {
65
        $this->useProxy = $useProxy;
66
        return $this;
67
    }
68
69
    /**
70
     * Checks proxy handling setting.
71
     *
72
     * @return bool Current setting value.
73
     */
74
    public function getUseProxy() {
75
        return $this->useProxy;
76
    }
77
78
    /**
79
     * Set list of trusted proxy addresses
80
     *
81
     * @param  array $trustedProxies
82
     * @return RemoteAddress
83
     */
84
    public function setTrustedProxies(array $trustedProxies) {
85
        $this->trustedProxies = $trustedProxies;
86
        return $this;
87
    }
88
89
    /**
90
     * Set the header to introspect for proxy IPs
91
     *
92
     * @param  string $header
93
     * @return RemoteAddress
94
     */
95
    public function setProxyHeader($header = 'X-Forwarded-For') {
96
        $this->proxyHeader = $this->normalizeProxyHeader($header);
97
        return $this;
98
    }
99
100
    /**
101
     * Returns client IP address.
102
     *
103
     * @return string IP address.
104
     */
105
    public function getIpAddress() {
106
        $ip_address = $this->getIpAddressFromProxy();
107
108
        if($ip_address == "127.0.0.1" || strlen($ip_address) < 7) {
0 ignored issues
show
Bug introduced by
It seems like $ip_address can also be of type false; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

108
        if($ip_address == "127.0.0.1" || strlen(/** @scrutinizer ignore-type */ $ip_address) < 7) {
Loading history...
109
            $ip_address = false;
110
        }
111
112
        if ($ip_address) {
113
            return $ip_address;
114
        }
115
116
        $ip_address = $this->getServerVariable("REMOTE_ADDR");
117
118
        if(strlen($ip_address) < 7) {
119
            $ip_address = "127.0.0.1";
120
        }
121
122
        // direct IP address
123
        return $ip_address;
124
    }
125
126
    /**
127
     * Attempt to get the IP address for a proxied client
128
     *
129
     * @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
130
     * @return false|string
131
     */
132
    protected function getIpAddressFromProxy() {
133
        if (!$this->useProxy
134
            || ($this->getServerVariable('REMOTE_ADDR') != null && !in_array($this->getServerVariable('REMOTE_ADDR'), $this->trustedProxies))
135
        ) {
136
            return false;
137
        }
138
139
        $header = $this->proxyHeader;
140
        if (!$this->getServerVariable($header)) {
141
            return false;
142
        }
143
144
        // Extract IPs
145
        $ips = explode(',', $this->getServerVariable($header));
146
        // trim, so we can compare against trusted proxies properly
147
        $ips = array_map('trim', $ips);
148
        // remove trusted proxy IPs
149
        $ips = array_diff($ips, $this->trustedProxies);
150
151
        // Any left?
152
        if (empty($ips)) {
153
            return false;
154
        }
155
156
        // Since we've removed any known, trusted proxy servers, the right-most
157
        // address represents the first IP we do not know about -- i.e., we do
158
        // not know if it is a proxy server, or a client. As such, we treat it
159
        // as the originating IP.
160
        // @see http://en.wikipedia.org/wiki/X-Forwarded-For
161
        $ip = array_pop($ips);
162
        return $ip;
163
    }
164
165
    /**
166
     * Normalize a header string
167
     *
168
     * Normalizes a header string to a format that is compatible with
169
     * $_SERVER
170
     *
171
     * @param  string $header
172
     * @return string
173
     */
174
    protected function normalizeProxyHeader($header) {
175
        $header = strtoupper($header);
176
        $header = str_replace('-', '_', $header);
177
        if (0 !== strpos($header, 'HTTP_')) {
178
            $header = 'HTTP_' . $header;
179
        }
180
        return $header;
181
    }
182
183
    protected function getServerVariable($key, $default = null){
184
        if (!isset($_SERVER[$key]) || empty($_SERVER[$key])) {
185
            return $default;
186
        }
187
188
        return $_SERVER[$key];
189
    }
190
191
    /**
192
     * @return bool
193
     */
194
    public function isProxy(){
195
        $test_HTTP_proxy_headers = [
196
            'HTTP_VIA',
197
            'VIA',
198
            'Proxy-Connection',
199
            'HTTP_X_FORWARDED_FOR',
200
            'HTTP_FORWARDED_FOR',
201
            'HTTP_X_FORWARDED',
202
            'HTTP_FORWARDED',
203
            'HTTP_CLIENT_IP',
204
            'HTTP_FORWARDED_FOR_IP',
205
            'X-PROXY-ID',
206
            'MT-PROXY-ID',
207
            'X-TINYPROXY',
208
            'X_FORWARDED_FOR',
209
            'FORWARDED_FOR',
210
            'X_FORWARDED',
211
            'FORWARDED',
212
            'CLIENT-IP',
213
            'CLIENT_IP',
214
            'PROXY-AGENT',
215
            'HTTP_X_CLUSTER_CLIENT_IP',
216
            'FORWARDED_FOR_IP',
217
            'HTTP_PROXY_CONNECTION'
218
        ];
219
220
        foreach($test_HTTP_proxy_headers as $header){
221
            if ($this->getServerVariable($header, false)) {
222
                return true;
223
            }
224
        }
225
226
        return false;
227
    }
228
229
    /**
230
     * @param $user_agent
231
     * @return false|int
232
     */
233
    public function isCrawler($user_agent) {
234
        return preg_match('/bot|crawl|slurp|spider|mediapartners|bing/i', $user_agent) > 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return preg_match('/bot|...ng/i', $user_agent) > 0 returns the type boolean which is incompatible with the documented return type false|integer.
Loading history...
235
    }
236
237
    /**
238
     * @param $hostname
239
     * @return null|string
240
     */
241
    public function getISP($hostname) {
242
243
        $isp = explode('.', $hostname);
244
        $isp = array_reverse($isp);
245
        $tmp = $isp[1];
246
        if (preg_match("/\<(org?|com?|net)\>/i", $tmp)) {
247
            $myisp = $isp[2].'.'.$isp[1].'.'.$isp[0];
248
        } else {
249
            $myisp = $isp[1].'.'.$isp[0];
250
        }
251
        if (preg_match("/[0-9]{1,3}\.[0-9]{1,3}/", $myisp))
252
            return null;
253
254
        $isp = explode('.', $myisp);
255
        return $isp[0];
256
    }
257
258
    /**
259
     * @param $ip_address
260
     * @return string
261
     */
262
    public function getHost($ip_address) {
263
        return gethostbyaddr($ip_address);
264
    }
265
266
}
267