如何在Laravel 5+中获取客户端IP地址?

Amr*_*ngh 110 php laravel laravel-5 laravel-5.1 laravel-5.7

我想在Laravel中获取客户端的IP地址.众所周知,使用PHP获取客户端的IP要容易得多$_SERVER["REMOTE_ADDR"].

它在核心PHP中运行良好,但是当我在Laravel中使用相同的东西时,它会提供服务器IP而不是访问者IP.

sam*_*lev 157

看看Laravel API:

Request::ip();
Run Code Online (Sandbox Code Playgroud)

在内部,它使用Symfony请求对象中getClientIps方法:

public function getClientIps()
{
    $clientIps = array();
    $ip = $this->server->get('REMOTE_ADDR');
    if (!$this->isFromTrustedProxy()) {
        return array($ip);
    }
    if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
        $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
        preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
        $clientIps = $matches[3];
    } elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
        $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
    }
    $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
    $ip = $clientIps[0]; // Fallback to this when the client IP falls into the range of trusted proxies
    foreach ($clientIps as $key => $clientIp) {
        // Remove port (unfortunately, it does happen)
        if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
            $clientIps[$key] = $clientIp = $match[1];
        }
        if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
            unset($clientIps[$key]);
        }
    }
    // Now the IP chain contains only untrusted proxies and the client IP
    return $clientIps ? array_reverse($clientIps) : array($ip);
} 
Run Code Online (Sandbox Code Playgroud)

  • 使用Request对象对我不起作用,它返回我的Homestead服务器的地址.192.168.10.10这显然不是我的IP地址. (3认同)
  • @VinceKronlein在您的情况下,这是非常正确的。因为您要访问的是Homestead,所以在您的本地网络中,您的IP地址为192。如果您正在通过互联网访问别人的家庭服务器,那么您的IP将通过您的ISP消失,而您的公共IP将被使用。 (2认同)

Sta*_*ers 60

使用 request()->ip()

从Laravel 5开始(根据我的理解)建议/良好实践使用全局函数,如:

response()->json($v);
view('path.to.blade');
redirect();
route();
cookie();
Run Code Online (Sandbox Code Playgroud)

你明白了这一点:-)如果有的话,当使用这些函数(而不是静态的notarion)时,我的IDE就不会像圣诞树一样;-)

  • 你是对的``request`是一个"全局"函数 - 它是laravel提供的全局辅助函数之一.但是,Request facade不是静态的(也不是方法ip) - `request() - > foo`,`reqest :: foo`和`$ request-> foo`都是相同的.看一下这个要点:https://gist.github.com/cjke/026e3036c6a10c672dc5 (3认同)
  • 问题是这些全局函数不容易测试 - 它们不能被模拟.外墙可以.我试图避免全局函数,因为它意味着挖掘全局函数源来模拟它的调用,这是额外的工作,烦人,并且不应该是我的责任. (3认同)

Seb*_*rin 57

如果您在负载均衡器下

Laravel \Request::ip() 总是返回平衡器的IP

            echo $request->ip();
            // server ip

            echo \Request::ip();
            // server ip

            echo \request()->ip();
            // server ip

            echo $this->getIp(); //see the method below
            // clent ip
Run Code Online (Sandbox Code Playgroud)

这个自定义方法返回真正的客户端ip:

public function getIp(){
    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
        if (array_key_exists($key, $_SERVER) === true){
            foreach (explode(',', $_SERVER[$key]) as $ip){
                $ip = trim($ip); // just to be safe
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                    return $ip;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更多:如果您使用Laravel的油门中间件

除此之外,我建议您使用Laravel的油门中间件时要非常小心:它也使用Laravel Request::ip(),因此所有访客都将被识别为同一个用户,您将很快达到油门限制.在现场体验......这让我遇到了大问题......

解决这个问题:

照亮\ HTTP\Request.php

    public function ip()
    {
        //return $this->getClientIp(); //original method
        return $this->getIp(); // the above method
    }
Run Code Online (Sandbox Code Playgroud)

您现在也可以使用Request::ip(),它应该返回生产中的真实IP

  • 这实际上适用于laravel 5.4请考虑在github上制作PR.我认为这应该是默认行为 (4认同)
  • 不能通过信任的代理解决此问题吗?-https://laravel.com/docs/master/requests#configuring-trusted-proxies (2认同)
  • 对于答案的第二部分,编辑核心框架文件(Illuminate\Http\Request.php)是否明智?因为每次你在另一台机器上安装composer时,这将不适用。 (2认同)

sha*_*ini 23

添加命名空间

use Request;
Run Code Online (Sandbox Code Playgroud)

然后调用该函数

Request::ip();
Run Code Online (Sandbox Code Playgroud)


Tod*_*rov 14

对于Laravel 5,您可以使用Request对象.只需调用其ip()方法即可.就像是:

$request->ip();


Pej*_*yri 12

我在 Laravel 8.x 中进行了测试,您可以使用:

$request->ip()
Run Code Online (Sandbox Code Playgroud)

用于获取客户端的IP地址。


Gov*_*row 11

在Laravel 5

public function index(Request $request) {
  $request->ip();
}
Run Code Online (Sandbox Code Playgroud)


小智 7

在 Laravel 5.4 中我们不能调用 ip static。这是获取用户IP的正确方法:

 use Illuminate\Http\Request;

public function contactUS(Request $request)
    {
        echo $request->ip();
        return view('page.contactUS');
    }
Run Code Online (Sandbox Code Playgroud)


小智 7

如果你调用这个函数,那么你很容易得到客户端的 IP 地址。我已经在我现有的项目中使用了它:

public function getUserIpAddr(){
       $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_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;
    }
Run Code Online (Sandbox Code Playgroud)


Phi*_*ine 6

如果您仍然获得 127.0.0.1 作为 IP,则需要添加您的“代理”,但请注意,您必须在投入生产之前对其进行更改!

阅读“配置可信代理”。

并添加这个:

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array
     */
    protected $proxies = '*';
Run Code Online (Sandbox Code Playgroud)

现在request()->ip()给你正确的IP。


小智 5

如果您需要客户端 IP 并且您的服务器位于 aws elb 之后,请使用以下代码。已针对 Laravel 5.3 进行测试

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Run Code Online (Sandbox Code Playgroud)

  • 不再工作,现在需要“trustedHeaderSet” (2认同)

Yev*_*yev 5

有两件事要照顾

1)获取返回a Illuminate\Http\Request和call ->ip()方法的辅助函数。

request()->ip();
Run Code Online (Sandbox Code Playgroud)

2)考虑您的服务器配置,它可能使用proxyload balancer(特别是在AWS ELBconfig中)

如果是这种情况,则需要配置“受信任的代理”,甚至可能要设置一个Trusting All Proxies选项。

为什么?

因为成为您的服务器将获得您的代理/天平加载器IP。

怎么样?

如果你不 AWS balance-loader

App\Http\Middleware\TrustProxies

并使$proxies声明如下所示:

protected $proxies = '*';
Run Code Online (Sandbox Code Playgroud)

现在进行测试并庆祝,因为您只是避免了麻烦 throttle middleware。它还依赖request()->ip()并且无需进行设置TrustProxies,您可以阻止所有用户登录,而不仅仅是阻止罪魁祸首的IP。

并且由于throttle middleware文档中没有正确解释,因此我建议您观看此视频

在Laravel 5.7中测试