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

85

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

Он отлично работает в основном PHP, но когда я использую то же самое в Laravel, он дает IP-адрес сервера вместо IP-адреса посетителя.

Теги:
laravel-5
laravel-5.1
laravel-5.7

13 ответов

126
Лучший ответ

Глядя на 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);
} 
  • 2
    Использование объекта Request не работает для меня, оно возвращает адрес моего сервера Homestead. 192.168.10.10, который явно не мой IP-адрес.
  • 0
    @VinceKronlein для вашего случая, проверьте этот ответ stackoverflow.com/a/41769505/3437790
Показать ещё 1 комментарий
52

Используйте 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/cjke/026e3036c6a10c672dc5
  • 0
    Да, я знаю :) Но это написано в статическом синтаксисе :: . Моя IDE имеет тенденцию зажигать рождественскую елку вместе с ними. Глобальные функции просто «выглядят» чище ;-) Но каждому свое!
Показать ещё 8 комментариев
45

Если вы находитесь под балансировщиком нагрузки

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: Он использует Laravel Request::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? этот код никогда не будет выполнен.
  • 0
    @ Mistre83 Да, вы правы, я думаю, что это тестовый недосмотр. Я обновляю это!
Показать ещё 7 комментариев
21

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

use Request;

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

Request::ip();
  • 0
    Если у вас есть пространство имен: -> используйте Illuminate \ Http \ Request; Жирный переименовать пространство имен для запроса, так как оба будут конфликтовать
  • 0
    Оригинальный ответ правильный. Вам нужно импортировать use Request потому что вы пытаетесь использовать Фасад. Предоставленное вами пространство имен предназначено для базового класса. Если вы импортируете это, вы получите ошибку, потому что ip() не может быть вызван статически, для этого предназначен фасад.
Показать ещё 1 комментарий
12

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

$request->ip();

9

В Laravel 5

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

Если вы хотите, чтобы клиентский IP-адрес и ваш сервер находились за aws-elb, тогда введите следующий код. Протестировано для laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
  • 0
    Больше не работает, теперь нужен "rustHeaderSet "
2

в версии laravel 5.4 мы не можем вызвать ip static, это правильный способ получить ip пользователя

 use Illuminate\Http\Request;

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

Если вы все еще получаете 127.0.0.1 в качестве IP-адреса, вам нужно добавить свой "прокси".

Но будьте осторожны, что вы должны изменить его перед началом производства!

Прочитайте эту часть: https://laravel.com/docs/5.7/requests#configuring-trusted-proxies

А теперь просто добавьте это:

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

Теперь request() → ip() дает вам правильный ip

0

Если вы вызываете эту функцию, вы легко получаете 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;
    }
0

Есть 2 вещи, о которых нужно позаботиться

1) получить вспомогательную функцию, которая возвращает метод Illuminate\Http\Request и вызвать ->ip().

request()->ip();

2) Подумайте о конфигурации вашего сервера, он может использовать proxy или load balancer (особенно в конфигурации AWS ELB)

Если это ваш случай, вам нужно настроить доверенные прокси или, возможно, даже установить опцию Trusting All Proxies.

Зачем?

Потому что, будучи вашим сервером, вы получите ваш IP прокси/балансировщика.

Как?

Если вы не используете AWS balance-loader

Перейдите в App\Http\Middleware\TrustProxies

и сделать объявление $proxies похожим на это:

protected $proxies = '*';

Теперь проверьте это и будьте счастливы, потому что вы только что избавили себя от проблем с throttle middleware. Он также полагается на request()->ip() и без настройки TrustProxies вы можете TrustProxies всем своим пользователям вход в систему вместо того, чтобы блокировать только IP-адрес виновника.

А поскольку throttle middleware не описано должным образом в документации, я рекомендую посмотреть это видео

Протестировано в Laravel 5.7

0

В новой версии вы можете получить его с запросом помощника

request()->ip();
-2

Когда нам нужен пользователь ip_address:

$_SERVER['REMOTE_ADDR']

и хотите адрес сервера:

$_SERVER['SERVER_ADDR']

Ещё вопросы

Сообщество Overcoder
Наверх
Меню