I am trying to get the client's IP address in Laravel. As we all know that it is pretty much easier to get a client's IP in PHP by using $_SERVER["REMOTE_ADDR"]
.
It is working fine in core PHP, but when I use the same thing in Laravel, then it gives server IP instead of visitor IP.
Looking at the Laravel API:
Request::ip();
Internally, it uses the getClientIps
method from the Symfony Request Object:
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);
}
Use request()->ip()
Since Laravel 5 it's (from what I understand) advised / good practice to use the global functions like:
response()->json($v);
view('path.to.blade');
redirect();
route();
cookie();
You get the point :-) And if anything, when using the functions (instead of the static notarion) my IDE doesn't ligt up like a christmas tree ;-)
If you are under a load balancer
Laravel's \Request::ip()
always return the balancer's 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
This custom method returns the real client 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;
}
}
}
}
}
More: If you use the Laravel's throttle middleware
In addition to this I suggest you to be very careful using the Laravel's throttle middleware: It uses the Laravel's Request::ip()
as well, so all your visitors will be identified as the same user and you will hit the throttle limit very quickly. Experienced in live...this led me to big issues...
To fix this:
Illuminate\Http\Request.php
public function ip()
{
//return $this->getClientIp(); //original method
return $this->getIp(); // the above method
}
You can now also use Request::ip()
, which should return the real IP in production
Add namespace
use Request;
Then call the function
Request::ip();
For Laravel 5 you can use the Request object. Just call its ip() method. Something like:
$request->ip();
In Laravel 5
public function index(Request $request) {
$request->ip();
}
If you are still getting 127.0.0.1 as IP, you need to add your "proxy".
But beware that you have to change it before going production!!
Read this part: https://laravel.com/docs/5.7/requests#configuring-trusted-proxies
And now just add this:
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array
*/
protected $proxies = '*';
Now request()->ip() gives you the correct ip
in version laravel 5.4 we can't call ip static this a correct way to get ip user
use Illuminate\Http\Request;
public function contactUS(Request $request)
{
echo $request->ip();
return view('page.contactUS');
}
If you want client IP and your server is behind aws elb, then user the following code. Tested for laravel 5.3
$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
If you call this function then you easily get the client IP address. I have already used this useful code in my existing project.
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;
}
There are 2 things to take care of
1) get helper function that returns a Illuminate\Http\Request
and call ->ip()
method.
request()->ip();
2) Think of your server configuration, it may use proxy
or load balancer
(especially in AWS ELB
config)
If this is your case you need to Configuring Trusted Proxies or maybe even set a Trusting All Proxies
option.
Why?
Because being your server will be getting your proxy/balance-loader IP instead.
How?
If you are no AWS balance-loader
Go to App\Http\Middleware\TrustProxies
and make $proxies
declaration look like this:
protected $proxies = '*';
Now test it and celebrate, because you just saved yourself from having trouble with throttle middleware
. It also relies on request()->ip()
and without setting TrustProxies
up, you could have all your users blocked from logging in instead of blocking only the culprit's IP.
And because throttle middleware
is not explained properly in documentation, I recommend watch this video
Tested in Laravel 5.7
When we want the user's ip_address
:
$_SERVER['REMOTE_ADDR']
and want to server address:
$_SERVER['SERVER_ADDR']
来源:https://stackoverflow.com/questions/33268683/how-to-get-client-ip-address-in-laravel-5