Я пытаюсь получить IP-адрес клиента в Laravel. Как мы все знаем, гораздо проще получить IP-адрес клиента в PHP с помощью $_SERVER["REMOTE_ADDR"]
.
Он отлично работает в основном PHP, но когда я использую то же самое в Laravel, он дает IP-адрес сервера вместо IP-адреса посетителя.
Глядя на 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);
}
Используйте 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/cjke/026e3036c6a10c672dc5
::
. Моя IDE имеет тенденцию зажигать рождественскую елку вместе с ними. Глобальные функции просто «выглядят» чище ;-) Но каждому свое!
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
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 в производстве
Добавить пространство имен
use Request;
Затем вызовите функцию
Request::ip();
use Request
потому что вы пытаетесь использовать Фасад. Предоставленное вами пространство имен предназначено для базового класса. Если вы импортируете это, вы получите ошибку, потому что ip()
не может быть вызван статически, для этого предназначен фасад.
Для Laravel 5 вы можете использовать объект Request. Просто вызовите его метод ip(). Что-то вроде:
$request->ip();
В Laravel 5
public function index(Request $request) {
$request->ip();
}
Если вы хотите, чтобы клиентский IP-адрес и ваш сервер находились за aws-elb, тогда введите следующий код. Протестировано для laravel 5.3
$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
в версии laravel 5.4 мы не можем вызвать ip static, это правильный способ получить ip пользователя
use Illuminate\Http\Request;
public function contactUS(Request $request)
{
echo $request->ip();
return view('page.contactUS');
}
Если вы все еще получаете 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
Если вы вызываете эту функцию, вы легко получаете 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;
}
Есть 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
В новой версии вы можете получить его с запросом помощника
request()->ip();
Когда нам нужен пользователь ip_address
:
$_SERVER['REMOTE_ADDR']
и хотите адрес сервера:
$_SERVER['SERVER_ADDR']