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

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

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


person Amrinder Singh    schedule 21.10.2015    source источник


Ответы (19)


Взглянув на 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);
} 
person samlev    schedule 21.10.2015
comment
Использование объекта Request у меня не работает, он возвращает адрес моего сервера Homestead. 192.168.10.10, который, очевидно, не является моим IP-адресом. - person Vince Kronlein; 13.01.2017
comment
@VinceKronlein для вашего случая проверьте этот ответ stackoverflow.com/a/41769505/3437790 - person Sebastien Horin; 08.09.2017
comment
@VinceKronlein в вашем случае это было очень правильно. Поскольку вы заходили в Homestead, в вашей ЛОКАЛЬНОЙ сети у вас был 192. IP. если бы вы получали доступ к чужому серверу через Интернет, ваш IP-адрес будет выходить через вашего интернет-провайдера, а ваш общедоступный будет использоваться. - person ied3vil; 23.04.2018
comment
Чтобы получить текущий ip пользователя в php, laravel \ Request :: ip (); ИЛИ $ request- ›ip (); - person Hassan Joseph; 19.05.2021

Если вы используете балансировщик нагрузки, \Request::ip() всегда Laravel возвращает 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 throttle: оно также использует Laravel Request::ip(), поэтому все ваши посетители будут идентифицированы как один и тот же пользователь, и вы очень быстро достигнете предела газа. . Я испытал это вживую, и это вызвало большие проблемы.

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

Освещение \ Http \ Request.php

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

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

person Sebastien Horin    schedule 20.01.2017
comment
правильно if (filter_var ...) внутри второго foreach? этот код никогда не будет выполнен. - person Mistre83; 03.02.2017
comment
@ Mistre83 Да вы правы, я думаю это тестовая оплошность. Обновляю! - person Sebastien Horin; 03.02.2017
comment
это действительно работает с laravel 5.4. Пожалуйста, подумайте о создании PR на github. Я думаю, это должно быть поведение по умолчанию - person Crystal; 05.04.2017
comment
Это сработало в Laravel 5.3, когда метод ip () объекта запроса Laravel продолжал возвращать 127.0.0.1 - person w5m; 26.06.2017
comment
Не можете ли вы исправить это с помощью доверенных прокси? - laravel.com/docs/master/requests#configuring-trusted-proxies - person user2722667; 14.06.2018
comment
Спасибо, ваш ответ помог мне больше, чем я думал. Но есть способ лучше решить эту проблему, см. Мой ответ. - person Yevgeniy Afanasyev; 19.12.2018
comment
@YevgeniyAfanasyev не уверен насчет protected $proxies = '*'; с точки зрения безопасности, при чтении заголовков безобидно - person Sebastien Horin; 19.12.2018
comment
Думаю одна труба | знак отсутствует после FILTER_FLAG_NO_PRIV_RANGE FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE кроме этого он отлично работает для меня Спасибо @SebastienHorin - person Deepak Sharma; 28.03.2019
comment
если клиент использует VPN, будет ли этот код извлекать поддельный IP-адрес или реальный IP-адрес? - person Syamsoul Azrien; 21.04.2020
comment
Чтобы ответить @SyamsoulAzrien, это может быть невозможно из-за наличия IP-адреса пользователя до того, как запрос был выполнен, поэтому IP-адрес vpn был настоящим - person daison12006013; 12.12.2020
comment
Что касается второй части ответа, разумно ли редактировать основной файл фреймворка (Illuminate \ Http \ Request.php)? Поскольку каждый раз, когда вы устанавливаете композитор на другой компьютер, это не применяется. - person Misbah Ahmad; 11.03.2021

Используйте 1_.

Насколько я понимаю, начиная с Laravel 5 рекомендуется / хорошая практика использовать глобальные функции, такие как:

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

И, во всяком случае, при использовании функций вместо статической нотации моя IDE не загорается, как рождественская елка.

person Stan Smulders    schedule 10.12.2015
comment
Вы правы, что request - это глобальная функция - это одна из глобальных вспомогательных функций, предоставляемых laravel. Однако фасад запроса не является статическим (как и метод ip) - request()->foo, а также Reqest::foo и $request->foo идентичны. Взгляните на эту суть для примера: gist.github.com/cjke/026e3036c6a10c672dc5 - person Chris; 30.12.2015
comment
Да я знаю :) Но это написано в статическом синтаксисе ::. Моя IDE имеет тенденцию зажигать ими елку. Глобальные функции просто «выглядят» чище ;-) Но каждому свое! - person Stan Smulders; 31.12.2015
comment
Справедливо - оба одинаково правы. Я просто подумал, что ты сказал, что это не Request::ip, может вводить в заблуждение - person Chris; 01.01.2016
comment
Вы совершенно правы! Перечитывая его, я замечаю, что второе предложение должно было читаться следующим образом: And since Laravel 5 it's (from what I understand) [recommended] to use the global functions like Моя плохая! Это должно было увидеть ситуацию в перспективе. - person Stan Smulders; 02.01.2016
comment
Проблема в том, что эти глобальные функции нелегко протестировать - над ними нельзя издеваться. Фасады могут быть. Я стараюсь избегать глобальных функций, поскольку это означает копаться в источнике глобальной функции, чтобы имитировать ее вызовы, что является дополнительной работой, раздражает и не должно быть моей обязанностью. - person hackel; 07.04.2016
comment
Хотя request()->ip() правильно, окружающий текст действительно вводит в заблуждение - особенно если сказать, что это не Request::ip. - person Chris; 23.11.2016
comment
@Chris Спасибо, вы абсолютно правы. Отредактировано для наглядности! - person Stan Smulders; 23.11.2016
comment
@hackel Хороший вопрос! Спасибо, что объяснили это. Я почти никогда не издеваюсь, поэтому не сталкивайтесь с этой проблемой, но это определенно похоже на то, что нужно знать! - person Stan Smulders; 23.11.2016
comment
@StanSmulders Ура! - person Chris; 23.11.2016
comment
$ request- ›ip () L5.1 - person mizan3008; 05.04.2018

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

use Request;

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

Request::ip();
person shalini    schedule 19.01.2016
comment
Если у вас есть пространство имен use: - ›используйте Illuminate \ Http \ Request; полужирным шрифтом Переименовать пространство имен для запроса, так как оба будут конфликтовать - person shalini; 19.01.2016
comment
Исходный ответ правильный. Вам нужно импортировать use Request, потому что вы пытаетесь использовать фасад. Предоставленное вами пространство имен предназначено для базового класса. Если вы импортируете это, вы получите сообщение об ошибке, потому что ip() не может быть вызван статически, для этого и нужен фасад. - person jfadich; 26.02.2016
comment
Если вы собираетесь импортировать класс, вам следует использовать фактический фасад, а не псевдоним: use Illuminate\Support\Facades\Request. Если нет, просто используйте \Request::. - person hackel; 07.04.2016

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

$request->ip();
person Todor Todorov    schedule 07.03.2016

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

  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-адрес преступника.

А поскольку промежуточное программное обеспечение throttle не объясняется должным образом в документации, я рекомендую посмотреть "руководство по laravel 5.2 для начинающих, API Ограничение скорости "

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

person Yevgeniy Afanasyev    schedule 18.12.2018

В Laravel 5

public function index(Request $request) {
  $request->ip();
}
person Govind Samrow    schedule 21.06.2016

В Laravel 5.4 мы не можем называть ip static. Это правильный способ получить IP пользователя:

 use Illuminate\Http\Request;

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

Если вы вызовете эту функцию, вы легко получите 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;
    }
person Soura Sankar Ghosh    schedule 23.01.2019

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

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

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

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

Теперь request()->ip() дает вам правильный IP.

person Philipp Mochine    schedule 29.01.2019
comment
@ Huzaifa99 странно, у меня это работало какое-то время, но не то, что не работает! Как странно (вы нашли другое решение?) - person Philipp Mochine; 08.10.2020

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

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
person Aung Bo    schedule 24.10.2017
comment
Больше не работает, теперь нужен trustHeaderSet - person Philipp Mochine; 29.01.2019
comment
последние версии laravel см. в документации laravel.com/docs/5.5/requests# настройка доверенных прокси - person Sandra; 30.09.2019

Вы можете получить несколько способов IP-адреса, используя Request ip, Request getClientIp и работу с партнером по ходатайству. В этой модели я расскажу вам лучший способ получить текущий IP-адрес клиента в laravel 5.8.

$clientIP = request()->ip();

dd($clientIP);

Вы можете следить за этим здесь

person hammad khan    schedule 18.08.2020

Решение 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;
 }

NB: если вы использовали балансировщик нагрузки / прокси-сервер на своем действующем сервере, вам необходимо использовать решение 2 для получения реального ip посетителя.

person Majbah Habib    schedule 21.09.2020

Если вы беспокоитесь о получении IP-адреса, но не нуждаетесь или хотите использовать какие-либо функции Laravel, вы можете использовать только php:

PHP ‹5.3.0
$ localIP = getHostByName (php_uname ('n'));

PHP ›= 5.3.0
$ localIP = getHostByName (getHostName ());

как ответили в этой теме: PHP, как получить локальный IP-адрес системы

person jarno punt    schedule 03.09.2020

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

приложение / Http / Middleware / TrustProxies.php

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

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

person Bing    schedule 09.04.2020

Я использовал функции Себастьяна Хорина 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;
            }
        }
    }
}

}

person pedro.caicedo.dev    schedule 27.07.2020

Это решение я использовал в своем проекте. Я нашел здесь другие решения, либо неполные, либо слишком сложные для понимания.

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'];
    }
}
person Munna Khan    schedule 25.05.2021

Когда мы хотим, чтобы пользователь ip_address:

$_SERVER['REMOTE_ADDR']

и хотите получить адрес сервера:

$_SERVER['SERVER_ADDR']
person shashikant parmar    schedule 10.08.2016

person    schedule
comment
Будет лучше, если вы объясните, почему это предпочтительное решение, и объясните, как оно работает. Мы хотим обучать, а не просто предоставлять код. В настоящее время система отмечает его как низкое качество, поэтому постарайтесь улучшить его. - person the Tin Man; 30.12.2019
comment
Спасибо за ваше предложение. - person rashedcs; 31.12.2019