LaravelでクライアントのIPアドレスを取得しようとしています。
PHPでクライアントのIPを取得するのは簡単$_SERVER["REMOTE_ADDR"]
です。コアPHPでは問題なく動作しますが、Laravelで同じものを使用すると、ビジターのIPではなくサーバーのIPが返されます。
LaravelでクライアントのIPアドレスを取得しようとしています。
PHPでクライアントのIPを取得するのは簡単$_SERVER["REMOTE_ADDR"]
です。コアPHPでは問題なく動作しますが、Laravelで同じものを使用すると、ビジターのIPではなくサーバーのIPが返されます。
回答:
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);
}
ロードバランサーを使用している場合、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が返されます。
を使用しrequest()->ip()
ます。
私が理解していることから、Laravel 5以降、次のようなグローバル関数を使用することが推奨/推奨されています:
response()->json($v);
view('path.to.blade');
redirect();
route();
cookie();
そして、どちらかといえば、静的表記の代わりに関数を使用すると、私のIDEがクリスマスツリーのように点灯しません。
request
、それはlaravelが提供するグローバルヘルパー関数の一つだ- 「グローバル」機能です。しかし、要求のファサードは、静的ではありません(でもメソッドのIPです) - request()->foo
、およびReqest::foo
と$request->foo
すべて同じです。例については、この要旨をご覧ください。gist.github.com
Request::ip
誤解を招くかもしれない
request()->ip()
正しいか、周囲のテキストは本当に誤解される-特にそれはありません」と言ってRequest::ip
。
名前空間を追加
use Request;
次に、関数を呼び出します
Request::ip();
use Request
Facadeを使用しようとしているため、インポートする必要があります。指定した名前空間は、基になるクラス用です。それをインポートするip()
と、静的に呼び出すことができないためエラーが発生します。それがファサードの目的です。
use Illuminate\Support\Facades\Request
。そうでない場合は、を使用してください\Request::
。
注意すべき点が2つあります。
を返すヘルパー関数を取得しIlluminate\Http\Request
、->ip()
メソッドを呼び出します。
request()->ip();
サーバー構成を考えてみてください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でテスト済み
Laravel 5.4では、ip staticを呼び出すことはできません。これは、ユーザーのIPを取得する正しい方法です。
use Illuminate\Http\Request;
public function contactUS(Request $request)
{
echo $request->ip();
return view('page.contactUS');
}
この関数を呼び出すと、クライアントの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;
}
それでもIPとして127.0.0.1を取得している場合は、「プロキシ」を追加する必要がありますが、運用に入る前に変更する必要があることに注意してください!
「信頼できるプロキシの設定」をお読みください。
そしてこれを追加してください:
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array
*/
protected $proxies = '*';
これでrequest()->ip()
正しいIPが得られます。
クライアントIPが必要で、サーバーがaws elbの背後にある場合は、次のコードを使用します。laravel 5.3でテスト済み
$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
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
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;
}
}
}
}
}
ユーザーが欲しいときip_address
:
$_SERVER['REMOTE_ADDR']
サーバーアドレスにしたい:
$_SERVER['SERVER_ADDR']