Как получить IP-адрес клиента в Laravel 5+


136

Я пытаюсь получить IP-адрес клиента в Laravel.

Получить IP-адрес клиента в PHP легко, используя $_SERVER["REMOTE_ADDR"]. Он отлично работает в основном PHP, но когда я использую то же самое в Laravel, он возвращает IP-адрес сервера вместо IP-адреса посетителя.

Ответы:


195

Посмотрим на Laravel API :

Request::ip();

Внутри он использует getClientIpsметод из объекта запроса Symfony :

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-адресом.
Винс Кронлайн

@VinceKronlein для вашего случая, проверьте этот ответ stackoverflow.com/a/41769505/3437790
Себастьен Хорин

3
@VinceKronlein в вашем случае это было очень правильно. Поскольку вы заходили в Homestead в ЛОКАЛЬНОЙ сети, у вас был 192. IP. если бы вы получали доступ к чужому серверу приусадебного типа через Интернет, ваш 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 throttle : оно использует Laravel'sRequest::ip() , так что все ваши посетители будут идентифицированы как тот же пользователь , и вы будете очень быстро ударили дроссельный предел. Я испытал это вживую, и это вызвало большие проблемы.

Чтобы исправить это:

Осветите \ Http \ Request.php

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

Теперь вы также можете использовать Request::ip(), который должен возвращать реальный IP-адрес в производстве.


1
правильно if (filter_var ...) внутри второго foreach? этот код никогда не будет выполнен.
Mistre83

@ Mistre83 Да вы правы, я думаю это тестовая оплошность. Обновляю!
Себастьян Хорин

6
это действительно работает с laravel 5.4. Пожалуйста, подумайте о создании PR на github. Я думаю, это должно быть поведение по умолчанию
Кристалл

1
Это сработало в Laravel 5.3, когда метод ip () объекта запроса Laravel продолжал возвращать 127.0.0.1
w5m

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. Однако запрос фасад, не является статичным (ни метод ф) - request()->fooи Reqest::fooи $request->fooвсе одинаковые. Взгляните на эту суть для примера: gist.github.com/cjke/026e3036c6a10c672dc5
Крис

1
Справедливо - оба одинаково правы. Я просто подумал, что ты сказал: «Это не Request::ipможет вводить в заблуждение»
Крис

3
Проблема в том, что эти глобальные функции нелегко протестировать - их нельзя подделать. Фасады могут быть. Я стараюсь избегать глобальных функций, поскольку это означает копаться в источнике глобальной функции, чтобы имитировать ее вызовы, что является дополнительной работой, раздражает и не должно быть моей обязанностью.
hackel

1
Хотя request()->ip()правильно, окружающий текст действительно вводит в заблуждение - особенно сказать «это не Request::ip.
Chris

1
@Chris Спасибо, вы абсолютно правы. Отредактировано для наглядности!
Стэн Смолдерс

27

Добавить пространство имен

use Request;

Затем вызовите функцию

Request::ip();

1
Если у вас есть пространство имен use: -> используйте Illuminate \ Http \ Request; полужирным шрифтом Переименовать пространство имен для запроса, поскольку оба будут конфликтовать
shalini

Исходный ответ правильный. Вам нужно импортировать, use Requestпотому что вы пытаетесь использовать фасад. Предоставленное вами пространство имен предназначено для базового класса. Если вы импортируете это, вы получите ошибку, потому что ip()не может быть вызван статически, для этого и нужен фасад.
jfadich

Если вы собираетесь беспокоить импортировать класс, вы должны использовать фактический фасад, а не псевдоним: use Illuminate\Support\Facades\Request. Если нет, просто используйте \Request::.
hackel

18

Для Laravel 5 вы можете использовать объект Request. Просто вызовите его ip()метод, например:

$request->ip();


12

Необходимо позаботиться о двух вещах:

  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

Если вы все еще получаете 127.0.0.1 в качестве IP-адреса, вам необходимо добавить свой «прокси», но имейте в виду, что вы должны изменить его перед запуском в производство!

Прочтите « Настройка доверенных прокси ».

И добавьте это:

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
Больше не работает, теперь нужен "trustHeaderSet"
Shadrix

для «последних» версий laravel см. документацию laravel.com/docs/5.5/requests#configuring-trusted-proxies
Сандра

0

Если у вас многоуровневые прокси, такие как CDN + Load Balancer.
Использование функции Laravel Request :: ip () получит самый правый IP-адрес прокси, но не IP-адрес клиента.
Вы можете попробовать следующее решение.

приложение / Http / Промежуточное / TrustProxies.php

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

Ссылка: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215


0

Я использовал функции Себастьяна Хорина getIp и request () -> ip () (по глобальному запросу), потому что для localhost функция 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.