laravel获取客户端 IP 地址两种方式

1 laravel自带方法获取客户端ip

dd(request()->ip());
var_dump(request()->getClientIp());

但是,这是在没有代理的情况下,有时候我们的业务使用了反向代理、负载均衡、cdn加速等等,我们就要设置信任的代理IP。

修改 app\Http\Middleware\TrustProxies.php 中的 $proxies

protected $proxies = [
    '192.168.1.1/24',//你信任的代理IP,支持IP段。
];

如果你不清楚代理服务器IP,或者IP会一直变动。可以设置信任所有代理。(这样是极其不安全的,用户可以伪造X-Forwarded-For来伪造IP)

网段192.168.1.0/24是什么意思?
192.168.1.0/24表示网段是192.168.1.0,子网掩码是24位,子网掩码为:255.255.255.0,
用二进制表示为:11111111 11111111 11111111 00000000 ,
这里为什么是24呢,就是因为子网掩码里面的前面连续的“1”的个数为24个,一定要连续的才行。

192.168.1.0/28表示的意思是网段是192.168.1.0,子网掩码为:255.255.255.240,
用二进制表示为:11111111 11111111 11111111 11110000。

这时候你也许就疑惑了,就是24和28两个字不一样,为什么网段是一样的呢?

24位说明网络位是24位,那么主机位就是32-24=8位了,则子网的IP个数是254个,即是从00000001到11111110.
28位说明网络位是28位,那么主机位4位,则子网的IP个数是14个,即是从00000001到00001110.

protected $proxies = ‘**’;

// 自定义函数获取客户端IP
<?php
namespace App\Http\Controllers;
class TestController extends Controller
{
    public function ip()
    {
        dd($this->getClientIp());
    }
    /**
     * 获取用户真实 ip
     * @return array|false|mixed|string
     */
    private function getClientIp()
    {
        if (getenv('HTTP_CLIENT_IP')) {
            $ip = getenv('HTTP_CLIENT_IP');
        }
        if (getenv('HTTP_X_REAL_IP')) {
            $ip = getenv('HTTP_X_REAL_IP');
        } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
            $ips = explode(',', $ip);
            $ip = $ips[0];
        } elseif (getenv('REMOTE_ADDR')) {
            $ip = getenv('REMOTE_ADDR');
        } else {
            $ip = '0.0.0.0';
        }
        return $ip;
    }
}

getenv —获取环境变量的值
(PHP 4,PHP 5,PHP 7,PHP 8)
getenv —获取环境变量的值

var_dump(getenv('PATH'));
//得出
//string(106) "/usr/local/node/bin:/usr/local/jdk-12.0.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

HTTP_CLIENT_IP
HTTP_CLIENT_IP 是代理服务器发送的HTTP头。如果是“超级匿名代理”,则返回none值。同样,REMOTE_ADDR也会被替换为这个代理服务器的IP。

$_SERVER[‘HTTP_CLIENT_IP’]; //代理端的(有可能存在,可伪造)
HTTP_X_REAL_IP
nginx 代理模式下,获取客户端真实IP

$_SERVER[‘HTTP_X_REAL_IP’]; // 得到的都是客户端的地址

在nginx中设置:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

后端程序可以从Server变量HTTP_X_REAL_IP和HTTP_X_FORWARDED_FOR中获取用户的ip地址。

HTTP_X_REAL_IP的值是nginx得到的用户REMOTE_ADDR。

HTTP_X_FORWARDED_FOR
$_SERVER[‘HTTP_X_FORWARDED_FOR’]; //用户是在哪个IP使用的代理(有可能存在,也可以伪造)

一、没有使用代理服务器的情况:

REMOTE_ADDR = 您的 IP
HTTP_VIA = 没数值或不显示
HTTP_X_FORWARDED_FOR = 没数值或不显示

二、使用透明代理服务器的情况:Transparent Proxies

REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 您的真实 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

这类代理服务器还是将您的信息转发给您的访问对象,无法达到隐藏真实身份的目的。

三、使用普通匿名代理服务器的情况:Anonymous Proxies

REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 代理服务器 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

隐藏了您的真实IP,但是向访问对象透露了您是使用代理服务器访问他们的。

四、使用欺骗性代理服务器的情况:Distorting Proxies

REMOTE_ADDR = 代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 随机的 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

告诉了访问对象您使用了代理服务器,但编造了一个虚假的随机IP代替您的真实IP欺骗它。

五、使用高匿名代理服务器的情况:High Anonymity Proxies (Elite proxies)

REMOTE_ADDR = 代理服务器 IP
HTTP_VIA = 没数值或不显示
HTTP_X_FORWARDED_FOR = 没数值或不显示 ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

REMOTE_ADDR
如果不想获取代理ip需要对NGINX进行设置。

$_SERVER[‘REMOTE_ADDR’]; //访问端(有可能是用户,有可能是代理的)IP

表示发出请求的远程主机的 IP 地址,remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP。

x_forwarded_for

简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项,正如上面所述,当你使用了代理时,web服务器就不知道你的真实IP了,为了避免这个情况,代理服务器通常会增加一个叫做x_forwarded_for的头信息,把连接它的客户端IP(即你的上网机器IP)加到这个头信息里,这样就能保证网站的web服务器能获取到真实IP。

格式一般为:

X-Forwarded-For: 1.1.1.1, 2.2.2.2, 3.3.3.3

代表 请求由1.1.1.1发出,经过三层代理,第一层是2.2.2.2,第二层是3.3.3.3,而本次请求的来源IP4.4.4.4是第三层代理。

场景1
是很简单的场景,Nginx Proxy直接把请求往后转发,没有做任何处理

Nginx Proxy
192.168.107.107 nginx.conf
location /test {
    proxy_pass http://192.168.107.112:8080;
}
192.168.107.112 nginx.conf
location /test {
    proxy_pass http://192.168.107.114:8080;
}
Nginx Proxy就是简单的把请求往后转发。
Nginx Backend
192.168.107.114 nginx.conf
location /test {
    default_type text/html;
    charset gbk;
    echo "$remote_addr || $http_x_forwarded_for";
}

Nginx Backend输出客户端IP(r e m o t e a d d r ) 和 X − F o r w a r d e d − F o r 请 求 头 ( remote_addr)和X-Forwarded-For请求头(remote_addr)和X−Forwarded−For请求头(http_x_forwarded_for),当访问服务时输出结果如下所示:

192.168.107.112 ||

分析
1.$remote_addr代表客户端IP,当前配置的输出结果为最后一个代理服务器的IP,并不是真实客户端IP;

2.在没有特殊配置情况下,X-Forwarded-For请求头不会自动添加到请求头中,即Nginx Backend的$http_x_forwarded_for输出为空。

3 PHP判断ip范围
判断192.168.1.127是否在 (192.168.1.1–192.168.1.255)的范围

//定义变量    注释
$ip_start = get_iplong(192.168.1.1);    起始ip
$ip_end = get_iplong(192.168.1.255);    结束ip
$ip = get_iplong(192.168.1.127);    判断的ip
//可以这样简单判断  
if($ip>=$ip_start && $ip <=$ip_end){  
    echo 'IP在此范围内';  
}else{  
    echo 'IP不在此范围';  
}  
/*将ip地址转换成int型*/  
function get_iplong($ip){  
    /*decbin() 函数把十进制数转换为二进制数,bindec() 函数把二进制转换为十进制。
      ip2long();的意思是将IP地址转换成整型 ,  
      之所以要decbin和bindec一下是为了防止IP数值过大int型存储不了出现负数。 */ 
    return bindec(decbin(ip2long($ip)));  
}

4 获取客户端ip方法

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TestContainer extends Controller
{
    # 获取客户端ip
    public function containers()
    {
        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 {
            $ip = $_SERVER["REMOTE_ADDR"];
        }
        return $ip;
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
最美的不是下雨天,而是和你一起躲过的屋檐!
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!