PHP 获取客户端ip地址
一、如果没有使用代理服务器,
REMOTE_ADDR
= 客户端IP HTTP_X_FORWARDED_FOR
= 没数值或不显示
$ip = $_SERVER['REMOTE_ADDR'];
二、使用透明代理,
REMOTE_ADDR
= 最后一个代理服务器 IP
HTTP_X_FORWARDED_FOR
= 客户端真实 IP (经过多个代理服务器时,这个值类似:221.5.252.160, 203.98.182.163, 203.129.72.215)
这类代理还会将客户真实ip发送到请求对象,无法隐藏真实ip。
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
三、使用普通匿名代理服务器,
REMOTE_ADDR
= 最后一个代理服务器 IP
HTTP_X_FORWARDED_FOR
= 代理服务器 IP (经过多个代理服务器时,这个值类似:203.98.182.163, 203.98.182.163, 203.129.72.215)
这样就隐藏了客户端的真实ip,但服务器会知道客户端是通过代理服务器去访问的。
四、使用欺骗性代理服务器,
REMOTE_ADDR
= 代理服务器 IP
HTTP_X_FORWARDED_FOR
= 随机的 IP(经过多个代理服务器时,这个值类似:220.4.251.159, 203.98.182.163, 203.129.72.215)
服务器可以识别到时通过代理服务器访问的,但发送给目标服务器的是虚假ip。
五、使用高匿名代理,
REMOTE_ADDR
= 代理服务器 IP HTTP_X_FORWARDED_FOR
= 没数值或不显示
使用这种代理时,不同浏览器不同设备会返回不同的ip头信息,因此PHP使用$_SERVER["REMOTE_ADDR"]
、$_SERVER["HTTP_X_FORWARDED_FOR"]
获取的值可能是空值也可能是“unknown
”值。
PHP获取ip代码方法1:
function getip() {
static $realip;
if (isset($_SERVER)) {
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$realip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
$realip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$realip = $_SERVER['REMOTE_ADDR'];
}
} else {
if (getenv('HTTP_X_FORWARDED_FOR')) {
$realip = getenv('HTTP_X_FORWARDED_FOR');
} else if (getenv('HTTP_CLIENT_IP')) {
$realip = getenv('HTTP_CLIENT_IP');
} else {
$realip = getenv('REMOTE_ADDR');
}
}
return $realip;
}
PHP获取ip代码方法2:
function getip(){
$ip=false;
if(!empty($_SERVER['HTTP_CLIENT_IP'])){
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ips=explode (', ', $_SERVER['HTTP_X_FORWARDED_FOR']);
if($ip){
array_unshift($ips, $ip);
$ip=FALSE;
}
for ($i=0; $i < count($ips); $i++){
if(!eregi ('^(10│172.16│192.168).', $ips[$i])){
$ip=$ips[$i];
break;
}
}
}
return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
}
根据ip获取归属地信息
/**
获取 IP 地理位置
* 淘宝IP接口
* @Return: array
*/
function getCity($ip = '')
{
$url="http://ip.taobao.com/service/getIpInfo.php?ip=".$ip;
$ip=json_decode(file_get_contents($url));
if((string)$ip->code=='1'){
return false;
}
$data = (array)$ip->data;
return $data;
}
现状
目前主流的函数方法:
<?php
function getIp()
{
if ($_SERVER["HTTP_CLIENT_IP"] && strcasecmp($_SERVER["HTTP_CLIENT_IP"], "unknown")) {
$ip = $_SERVER["HTTP_CLIENT_IP"];
} else {
if ($_SERVER["HTTP_X_FORWARDED_FOR"] && strcasecmp($_SERVER["HTTP_X_FORWARDED_FOR"], "unknown")) {
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else {
if ($_SERVER["REMOTE_ADDR"] && strcasecmp($_SERVER["REMOTE_ADDR"], "unknown")) {
$ip = $_SERVER["REMOTE_ADDR"];
} else {
if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'],
"unknown")
) {
$ip = $_SERVER['REMOTE_ADDR'];
} else {
$ip = "unknown";
}
}
}
}
return ($ip);
}
echo getIp();
测试
curl伪造IP请求:
$ch = curl_init('http://localhost/ip.php');
//通用设置
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//不直接输出
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);//跟踪重定向
//伪造请求头
$ip = mt_rand(1, 255) . '.' . mt_rand(1, 255) . '.' . mt_rand(1, 255) . '.' . mt_rand(1, 255);
$header = [
'CLIENT-IP: ' . $ip,
'X-FORWARDED-FOR: ' . $ip,
'X-REAL-IP: ' . $ip,
'Accept-Language: zh-CN,zh;',
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
$html = curl_exec($ch);
curl_close($ch);
echo $html;
输出SERVER数组,发现【HTTP_CLIENT_IP】、【HTTP_X_FORWARDED_FOR】、【HTTP_X_REAL_IP】是随机变动的IP地址。
主流方法根本不安全!
分析
为什么?
HTTP_CLIENT_IP:存在于http请求的header
HTTP_X_FORWARDED_FOR:请求转发路径,客户端IP,代理1IP,代理2IP......
HTTP_X_REAL_IP:这个用得比较少,暂不讨论。
这三个值都是从HTTP请求头获取的,所以并不可靠!
REMOTE_ADDR
REMOTE_ADDR:是直接从TCP中获取的IP,基本不会被伪造!
返回查看$_SERVER数组,发现【REMOTE_ADDR】显示正确的IP!
所以直接用 $_SERVER['REMOTE_ADDR'] 就解决问题了?
其实还不行,如果客户端和服务器之间存在代理服务器,【REMOTE_ADDR】的值是最后一个代理服务器的IP!
只有第一台接收客户端请求的代理服务器的【REMOTE_ADDR】值才是客户的真实IP地址,要把该值传递下去!
解决方案
1. 客户端和服务器直连
<?php
function get_client_ip()
{
$ip = $_SERVER['REMOTE_ADDR'];
return $ip;
}
2. 客户端和服务器存在中间代理
第一层nginx代理设置:
proxy_set_header X-Forwarded-For $remote_addr;
其他层nginx代理设置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
PHP代码:
<?php
function get_client_ip()
{
$ip = null;
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$ip = trim(current($ip));
}
return $ip;
}
另:
<?php
function getIP()
{
static $realip;
if (isset($_SERVER)){
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
$realip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else if (isset($_SERVER["HTTP_CLIENT_IP"])) {
$realip = $_SERVER["HTTP_CLIENT_IP"];
} else {
$realip = $_SERVER["REMOTE_ADDR"];
}
} else {
if (getenv("HTTP_X_FORWARDED_FOR")){
$realip = getenv("HTTP_X_FORWARDED_FOR");
} else if (getenv("HTTP_CLIENT_IP")) {
$realip = getenv("HTTP_CLIENT_IP");
} else {
$realip = getenv("REMOTE_ADDR");
}
}
return $realip;
}
echo getIP();
?>
简易
<?php
$ip = $_SERVER['REMOTE_ADDR'];
echo $ip;
?>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了