Laravel 5+でクライアントIPアドレスを取得する方法


136

LaravelでクライアントのIPアドレスを取得しようとしています。

PHPでクライアントのIPを取得するのは簡単$_SERVER["REMOTE_ADDR"]です。コアPHPでは問題なく動作しますが、Laravelで同じものを使用すると、ビジターのIPではなくサーバーのIPが返されます。

回答:


194

Laravel APIを見る:

Request::ip();

内部getClientIps的には、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);
} 

3
Requestオブジェクトを使用しても機能しません。Homesteadサーバーのアドレスを返します。192.168.10.10これは明らかに私のIPアドレスではありません。
Vince Kronlein 2017年

あなたのケースのための@VinceKronleinこの回答のチェックstackoverflow.com/a/41769505/3437790
セバスチャンHorin

3
あなたの場合、@ VinceKronleinはとても正しかったです。ホームステッドにアクセスしていたため、ローカルネットワークでは、tje 192がありました。IP。インターネットを介して他の誰かのホームステッドサーバーにアクセスしている場合、IPはISPを介して送信され、パブリックIPが使用されます。
ied3vil

83

ロードバランサーを使用している場合、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

このカスタムメソッドは、実際のクライアント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;
                }
            }
        }
    }
}

これに加えて、私はあなたがLaravelの使用は非常に慎重であることを示唆スロットルミドルウェア:それはLaravelの使用していますRequest::ip()もため、すべての訪問者が同じユーザーとして識別され、スロットルの制限にすぐに到達します。私はこのライブを経験し、これが大きな問題を引き起こしました。

これを修正するには:

Illuminate \ Http \ Request.php

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

を使用することもできますRequest::ip()。これにより、本番環境で実際のIPが返されます。


1
2番目のforeach内のif(filter_var ...)は正しいですか?このコードは実行されません。
Mistre83

@ Mistre83はい、そうです、それはテストの監視だと思います。更新します!
セバスチャンホリン2017

6
これは実際にはlaravel 5.4で動作します。githubでPRを作成することを検討してください。これはデフォルトの動作であると思います
Crystal

1
Laravelリクエストオブジェクトのip()メソッドが127.0.0.1を返し続けたとき、これはLaravel 5.3の扱いとして機能しました
でした

3
信頼できるプロキシでこれを修正できませんか?- laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667

74

を使用しrequest()->ip()ます。

私が理解していることから、Laravel 5以降、次のようなグローバル関数を使用することが推奨/推奨されています:

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

そして、どちらかといえば、静的表記の代わりに関数を使用すると、私のIDEがクリスマスツリーのように点灯しません。


3
あなたは正しいですrequest、それはlaravelが提供するグローバルヘルパー関数の一つだ- 「グローバル」機能です。しかし、要求のファサードは、静的ではありません(でもメソッドのIPです) - request()->foo、およびReqest::foo$request->fooすべて同じです。例については、この要旨をご覧ください。gist.github.com
Chris

1
十分に公平です-どちらも同じように正しいです。私はちょうどあなたはそれがありません」と述べビットが考えRequest::ip誤解を招くかもしれない
クリス

3
問題は、これらのグローバル関数を簡単にテストできないことです。これらを模倣することはできません。ファサードにすることができます。グローバル関数を回避しようとします。これは、グローバル関数のソースを調べて呼び出しを模擬することを意味します。これは余分な作業であり、煩わしく、私の責任ではありません。
hackel

1
request()->ip()正しいか、周囲のテキストは本当に誤解される-特にそれはありません」と言ってRequest::ip
クリス・

1
@クリスありがとう、あなたは絶対的に正しいです。明確にするために編集されました!
スタンスマルダース2016年

27

名前空間を追加

use Request;

次に、関数を呼び出します

Request::ip();

1
名前空間を使用している場合:-> use Illuminate \ Http \ Request; 両方が
競合

元の答えは正しいです。use RequestFacadeを使用しようとしているため、インポートする必要があります。指定した名前空間は、基になるクラス用です。それをインポートするip()と、静的に呼び出すことができないためエラーが発生します。それがファサードの目的です。
jfadich 2016

クラスをインポートする必要がある場合は、エイリアスではなく、実際のファサードを使用する必要がありますuse Illuminate\Support\Facades\Request。そうでない場合は、を使用してください\Request::
hackel

18

Laravel 5の場合、Requestオブジェクトを使用できます。そのip()メソッドを呼び出すだけです:

$request->ip();


12

注意すべき点が2つあります。

  1. を返すヘルパー関数を取得しIlluminate\Http\Request->ip()メソッドを呼び出します。

    request()->ip();
  2. サーバー構成を考えてみてくださいload-balancer。特にAWS ELB構成では、プロキシまたはを使用する場合があります。

これが当てはまる場合は、「信頼できるプロキシの構成」に従うか、「すべてのプロキシを信頼する」オプションを設定する必要があるかもしれません。

どうして?あなたのサーバーであることはload-balancer代わりにあなたのプロキシ/ IPを取得するためです。

AWSバランスローダーを使用している場合は、に移動しApp\Http\Middleware\TrustProxies$proxies宣言を次のようにします。

protected $proxies = '*';

スロットルミドルウェアの問題から自分を救っただけなので、テストして祝いましょう。またrequest()->ip()、「TrustProxies」を設定せずに依存しているため、犯人のIPのみをブロックするのではなく、すべてのユーザーのログインをブロックすることもできます。

また、スロットルミドルウェアはドキュメントで適切に説明されていないため、「初心者向けのlaravel 5.2チュートリアル、APIレート制限」を視聴することをお勧めします

Laravel 5.7でテスト済み


7

Laravel 5.4では、ip staticを呼び出すことはできません。これは、ユーザーのIPを取得する正しい方法です。

 use Illuminate\Http\Request;

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

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

5

それでもIPとして127.0.0.1を取得している場合は、「プロキシ」を追加する必要がありますが、運用に入る前に変更する必要があることに注意してください!

信頼できるプロキシの設定」をお読みください。

そしてこれを追加してください:

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

これでrequest()->ip()正しいIPが得られます。


4

クライアントIPが必要で、サーバーがaws elbの背後にある場合は、次のコードを使用します。laravel 5.3でテスト済み

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

1
機能しなくなったため、「trustedHeaderSet」が不要になりました
Shadrix

「最新」のlaravelバージョンについては、docs laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra

0

CDN +ロードバランサーのように複数のレイヤープロキシがある場合。
Laravel Request :: ip()関数を使用すると、右端のプロキシIPが取得されますが、クライアントIPは取得されません。
次の解決策を試すことができます。

app / Http / Middleware / TrustProxies.php

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

リファレンス:https : //github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215


0

Sebastien Horin関数getIpとrequest()-> ip()を使用しました(グローバルリクエストの場合)。getIp関数をローカルホストするとnullが返されるためです。

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

getIp関数:

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

}


-2

ユーザーが欲しいときip_address

$_SERVER['REMOTE_ADDR']

サーバーアドレスにしたい:

$_SERVER['SERVER_ADDR']

-2
  $ip = $_SERVER['REMOTE_ADDR'];

1
これが望ましいソリューションである理由と、それがどのように機能するかを説明すると、さらに役立ちます。コードを提供するだけでなく、教育したいと考えています。現状では、システムによって低品質としてフラグが立てられているため、改善を試みてください。
ティンマン

提案ありがとう。
rashedcs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.