如何获得客户端 IP 地址在 Laravel5 +

我想知道客户在 Laravel 的 IP 地址。

通过使用 $_SERVER["REMOTE_ADDR"]可以很容易地在 PHP 中获得客户端的 IP。它在核心 PHP 中工作得很好,但是当我在 Laravel 使用同样的东西时,它返回的是服务器 IP 而不是访问者的 IP。

349857 次浏览

看看 Laravel API:

Request::ip();

在内部,它使用来自 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);
}

使用 request()->ip()

据我所知,自从 Laravel 5以来,建议/好的做法是使用如下全局函数:

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

而且,如果使用函数而不是静态符号的话,我的 IDE 不会像圣诞树一样亮起来。

添加名称空间

use Request;

然后调用函数

Request::ip();

对于 Laravel 5,你可以使用 Request 对象,只需调用它的 ip()方法,比如:

$request->ip();

在 Laravel 5

public function index(Request $request) {
$request->ip();
}

当我们想要用户的 ip_address:

$_SERVER['REMOTE_ADDR']

并希望服务器地址:

$_SERVER['SERVER_ADDR']

如果你在负载平衡器下,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;
}
}
}
}
return request()->ip(); // it will return server ip when no client ip found
}

除此之外,我建议你在使用 Laravel 的 油门中间件时要非常小心: 它也使用了 Laravel 的 Request::ip(),所以你的所有访问者都将被识别为同一个用户,你将很快达到油门限制。我亲身经历过,这引起了很大的问题。

为了解决这个问题:

照明 Http Request.php

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

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

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

 use Illuminate\Http\Request;


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

如果您想要客户端 IP 并且您的服务器位于 aws elb 之后,那么使用以下代码。测试了幼虫5.3

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

有两件事需要注意:

  1. 获取一个返回 Illuminate\Http\Request并调用 ->ip()方法的 helper 函数:

    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 = '*';

现在测试它并庆祝一下,因为您刚刚避免了在使用油门中间件时遇到麻烦。它还依赖于 request()->ip(),如果不设置“ TrustProxy”,就可以阻止所有用户登录,而不仅仅是阻止罪魁祸首的 IP。

由于文档中没有正确解释油门中间件,因此我建议观看“ Laravel 5.2初学者教程,API 速率限制

在 Laravel 5.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;
}

如果您仍然得到127.0.0.1作为 IP,您需要添加您的“代理”,但是要注意,您必须在投入生产之前更改它!

读“ 配置可信代理”。

再加上这个:

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

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

  $ip = $_SERVER['REMOTE_ADDR'];

如果您有多层代理,就像 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 地址,但不需要或不想使用任何 Laravel 功能,可以只使用 php:

PHP < 5.3.0

$localIP = getHostByName(php_uname('n'));

PHP > = 5.3.0

$localIP = getHostByName(getHostName());

正如在这个帖子中所回答的: 如何获取系统的本地 IP

解决方案1: 您可以使用这种类型的函数来获取客户端 IP

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

解决方案2: 如果解决方案1是 没有提供准确的 IP 地址,那么您可以使用这个函数来获得访问者真正的 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;
}

注意: 当你在实时服务器上使用 负载平衡器/代理服务器时,你需要使用 解决方案2来获得真正的访问者 ip。

我在我的项目中使用的这个解决方案。我发现这里的其他解决方案要么不完整,要么太复杂以至于难以理解。

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

我在 Laravel 8.x 中测试过,你可以使用:

$request->ip()

获取客户的 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 () ,这样所有的访问者都会被识别为同一个用户,你很快就会达到油门限制。我亲身经历过,这引起了很大的问题。

为了解决这个问题:

照明 Http Request.php

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

现在还可以使用 Request: : IP () ,它应该在生产中返回真正的 IP。