How to get the client IP address in PHP
如何使用PHP获取客户端IP地址?
我想记录通过他/她的IP地址登录我的网站的用户。
无论您做什么,请确保不要信任从客户机发送的数据。
但是,它们可能位于代理服务器之后,在这种情况下,代理可能设置了
这意味着,如果要保存
如果要将IP以字符串形式保存到数据库中,请确保至少有45个字符的空间。IPv6将保留下来,并且这些地址大于旧的IPv4地址。
(请注意,ipv6最多使用39个字符,但也有一个针对ipv4地址的特殊ipv6表示法,其完整形式最多可以使用45个字符。所以,如果你知道你在做什么,你可以用39个字符,但如果你只是想设置并忘记它,用45个字符)。
有几个HTTP头,如
说到这里,下面是一些示例代码:
1 2 3 4 5 6 7 |
编者按:使用上面的代码会带来安全隐患。客户机可以将所有HTTP头信息(即
发件人:http://roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html
1 | echo $_SERVER['REMOTE_ADDR']; |
http://php.net/manual/en/reserved.variables.server.php
下面是一个更清晰的代码示例,它是获取用户IP地址的好方法。
1 | $ip = $_SERVER['HTTP_CLIENT_IP'] ? $_SERVER['HTTP_CLIENT_IP'] : ($_SERVER['HTTP_X_FORWARDED_FOR'] ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']); |
下面是使用ELVIS运算符的较短版本:
1 | $_SERVER['HTTP_CLIENT_IP'] ? : ($_SERVER['HTTP_X_FORWARDED_FOR'] ? : $_SERVER['REMOTE_ADDR']); |
下面是一个使用ISSET删除通知的版本(谢谢,@shasi kanth):
1 |
它应该包含在
我最喜欢的解决方案是Zend Framework 2的使用方式。它还考虑了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | class RemoteAddress { /** * Whether to use proxy addresses or not. * * As default this setting is disabled - IP address is mostly needed to increase * security. HTTP_* are not reliable since can easily be spoofed. It can be enabled * just for more flexibility, but if user uses proxy to connect to trusted services * it's his/her own risk, only reliable field for IP address is $_SERVER['REMOTE_ADDR']. * * @var bool */ protected $useProxy = false; /** * List of trusted proxy IP addresses * * @var array */ protected $trustedProxies = array(); /** * HTTP header to introspect for proxies * * @var string */ protected $proxyHeader = 'HTTP_X_FORWARDED_FOR'; // [...] /** * Returns client IP address. * * @return string IP address. */ public function getIpAddress() { $ip = $this->getIpAddressFromProxy(); if ($ip) { return $ip; } // direct IP address if (isset($_SERVER['REMOTE_ADDR'])) { return $_SERVER['REMOTE_ADDR']; } return ''; } /** * Attempt to get the IP address for a proxied client * * @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2 * @return false|string */ protected function getIpAddressFromProxy() { if (!$this->useProxy || (isset($_SERVER['REMOTE_ADDR']) && !in_array($_SERVER['REMOTE_ADDR'], $this->trustedProxies)) ) { return false; } $header = $this->proxyHeader; if (!isset($_SERVER[$header]) || empty($_SERVER[$header])) { return false; } // Extract IPs $ips = explode(',', $_SERVER[$header]); // trim, so we can compare against trusted proxies properly $ips = array_map('trim', $ips); // remove trusted proxy IPs $ips = array_diff($ips, $this->trustedProxies); // Any left? if (empty($ips)) { return false; } // Since we've removed any known, trusted proxy servers, the right-most // address represents the first IP we do not know about -- i.e., we do // not know if it is a proxy server, or a client. As such, we treat it // as the originating IP. // @see http://en.wikipedia.org/wiki/X-Forwarded-For $ip = array_pop($ips); return $ip; } // [...] } |
请参阅以下完整代码:https://raw.githubusercontent.com/zendframework/zend-http/master/src/phpenvironment/remoteaddress.php
Internet背后有不同类型的用户,因此我们希望从不同的部分捕获IP地址。那些是:
1。
2。埃多克斯1〔10〕。-这将获取用户查看当前页面的主机名。但要使该脚本工作,必须配置httpd.conf内部的主机名查找。
三。江户十一〔11〕号-这将在用户来自共享Internet服务时获取IP地址。
4。
因此,我们可以使用下面的组合函数从不同位置查看的用户那里获取真实的IP地址,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // Function to get the user IP address function getUserIP() { $ipaddress = ''; if (isset($_SERVER['HTTP_CLIENT_IP'])) $ipaddress = $_SERVER['HTTP_CLIENT_IP']; else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR']; else if(isset($_SERVER['HTTP_X_FORWARDED'])) $ipaddress = $_SERVER['HTTP_X_FORWARDED']; else if(isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) $ipaddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP']; else if(isset($_SERVER['HTTP_FORWARDED_FOR'])) $ipaddress = $_SERVER['HTTP_FORWARDED_FOR']; else if(isset($_SERVER['HTTP_FORWARDED'])) $ipaddress = $_SERVER['HTTP_FORWARDED']; else if(isset($_SERVER['REMOTE_ADDR'])) $ipaddress = $_SERVER['REMOTE_ADDR']; else $ipaddress = 'UNKNOWN'; return $ipaddress; } |
下面是我发现的最先进的方法,我过去已经尝试过其他一些方法。确保获取访问者的IP地址是有效的(但请注意,任何黑客都可以轻易地伪造IP地址)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | function get_ip_address() { // Check for shared Internet/ISP IP if (!empty($_SERVER['HTTP_CLIENT_IP']) && validate_ip($_SERVER['HTTP_CLIENT_IP'])) { return $_SERVER['HTTP_CLIENT_IP']; } // Check for IP addresses passing through proxies if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { // Check if multiple IP addresses exist in var if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false) { $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); foreach ($iplist as $ip) { if (validate_ip($ip)) return $ip; } } else { if (validate_ip($_SERVER['HTTP_X_FORWARDED_FOR'])) return $_SERVER['HTTP_X_FORWARDED_FOR']; } } if (!empty($_SERVER['HTTP_X_FORWARDED']) && validate_ip($_SERVER['HTTP_X_FORWARDED'])) return $_SERVER['HTTP_X_FORWARDED']; if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP']; if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && validate_ip($_SERVER['HTTP_FORWARDED_FOR'])) return $_SERVER['HTTP_FORWARDED_FOR']; if (!empty($_SERVER['HTTP_FORWARDED']) && validate_ip($_SERVER['HTTP_FORWARDED'])) return $_SERVER['HTTP_FORWARDED']; // Return unreliable IP address since all else failed return $_SERVER['REMOTE_ADDR']; } /** * Ensures an IP address is both a valid IP address and does not fall within * a private network range. */ function validate_ip($ip) { if (strtolower($ip) === 'unknown') return false; // Generate IPv4 network address $ip = ip2long($ip); // If the IP address is set and not equivalent to 255.255.255.255 if ($ip !== false && $ip !== -1) { // Make sure to get unsigned long representation of IP address // due to discrepancies between 32 and 64 bit OSes and // signed numbers (ints default to signed in PHP) $ip = sprintf('%u', $ip); // Do private network range checking if ($ip >= 0 && $ip <= 50331647) return false; if ($ip >= 167772160 && $ip <= 184549375) return false; if ($ip >= 2130706432 && $ip <= 2147483647) return false; if ($ip >= 2851995648 && $ip <= 2852061183) return false; if ($ip >= 2886729728 && $ip <= 2887778303) return false; if ($ip >= 3221225984 && $ip <= 3221226239) return false; if ($ip >= 3232235520 && $ip <= 3232301055) return false; if ($ip >= 4294967040) return false; } return true; } |
答案是使用
正如所有其他人之前所说,您可以使用
此外,如果您需要有关用户的更多信息,可以使用:
1 2 3 4 5 6 | <?php $ip = '0.0.0.0'; $ip = $_SERVER['REMOTE_ADDR']; $clientDetails = json_decode(file_get_contents("http://ipinfo.io/$ip/json")); echo"You're logged in from:" . $clientDetails->country .""; ?> |
客户的更具体信息在$clientdetails中。< BR>您可以通过以下方式获取存储在$clientdetails变量中的json项:$clientdetails->postalcode/hostname/region/loc…
我用ipinfo.io获取额外信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $ip =""; if (!empty($_SERVER["HTTP_CLIENT_IP"])) { // Check for IP address from shared Internet $ip = $_SERVER["HTTP_CLIENT_IP"]; } elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) { // Check for the proxy user $ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; } else { $ip = $_SERVER["REMOTE_ADDR"]; } echo $ip; |
这是我使用的方法,它验证IPv4输入:
1 2 3 4 5 6 7 8 9 10 11 | // Get user IP address if ( isset($_SERVER['HTTP_CLIENT_IP']) && ! empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) && ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $ip = (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; } $ip = filter_var($ip, FILTER_VALIDATE_IP); $ip = ($ip === false) ? '0.0.0.0' : $ip; |
我喜欢这个代码段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function getClientIP() { if (isset($_SERVER)) { if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) return $_SERVER["HTTP_X_FORWARDED_FOR"]; if (isset($_SERVER["HTTP_CLIENT_IP"])) return $_SERVER["HTTP_CLIENT_IP"]; return $_SERVER["REMOTE_ADDR"]; } if (getenv('HTTP_X_FORWARDED_FOR')) return getenv('HTTP_X_FORWARDED_FOR'); if (getenv('HTTP_CLIENT_IP')) return getenv('HTTP_CLIENT_IP'); return getenv('REMOTE_ADDR'); } |
试试这个:
1 | $_SERVER['REMOTE_ADDR']; |
好吧,这可以通过使用名为
只需这样分配:
1 | $userIp = $_SERVER['REMOTE_ADDR']; |
或直接使用,如
以下函数确定所有可能性,并以逗号分隔格式(IP、IP等)返回值。
它还有一个可选的验证函数作为(默认情况下禁用的第一个参数),用于根据(专用范围和保留范围)验证IP地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php echo GetClientIP(true); function GetClientIP($validate = False) { $ipkeys = array( 'REMOTE_ADDR', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP' ); /* Now we check each key against $_SERVER if containing such value */ $ip = array(); foreach ($ipkeys as $keyword) { if (isset($_SERVER[$keyword])) { if ($validate) { if (ValidatePublicIP($_SERVER[$keyword])) { $ip[] = $_SERVER[$keyword]; } } else{ $ip[] = $_SERVER[$keyword]; } } } $ip = ( empty($ip) ? 'Unknown' : implode(",", $ip) ); return $ip; } function ValidatePublicIP($ip){ if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { return true; } else { return false; } } |
这个函数很紧凑,您可以在任何地方使用它。但是!
别忘了!在这种类型的函数或代码块中,不能保证记录用户的真实IP地址,因为有些用户可以使用代理或另一个安全网关使其不可见或无法跟踪
PHP功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
用途:
获取IP地址的安全和警告感知代码段:
1 2 3 4 | $ip = filter_input(INPUT_SERVER, 'HTTP_CLIENT_IP', FILTER_VALIDATE_IP) ?: filter_input(INPUT_SERVER, 'HTTP_X_FORWARDED_FOR', FILTER_VALIDATE_IP) ?: $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; // Or other value fits"not defined" in your logic |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function get_client_ip() { $ipaddress = ''; if (getenv('HTTP_CLIENT_IP')) $ipaddress = getenv('HTTP_CLIENT_IP'); else if(getenv('HTTP_X_FORWARDED_FOR')) $ipaddress = getenv('HTTP_X_FORWARDED_FOR'); else if(getenv('HTTP_X_FORWARDED')) $ipaddress = getenv('HTTP_X_FORWARDED'); else if(getenv('HTTP_FORWARDED_FOR')) $ipaddress = getenv('HTTP_FORWARDED_FOR'); else if(getenv('HTTP_FORWARDED')) $ipaddress = getenv('HTTP_FORWARDED'); else if(getenv('REMOTE_ADDR')) $ipaddress = getenv('REMOTE_ADDR'); else $ipaddress = 'UNKNOWN'; return $ipaddress; } |
下面是获取客户端IP地址的一行程序版本:
$ip = @$_SERVER['HTTP_CLIENT_IP'] ?: @$_SERVER['HTTP_X_FORWARDED_FOR'] ?: @$_SERVER['REMOTE_ADDR'];
笔记:
- 通过使用
@ ,它将抑制php通知。 HTTP_X_FORWARDED_FOR 中的值可能包含多个用逗号分隔的地址,因此如果您希望获得第一个地址,可以使用以下方法:
此函数应按预期工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | function Get_User_Ip() { $IP = false; if (getenv('HTTP_CLIENT_IP')) { $IP = getenv('HTTP_CLIENT_IP'); } else if(getenv('HTTP_X_FORWARDED_FOR')) { $IP = getenv('HTTP_X_FORWARDED_FOR'); } else if(getenv('HTTP_X_FORWARDED')) { $IP = getenv('HTTP_X_FORWARDED'); } else if(getenv('HTTP_FORWARDED_FOR')) { $IP = getenv('HTTP_FORWARDED_FOR'); } else if(getenv('HTTP_FORWARDED')) { $IP = getenv('HTTP_FORWARDED'); } else if(getenv('REMOTE_ADDR')) { $IP = getenv('REMOTE_ADDR'); } //If HTTP_X_FORWARDED_FOR == server ip if((($IP) && ($IP == getenv('SERVER_ADDR')) && (getenv('REMOTE_ADDR')) || (!filter_var($IP, FILTER_VALIDATE_IP)))) { $IP = getenv('REMOTE_ADDR'); } if($IP) { if(!filter_var($IP, FILTER_VALIDATE_IP)) { $IP = false; } } else { $IP = false; } return $IP; } |
就在这一点上,我很惊讶它还没有被提到,是要得到正确的IP地址的那些网站是依附在像CloudFlare基础设施。它会破坏你的IP地址,并赋予它们相同的值。幸运的是,它们也有一些服务器头可用。不是我重写已经写的内容,而是在这里寻找一个更简洁的答案,是的,很久以前我也经历过这个过程。https://stackoverflow.com/a/14985633/1190051
像下面这样?
1 2 3 4 | if (($ip=filter_input(INPUT_SERVER, 'REMOTE_ADDR', validate_ip)) === false or empty($ip)) { exit; } echo $ip; |
聚苯乙烯
1 2 3 4 | if (($ip=filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP|FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE)) === false) { header('HTTP/1.0 400 Bad Request'); exit; } |
所有以"http_uuu"或"x-"开头的头都可能被欺骗,分别由用户定义。如果你想跟踪,使用cookies等。
这是一个简单的一行
1 | $ip = $_SERVER['HTTP_X_FORWARDED_FOR']?: $_SERVER['HTTP_CLIENT_IP']?: $_SERVER['REMOTE_ADDR']; |
编辑:
上面的代码可能会返回保留的地址(如10.0.0.1)、路上所有代理服务器的地址列表等。要处理这些情况,请使用以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function valid_ip($ip) { // for list of reserved IP addresses, see https://en.wikipedia.org/wiki/Reserved_IP_addresses return $ip && substr($ip, 0, 4) != '127.' && substr($ip, 0, 4) != '127.' && substr($ip, 0, 3) != '10.' && substr($ip, 0, 2) != '0.' ? $ip : false; } function get_client_ip() { // using explode to get only client ip from list of forwarders. see https://en.wikipedia.org/wiki/X-Forwarded-For return @$_SERVER['HTTP_X_FORWARDED_FOR'] ? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2)[0] : @$_SERVER['HTTP_CLIENT_IP'] ? explode(',', $_SERVER['HTTP_CLIENT_IP'], 2)[0] : valid_ip(@$_SERVER['REMOTE_ADDR']) ?: 'UNKNOWN'; } echo get_client_ip(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
1 | $_SERVER['REMOTE_ADDR']; |
例子:
1 2 3 4 5 6 7 |