182

I am trying to get the client's IP address in Laravel.

It is easy to get a client's IP in PHP by using $_SERVER["REMOTE_ADDR"]. It is working fine in core PHP, but when I use the same thing in Laravel, it returns the server IP instead of the visitor's IP.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Amrinder Singh
  • 5,300
  • 12
  • 46
  • 88

17 Answers17

251

Looking at the Laravel API:

Request::ip();

Internally, it uses the getClientIps method from the Symfony Request Object:

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);
} 
Peter Fox
  • 1,239
  • 2
  • 11
  • 31
samlev
  • 5,852
  • 1
  • 26
  • 38
  • 9
    Using the Request object doesn't work for me, it returns the address of my Homestead server. 192.168.10.10 which is obviously not my IP address. – secondman Jan 13 '17 at 06:36
  • @VinceKronlein for your case check this answer https://stackoverflow.com/a/41769505/3437790 – Sebastien Horin Sep 08 '17 at 14:04
  • 8
    @VinceKronlein in your case it was very correct. Because you were accessing Homestead, in your LOCAL network, you had tje 192. IP. if you were accessing someone else's homestead server, through the internet, your IP would go out through your ISP and your public one would be used. – ied3vil Apr 22 '18 at 21:07
  • To get current user ip in php, laravel \Request::ip(); OR $request->ip(); – Hassan Joseph May 19 '21 at 15:08
151

Note: This answer is outdated and dangerous. Request::ip() will, since Laravel 5.5, return the correct IP address if configured to trust the load balancer's headers. The "custom method" presented here allows clients to set any IP address they like.

If you are under a load balancer, Laravel's \Request::ip() always returns the balancer's IP:

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

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

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

            echo $this->getIp(); //see the method below
            // client IP

This custom method returns the real client 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;
                }
            }
        }
    }
    return request()->ip(); // it will return the server IP if the client IP is not found using this method.
}

In addition to this, I suggest you be very careful using Laravel's throttle middleware: It uses Laravel's Request::ip() as well, so all your visitors will be identified as the same user and you will hit the throttle limit very quickly. I experienced this in a live environment and this caused big issues.

To fix this:

Illuminate\Http\Request.php

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

You can now also use Request::ip(), which should return the real IP in production.

miken32
  • 42,008
  • 16
  • 111
  • 154
Sebastien Horin
  • 10,803
  • 4
  • 52
  • 54
  • 1
    is correct the if(filter_var...) inside second foreach ? this code will be never executed. – Mistre83 Feb 02 '17 at 21:21
  • @Mistre83 Yes you are right, I think it's a test oversight. I update it! – Sebastien Horin Feb 02 '17 at 23:36
  • 11
    this actually works with laravel 5.4 Please consider making PR on github. I think this should be default behavior – Crystal Apr 04 '17 at 21:18
  • 1
    This worked a treat in Laravel 5.3 when the Laravel request object's ip() method kept returning 127.0.0.1 – w5m Jun 26 '17 at 16:18
  • 5
    Cant you fix this with trusted proxys? - https://laravel.com/docs/master/requests#configuring-trusted-proxies – user2722667 Jun 14 '18 at 13:04
  • Thank you, your answer helped me more than I thought I needed. But there is a better way to solve this problem, see my answer. – Yevgeniy Afanasyev Dec 18 '18 at 23:02
  • @YevgeniyAfanasyev not sure about the `protected $proxies = '*';` in terms of security, when reading the headers is harmless – Sebastien Horin Dec 19 '18 at 13:05
  • I think one pipe "|" sign is missing after FILTER_FLAG_NO_PRIV_RANGE FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE other than this it work fine for me Thanks @SebastienHorin – Deepak Sharma Mar 28 '19 at 07:14
  • if the client use VPN, is this code will retrieve the fake IP address or the real IP address? – Syamsoul Azrien Apr 21 '20 at 03:45
  • To answer @SyamsoulAzrien, might not be a possible due to the user's IP's present before the request has been done, thus it's the vpn's ip was the present – NosiaD Dec 12 '20 at 00:12
  • 2
    For the second part of the answer, is it wise to edit the core framework file (Illuminate\Http\Request.php)? Because every time you do composer install on another machine, this will not apply. – Misbah Ahmad Mar 11 '21 at 16:48
81

Use request()->ip().

From what I understand, since Laravel 5 it's advised/good practice to use the global functions like:

response()->json($v);
view('path.to.blade');
redirect();
route();
cookie();

And, if anything, when using the functions instead of the static notation my IDE doesn't light up like a Christmas tree.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Stan Smulders
  • 6,079
  • 1
  • 27
  • 23
  • 4
    You are right that `request` is a "global" function - it's one of the global helper functions provided by laravel. However, the Request facade, isn't static (nor is the method ip) - `request()->foo`, and `Reqest::foo` and `$request->foo` are all identical. Have a look at this gist for an example: https://gist.github.com/cjke/026e3036c6a10c672dc5 – Chris Dec 30 '15 at 06:19
  • Yeah I know :) But it's written in the static syntax `::`. My IDE tends to light up light a christmas tree with those. The global functions just 'look' cleaner ;-) But to each his own! – Stan Smulders Dec 31 '15 at 10:37
  • 1
    Fair enough - both are equally correct. I just thought the bit where you said "it's not `Request::ip` might be misleading – Chris Jan 01 '16 at 07:35
  • You're absolutely right! Re-reading it I notice the second sentence should have read: `And since Laravel 5 it's (from what I understand) [recommended] to use the global functions like` My bad! That should have put things into perspective. – Stan Smulders Jan 02 '16 at 20:57
  • 3
    The problem is that these global functions aren't easily testable—they can't be mocked. Façades can be. I try to avoid global functions, since it means digging through to global function source to mock its calls, which is extra work, annoying, and shouldn't be my responsibility. – hackel Apr 07 '16 at 20:41
  • 1
    Although `request()->ip()` is correct, the surrounding text is really misleading - especially to say "it's not `Request::ip`. – Chris Nov 23 '16 at 06:24
  • 1
    @Chris Thanks, you're absolutely right. Edited for clarity! – Stan Smulders Nov 23 '16 at 06:42
  • @hackel Good point! Thanks for explaining that. I hardly ever mock so don't run into that problem but that definitely seems like something to be aware of! – Stan Smulders Nov 23 '16 at 06:43
  • $request->ip() L5.1 – mizan3008 Apr 05 '18 at 12:17
37

Add namespace

use Request;

Then call the function

Request::ip();
shalini
  • 1,291
  • 11
  • 13
  • 1
    If you have use namespace :--> use Illuminate\Http\Request; **bold** Rename namespace for request since both will clash – shalini Jan 19 '16 at 09:42
  • The original answer is correct. You need to import `use Request` because you're trying to use the Facade. The namespace you provided is for the underlying class. If you import that you will get an error because `ip()` can't be called statically, that's what the facade is for. – jfadich Feb 26 '16 at 02:03
  • If you're going to bother importing the class, you should use the actual façade, not the alias: `use Illuminate\Support\Facades\Request`. If not, just use `\Request::`. – hackel Apr 07 '16 at 20:43
  • Request::ip(); return me Server Ip. I want network Ip address . It is possible ??? – Suresh Kumar Kumawat Aug 25 '21 at 17:37
25

There are two things to take care of:

  1. Get a helper function that returns a Illuminate\Http\Request and call the ->ip() method:

    request()->ip();
    
  2. Think of your server configuration, it may use a proxy or load-balancer, especially in an AWS ELB configuration.

If this is your case you need to follow "Configuring Trusted Proxies" or maybe even set a "Trusting All Proxies" option.

Why? Because being your server will be getting your proxy/load-balancer IP instead.

If you are on the AWS balance-loader, go to App\Http\Middleware\TrustProxies and make $proxies declaration look like this:

protected $proxies = '*';

Now test it and celebrate because you just saved yourself from having trouble with throttle middleware. It also relies on request()->ip() and without setting "TrustProxies" up, you could have all your users blocked from logging in instead of blocking only the culprit's IP.

And because throttle middleware is not explained properly in the documentation, I recommend watching "laravel 5.2 tutorial for beginner, API Rate Limiting"

Tested in Laravel 5.7

Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
23

For Laravel 5 you can use the Request object. Just call its ip() method, something like:

$request->ip();
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Todor Todorov
  • 2,503
  • 1
  • 16
  • 15
19

In Laravel 5

public function index(Request $request) {
  $request->ip();
}
Govind Samrow
  • 9,981
  • 13
  • 53
  • 90
12

I tested in Laravel 8.x and you can use:

$request->ip()

For getting the client's IP address.

Pejman Kheyri
  • 4,044
  • 9
  • 32
  • 39
8

This below function will help you to give the client's IP address -

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;
    }
Soura Ghosh
  • 879
  • 1
  • 9
  • 16
7

In Laravel 5.4 we can't call ip static. This a correct way to get the IP of the user:

 use Illuminate\Http\Request;

public function contactUS(Request $request)
    {
        echo $request->ip();
        return view('page.contactUS');
    }
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Vahid Alvandi
  • 588
  • 9
  • 17
7

If you are still getting 127.0.0.1 as the IP, you need to add your "proxy", but be aware that you have to change it before going into production!

Read "Configuring Trusted Proxies".

And add this:

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array
     */
    protected $proxies = '*';

Now request()->ip() gives you the correct IP.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Philipp Mochine
  • 4,351
  • 10
  • 36
  • 68
5

If you want client IP and your server is behind aws elb, then user the following code. Tested for laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
  • 51
  • 1
  • 2
-1

If you have multiple layer proxies just like CDN + Load Balancer.
Using Laravel Request::ip() function will get right-most proxy IP but not client IP.
You may try following solution.

app/Http/Middleware/TrustProxies.php

protected $proxies = ['0.0.0.0/0'];

Reference: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215

Bing
  • 1
-1

I used the Sebastien Horin function getIp and request()->ip() (at global request), because to localhost the getIp function return null:

$this->getIp() ?? request()->ip();

The getIp function:

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;
            }
        }
    }
}

}

pedro.caicedo.dev
  • 2,269
  • 2
  • 16
  • 19
-1

Solution 1: You can use this type of function for getting client IP

public function getClientIPaddress(Request $request) {
    $clientIp = $request->ip();
    return $clientIp;
}

Solution 2: if the solution1 is not providing accurate IP then you can use this function for getting visitor real IP.

 public function getClientIPaddress(Request $request) {

    if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
        $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
        $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
    }
    $client  = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote  = $_SERVER['REMOTE_ADDR'];

    if(filter_var($client, FILTER_VALIDATE_IP)){
        $clientIp = $client;
    }
    elseif(filter_var($forward, FILTER_VALIDATE_IP)){
        $clientIp = $forward;
    }
    else{
        $clientIp = $remote;
    }

    return $clientIp;
 }

N.B: When you have used load-balancer/proxy-server in your production server then you need to used solution 2 for getting real visitor ip.

Majbah Habib
  • 8,058
  • 3
  • 36
  • 38
-1

This solution I used in my project. I found other solutions here either incomplete or too complex to understand.

if (! function_exists('get_visitor_IP'))
{
    /**
     * Get the real IP address from visitors proxy. e.g. Cloudflare
     *
     * @return string IP
     */
    function get_visitor_IP()
    {
        // Get real visitor IP behind CloudFlare network
        if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
            $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
            $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
        }

        // Sometimes the `HTTP_CLIENT_IP` can be used by proxy servers
        $ip = @$_SERVER['HTTP_CLIENT_IP'];
        if (filter_var($ip, FILTER_VALIDATE_IP)) {
           return $ip;
        }

        // Sometimes the `HTTP_X_FORWARDED_FOR` can contain more than IPs 
        $forward_ips = @$_SERVER['HTTP_X_FORWARDED_FOR'];
        if ($forward_ips) {
            $all_ips = explode(',', $forward_ips);

            foreach ($all_ips as $ip) {
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)){
                    return $ip;
                }
            }
        }

        return $_SERVER['REMOTE_ADDR'];
    }
}
Munna Khan
  • 1,902
  • 1
  • 18
  • 24
-1

In Laravel 7&8, I am using below methoths.

In Controller

use Illuminate\Http\Request;

public function index(Request $request)
{
    $request->ip();
    return view('users.index');
}

In Blade

Request::ip()

Anywhere

request()->ip()
bluestar0505
  • 338
  • 1
  • 14