CloudFlare and logging visitor IP addresses via in PHP - php

I'm trying to track and log users/visitors that are accessing my website using PHP's $_SERVER['REMOTE_ADDR'] to do so. A typical method for IP address tracking in PHP.
However, I am using CloudFlare for caching and such and receiving their IP addresses as CloudFlare's:
108.162.212.* - 108.162.239.*
What would be a correct method of retrieving the actual users/visitors IP address while still using CloudFlare?

Extra server variables that are available to cloud flare are:
$_SERVER["HTTP_CF_CONNECTING_IP"] real visitor ip address, this is what you want
$_SERVER["HTTP_CF_IPCOUNTRY"] country of visitor
$_SERVER["HTTP_CF_RAY"]
$_SERVER["HTTP_CF_VISITOR"] this can help you know if its http or https
you can use it like this:
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
If you do this, and the validity of the visiting IP address is important, you might need to verify that the $_SERVER["REMOTE_ADDR"] contains an actual valid cloudflare IP address, because anyone can fake the header if he was able to connect directly to the server IP.

Update: CloudFlare has released a module mod_cloudflare for apache, the module will log and display the actual visitor IP Addresses rather than those accessed by cloudflare! https://www.cloudflare.com/resources-downloads#mod_cloudflare (Answer by: olimortimer)
If you dont have access to the apache runtime you can use the script below, this will allow you to check if the connection was through cloudflare and get the users ip.
I am rewriting my answer i used for another question "CloudFlare DNS / direct IP identifier"
Cloudflare's ips are stored in public so you can go view them here then check if the ip is from cloudflare (this will allow us to get the real ip from the http header HTTP_CF_CONNECTING_IP).
If you are using this to disable all non cf connections or vice versa, i recommend you to have a single php script file that gets called before every other script such as a common.php or pagestart.php etc.
function ip_in_range($ip, $range) {
if (strpos($range, '/') == false)
$range .= '/32';
// $range is in IP/CIDR format eg 127.0.0.1/24
list($range, $netmask) = explode('/', $range, 2);
$range_decimal = ip2long($range);
$ip_decimal = ip2long($ip);
$wildcard_decimal = pow(2, (32 - $netmask)) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return (($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal));
}
function _cloudflare_CheckIP($ip) {
$cf_ips = array(
'199.27.128.0/21',
'173.245.48.0/20',
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'141.101.64.0/18',
'108.162.192.0/18',
'190.93.240.0/20',
'188.114.96.0/20',
'197.234.240.0/22',
'198.41.128.0/17',
'162.158.0.0/15',
'104.16.0.0/12',
);
$is_cf_ip = false;
foreach ($cf_ips as $cf_ip) {
if (ip_in_range($ip, $cf_ip)) {
$is_cf_ip = true;
break;
}
} return $is_cf_ip;
}
function _cloudflare_Requests_Check() {
$flag = true;
if(!isset($_SERVER['HTTP_CF_CONNECTING_IP'])) $flag = false;
if(!isset($_SERVER['HTTP_CF_IPCOUNTRY'])) $flag = false;
if(!isset($_SERVER['HTTP_CF_RAY'])) $flag = false;
if(!isset($_SERVER['HTTP_CF_VISITOR'])) $flag = false;
return $flag;
}
function isCloudflare() {
$ipCheck = _cloudflare_CheckIP($_SERVER['REMOTE_ADDR']);
$requestCheck = _cloudflare_Requests_Check();
return ($ipCheck && $requestCheck);
}
// Use when handling ip's
function getRequestIP() {
$check = isCloudflare();
if($check) {
return $_SERVER['HTTP_CF_CONNECTING_IP'];
} else {
return $_SERVER['REMOTE_ADDR'];
}
}
To use the script it's quite simple:
$ip = getRequestIP();
$cf = isCloudflare();
if($cf) echo "Connection is through cloudflare: <br>";
else echo "Connection is not through cloudflare: <br>";
echo "Your actual ip address is: ". $ip;
echo "The server remote address header is: ". $_SERVER['REMOTE_ADDR'];
This script will show you the real ip address and if the request is CF or not!

Cloudflare sends some additional request headers to your server including CF-Connecting-IP which we can store into $user_ip, if defined, using this simple one-liner:
$user_ip = $_SERVER["HTTP_CF_CONNECTING_IP"] ?? $_SERVER['REMOTE_ADDR'];

Since this question was asked and answered, CloudFlare has released mod_cloudflare for Apache, which logs & displays the actual visitor IP address rather than the CloudFlare address:
https://www.cloudflare.com/resources-downloads#mod_cloudflare

It would be hard to convert HTTP_CF_CONNECTING_IP to REMOTE_ADDR. So you can use apache (.htaccess) auto prepending to do that. So that you do not need to think about whether the $_SERVER['REMOTE_ADDR'] has the correct value in all the PHP scripts.
.htaccess code
php_value auto_prepend_file "/path/to/file.php"
php code (file.php)
<?php
define('CLIENT_IP', isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : $_SERVER['REMOTE_ADDR']);
Learn More here

HTTP_CF_CONNECTING_IP is only working if you are using cloudflare maybe you transfer your site or remove cloudflare you will forget the value so use this code .
$ip=$_SERVER["HTTP_CF_CONNECTING_IP"];
if (!isset($ip)) {
$ip = $_SERVER['REMOTE_ADDR'];
}

When you are using CloudFlare all your requests between your server and users are routed through CloudFlare servers.
In this case there are two methods to get User's Real IP Address:
Through Extra Server Headers added by CloudFlare Servers
Adding a CloudFlare Apache/NGINX Module on your server.
Method 1: Get IP though extra Server Headers
You can use the following code to get user's IP Address:
$user_ip = (isset($_SERVER["HTTP_CF_CONNECTING_IP"]) $_SERVER["HTTP_CF_CONNECTING_IP"]:$_SERVER['REMOTE_ADDR']);
How it is working?
CloudFlare adds some extra server variables in the request as follows:
$_SERVER["HTTP_CF_CONNECTING_IP"] - Real IP Address of user
$_SERVER["HTTP_CF_IPCOUNTRY"] - ISO2 Country of the User
$_SERVER["HTTP_CF_RAY"] A Special string for loggin purpose
In the above code, we are checking if $_SERVER["HTTP_CF_CONNECTING_IP"] is set or not. If it is there we will consider that as user's IP Address else we will use the default code as $_SERVER['REMOTE_ADDR']
Method 2: Installing Cloudflare Module on your server
Installing CloudFlare Module on Apache Server
Installing CloudFlare Module on NGINX Server
Installing CloudFlare Module on EasyApache+CPanel

In Laravel add the following line to AppServiceProvider:
...
use Symfony\Component\HttpFoundation\Request;
...
public function boot()
{
Request::setTrustedProxies(['REMOTE_ADDR'], Request::HEADER_X_FORWARDED_FOR);
}
Now you can get real client IP using request()->ip().
Read more here.

Cloudflare has an option to use a "Pseudo IPv4" address in the headers on the Network Management page for the domain. You have the option of adding or overwriting the headers that are sent to your server.
From the documentation:
What is Pseudo IPv4?
As a stopgap to accelerate the adoption of IPv6, Cloudflare offers Pseudo IPv4 which supports IPv6 addresses in legacy applications expecting IPv4 addresses. The goal is to provide a nearly unique IPv4 address for each IPv6 address, using Class E IPv4 address space, which is designated as experimental and would not normally see traffic. To learn more see here.
Options
Add header: Add additional Cf-Pseudo-IPv4 header only
Overwrite headers: Overwrite the existing Cf-Connecting-IP and X-Forwarded-For headers with a pseudo IPv4 address.
Note: We recommend leaving this set to “Off” unless you have a specific need.
You can learn more about this feature from this article from Cloudflare, where it goes into a little more detail about how they try to accommodate the 128-bit address space of IPv6 in the 32-bit space found in IPv4.
In the event that you would like to know the IPv6 address along with the pseudo IPv4, Cloudflare adds a Cf-Connecting-IPv6 header when Pseudo IPv4 is enabled. This can be used to measure how much of your traffic is originating from devices that are on IPv6 networks, which can be useful if you need a solid number to show management before investments are made in updating systems that are still bound to the IPv4 limitations.

It's better to check cloudflare ip ranges online (because it may change anytime) then check it's from cloudflare or not.
Cloudflare IP txt
If the source is Cloudflare you can use $_SERVER['HTTP_CF_CONNECTING_IP'] to get your client request ip-address but it's not safe to use it for all requests because it can send by any user in request header to trick you.
You can use following code to get real ip-address of your client request:
function _getUserRealIP() {
$ipaddress = '';
if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else 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_X_CLUSTER_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
function _readCloudflareIps()
{
$file = file("https://www.cloudflare.com/ips-v4",FILE_IGNORE_NEW_LINES);
return $file;
}
function _checkIpInRange($ip, $range) {
if (strpos($range, '/') == false)
$range .= '/32';
// $range is in IP/CIDR format eg 127.0.0.1/24
list($range, $netmask) = explode('/', $range, 2);
$range_decimal = ip2long($range);
$ip_decimal = ip2long($ip);
$wildcard_decimal = pow(2, (32 - $netmask)) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return (($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal));
}
function _checkIsCloudflare($ip) {
$cf_ips = _readCloudflareIps();
$is_cf_ip = false;
foreach ($cf_ips as $cf_ip) {
if (_checkIpInRange($ip, $cf_ip)) {
$is_cf_ip = true;
break;
}
}
return $is_cf_ip;
}
function getRealIp()
{
$httpIp = _getUserRealIP();
$check = _checkIsCloudflare($httpIp);
if ($check) {
return $_SERVER['HTTP_CF_CONNECTING_IP'];
}else{
return $httpIp;
}
}
After importing this functions to your code you just need to call getRealIp() function like:
$userIp = getRealIp();
echo $userIp();

For magento 1.x users (I haven't try magento 2.0 yet), check https://tall-paul.co.uk/2012/03/13/magento-show-remote-ip-in-cloudflare-the-right-way/ which needs to change app/etc/local.xml and add:
HTTP_CF_CONNECTING_IP

another way to get it in Laravel is simply by reading HTTP_CF_CONNECTING_IP header
$request->server('HTTP_CF_CONNECTING_IP')
you can read more about it here:
How to get real client IP behind Cloudflare in Laravel / PHP

Related

What if the $_SERVER does not contain the IPv4 ip?

I am trying to code a PHP script for getting the client's IP address using this function:
public function getIpAddress() {
$ipAddress = '';
if (! empty($_SERVER['HTTP_CLIENT_IP']) && $this->isValidIpAddress($_SERVER['HTTP_CLIENT_IP'])) {
// check for shared ISP IP
$ipAddress = $_SERVER['HTTP_CLIENT_IP'];
} else if (! empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $this->isValidIpAddress($_SERVER['HTTP_CLIENT_IP'])) {
// check for IPs passing through proxy servers
// check if multiple IP addresses are set and take the first one
$ipAddressList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($ipAddressList as $ip) {
if ($this->isValidIpAddress($ip)) {
$ipAddress = $ip;
break;
}
}
} else if (! empty($_SERVER['HTTP_X_FORWARDED']) && $this->isValidIpAddress($_SERVER['HTTP_X_FORWARDED'])) {
$ipAddress = $_SERVER['HTTP_X_FORWARDED'];
} else if (! empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->isValidIpAddress($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) {
$ipAddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
} else if (! empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->isValidIpAddress($_SERVER['HTTP_FORWARDED_FOR'])) {
$ipAddress = $_SERVER['HTTP_FORWARDED_FOR'];
} else if (! empty($_SERVER['HTTP_FORWARDED']) && $this->isValidIpAddress($_SERVER['HTTP_FORWARDED'])) {
$ipAddress = $_SERVER['HTTP_FORWARDED'];
} else if (! empty($_SERVER['REMOTE_ADDR']) && $this->isValidIpAddress($_SERVER['REMOTE_ADDR'])) {
$ipAddress = $_SERVER['REMOTE_ADDR'];
}else{
$ipAddress = 'error';
}
return $ipAddress;
}
I tried it many times and it's working. But I tried to connect to a VPN and it retrieved IPv6 instead of IPv4!
This could be a normal situation but I need to get the IPv4 of the visitor of that PHP script.
I googled a lot about converting IPv6 to IPv4 and I know that it cannot be converted.
But I notices some IP geolocation services are retrieving IPv4 for the same VPN (on the same device)! For example: canyouseeme.org and api.ipify.org.
That's mean that even if the IPv6 cannot be converted into IPv4, there's a method can be implemented to get IPv4 even if the visitor is using IPv6!
My questions:
If the conversion is not possible between these two versions, how did these IP geolocation services retrieved the IPv4 of the visitor?
If they are not converting the IPv6 into IPv4. So, they are retrieving the IPv4 directly without touching the IPv6. But, how did they do that if the $_SERVER does not contain an IPv4?
In additional to that, I noticed that when I visited whatismyipaddress.com, they retrieved the IPv6 first then it start loading beside the IPv4 field then they retrieved it!
Note: All these sites has retrieved the same IPv4.
Thanks.
Just drop the AAAA record from your DNS name (or disable ipv6 in your webservrr - this might introduce delays as browsers are supposed to prefer ipv6), then, however, people w/o ipv4 cannot access your service any more. As #MagnusEriksson said: "Instead of fighting the future, wouldn't it be better to fix your application so it works with IPv6 as well?"
Also, please be aware, if the ip address is so important for you, that http headers can be easily spoofed by clients (i.e., don't trust user provided data) or proxy servers might provide private ips as defined in RFC1918. You should only consider/use the headers you know a trusted proxy infront of your server uses - in all other cases you cannot trust the user provided headers.
if you are using apache, you may want to check if there are any IPv6 Bindings or VirtualHosts. there will be similar settings for other web servers
if you don't have access to the web server config, you can see if there's an option to disable IPv6 in your webhost panel
also, this could be client-controlled, i.e. when you connect using a VPN then IPv6 is enabled for that network interface (or tunnel). in which case you cannot force the visitor to disable IPv6 on their device / router, but you could try to disable it on your end. unlike HTTPS Everywhere which only accepts port 443 or nothing, I don't think IP addresses are at the stage where it is only possible to accept IPv6 with no fallback to IPv4, so this recommendation should be safe

Change IP address (proxy) with test

I want to browse some sites using a proxy, so I want to change the IP address of my client to the specified IP.
I am also testing it on localhost, so my goal is to visit my localhost site with PHP script (also localhost). The problem is how to test this (maybe some simple test by writing out changed IP to file).
I'm not entirely sure what exactly you mean, but you can check your clients IP address with this:
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
echo $ip;
Ofcourse this will not change your clients IP address. You need an actual proxy server for that.

Get real ip address using CloudFlare [duplicate]

I'm trying to track and log users/visitors that are accessing my website using PHP's $_SERVER['REMOTE_ADDR'] to do so. A typical method for IP address tracking in PHP.
However, I am using CloudFlare for caching and such and receiving their IP addresses as CloudFlare's:
108.162.212.* - 108.162.239.*
What would be a correct method of retrieving the actual users/visitors IP address while still using CloudFlare?
Extra server variables that are available to cloud flare are:
$_SERVER["HTTP_CF_CONNECTING_IP"] real visitor ip address, this is what you want
$_SERVER["HTTP_CF_IPCOUNTRY"] country of visitor
$_SERVER["HTTP_CF_RAY"]
$_SERVER["HTTP_CF_VISITOR"] this can help you know if its http or https
you can use it like this:
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
If you do this, and the validity of the visiting IP address is important, you might need to verify that the $_SERVER["REMOTE_ADDR"] contains an actual valid cloudflare IP address, because anyone can fake the header if he was able to connect directly to the server IP.
Update: CloudFlare has released a module mod_cloudflare for apache, the module will log and display the actual visitor IP Addresses rather than those accessed by cloudflare! https://www.cloudflare.com/resources-downloads#mod_cloudflare (Answer by: olimortimer)
If you dont have access to the apache runtime you can use the script below, this will allow you to check if the connection was through cloudflare and get the users ip.
I am rewriting my answer i used for another question "CloudFlare DNS / direct IP identifier"
Cloudflare's ips are stored in public so you can go view them here then check if the ip is from cloudflare (this will allow us to get the real ip from the http header HTTP_CF_CONNECTING_IP).
If you are using this to disable all non cf connections or vice versa, i recommend you to have a single php script file that gets called before every other script such as a common.php or pagestart.php etc.
function ip_in_range($ip, $range) {
if (strpos($range, '/') == false)
$range .= '/32';
// $range is in IP/CIDR format eg 127.0.0.1/24
list($range, $netmask) = explode('/', $range, 2);
$range_decimal = ip2long($range);
$ip_decimal = ip2long($ip);
$wildcard_decimal = pow(2, (32 - $netmask)) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return (($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal));
}
function _cloudflare_CheckIP($ip) {
$cf_ips = array(
'199.27.128.0/21',
'173.245.48.0/20',
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'141.101.64.0/18',
'108.162.192.0/18',
'190.93.240.0/20',
'188.114.96.0/20',
'197.234.240.0/22',
'198.41.128.0/17',
'162.158.0.0/15',
'104.16.0.0/12',
);
$is_cf_ip = false;
foreach ($cf_ips as $cf_ip) {
if (ip_in_range($ip, $cf_ip)) {
$is_cf_ip = true;
break;
}
} return $is_cf_ip;
}
function _cloudflare_Requests_Check() {
$flag = true;
if(!isset($_SERVER['HTTP_CF_CONNECTING_IP'])) $flag = false;
if(!isset($_SERVER['HTTP_CF_IPCOUNTRY'])) $flag = false;
if(!isset($_SERVER['HTTP_CF_RAY'])) $flag = false;
if(!isset($_SERVER['HTTP_CF_VISITOR'])) $flag = false;
return $flag;
}
function isCloudflare() {
$ipCheck = _cloudflare_CheckIP($_SERVER['REMOTE_ADDR']);
$requestCheck = _cloudflare_Requests_Check();
return ($ipCheck && $requestCheck);
}
// Use when handling ip's
function getRequestIP() {
$check = isCloudflare();
if($check) {
return $_SERVER['HTTP_CF_CONNECTING_IP'];
} else {
return $_SERVER['REMOTE_ADDR'];
}
}
To use the script it's quite simple:
$ip = getRequestIP();
$cf = isCloudflare();
if($cf) echo "Connection is through cloudflare: <br>";
else echo "Connection is not through cloudflare: <br>";
echo "Your actual ip address is: ". $ip;
echo "The server remote address header is: ". $_SERVER['REMOTE_ADDR'];
This script will show you the real ip address and if the request is CF or not!
Cloudflare sends some additional request headers to your server including CF-Connecting-IP which we can store into $user_ip, if defined, using this simple one-liner:
$user_ip = $_SERVER["HTTP_CF_CONNECTING_IP"] ?? $_SERVER['REMOTE_ADDR'];
Since this question was asked and answered, CloudFlare has released mod_cloudflare for Apache, which logs & displays the actual visitor IP address rather than the CloudFlare address:
https://www.cloudflare.com/resources-downloads#mod_cloudflare
It would be hard to convert HTTP_CF_CONNECTING_IP to REMOTE_ADDR. So you can use apache (.htaccess) auto prepending to do that. So that you do not need to think about whether the $_SERVER['REMOTE_ADDR'] has the correct value in all the PHP scripts.
.htaccess code
php_value auto_prepend_file "/path/to/file.php"
php code (file.php)
<?php
define('CLIENT_IP', isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : $_SERVER['REMOTE_ADDR']);
Learn More here
HTTP_CF_CONNECTING_IP is only working if you are using cloudflare maybe you transfer your site or remove cloudflare you will forget the value so use this code .
$ip=$_SERVER["HTTP_CF_CONNECTING_IP"];
if (!isset($ip)) {
$ip = $_SERVER['REMOTE_ADDR'];
}
When you are using CloudFlare all your requests between your server and users are routed through CloudFlare servers.
In this case there are two methods to get User's Real IP Address:
Through Extra Server Headers added by CloudFlare Servers
Adding a CloudFlare Apache/NGINX Module on your server.
Method 1: Get IP though extra Server Headers
You can use the following code to get user's IP Address:
$user_ip = (isset($_SERVER["HTTP_CF_CONNECTING_IP"]) $_SERVER["HTTP_CF_CONNECTING_IP"]:$_SERVER['REMOTE_ADDR']);
How it is working?
CloudFlare adds some extra server variables in the request as follows:
$_SERVER["HTTP_CF_CONNECTING_IP"] - Real IP Address of user
$_SERVER["HTTP_CF_IPCOUNTRY"] - ISO2 Country of the User
$_SERVER["HTTP_CF_RAY"] A Special string for loggin purpose
In the above code, we are checking if $_SERVER["HTTP_CF_CONNECTING_IP"] is set or not. If it is there we will consider that as user's IP Address else we will use the default code as $_SERVER['REMOTE_ADDR']
Method 2: Installing Cloudflare Module on your server
Installing CloudFlare Module on Apache Server
Installing CloudFlare Module on NGINX Server
Installing CloudFlare Module on EasyApache+CPanel
In Laravel add the following line to AppServiceProvider:
...
use Symfony\Component\HttpFoundation\Request;
...
public function boot()
{
Request::setTrustedProxies(['REMOTE_ADDR'], Request::HEADER_X_FORWARDED_FOR);
}
Now you can get real client IP using request()->ip().
Read more here.
Cloudflare has an option to use a "Pseudo IPv4" address in the headers on the Network Management page for the domain. You have the option of adding or overwriting the headers that are sent to your server.
From the documentation:
What is Pseudo IPv4?
As a stopgap to accelerate the adoption of IPv6, Cloudflare offers Pseudo IPv4 which supports IPv6 addresses in legacy applications expecting IPv4 addresses. The goal is to provide a nearly unique IPv4 address for each IPv6 address, using Class E IPv4 address space, which is designated as experimental and would not normally see traffic. To learn more see here.
Options
Add header: Add additional Cf-Pseudo-IPv4 header only
Overwrite headers: Overwrite the existing Cf-Connecting-IP and X-Forwarded-For headers with a pseudo IPv4 address.
Note: We recommend leaving this set to “Off” unless you have a specific need.
You can learn more about this feature from this article from Cloudflare, where it goes into a little more detail about how they try to accommodate the 128-bit address space of IPv6 in the 32-bit space found in IPv4.
In the event that you would like to know the IPv6 address along with the pseudo IPv4, Cloudflare adds a Cf-Connecting-IPv6 header when Pseudo IPv4 is enabled. This can be used to measure how much of your traffic is originating from devices that are on IPv6 networks, which can be useful if you need a solid number to show management before investments are made in updating systems that are still bound to the IPv4 limitations.
It's better to check cloudflare ip ranges online (because it may change anytime) then check it's from cloudflare or not.
Cloudflare IP txt
If the source is Cloudflare you can use $_SERVER['HTTP_CF_CONNECTING_IP'] to get your client request ip-address but it's not safe to use it for all requests because it can send by any user in request header to trick you.
You can use following code to get real ip-address of your client request:
function _getUserRealIP() {
$ipaddress = '';
if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else 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_X_CLUSTER_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
function _readCloudflareIps()
{
$file = file("https://www.cloudflare.com/ips-v4",FILE_IGNORE_NEW_LINES);
return $file;
}
function _checkIpInRange($ip, $range) {
if (strpos($range, '/') == false)
$range .= '/32';
// $range is in IP/CIDR format eg 127.0.0.1/24
list($range, $netmask) = explode('/', $range, 2);
$range_decimal = ip2long($range);
$ip_decimal = ip2long($ip);
$wildcard_decimal = pow(2, (32 - $netmask)) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return (($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal));
}
function _checkIsCloudflare($ip) {
$cf_ips = _readCloudflareIps();
$is_cf_ip = false;
foreach ($cf_ips as $cf_ip) {
if (_checkIpInRange($ip, $cf_ip)) {
$is_cf_ip = true;
break;
}
}
return $is_cf_ip;
}
function getRealIp()
{
$httpIp = _getUserRealIP();
$check = _checkIsCloudflare($httpIp);
if ($check) {
return $_SERVER['HTTP_CF_CONNECTING_IP'];
}else{
return $httpIp;
}
}
After importing this functions to your code you just need to call getRealIp() function like:
$userIp = getRealIp();
echo $userIp();
For magento 1.x users (I haven't try magento 2.0 yet), check https://tall-paul.co.uk/2012/03/13/magento-show-remote-ip-in-cloudflare-the-right-way/ which needs to change app/etc/local.xml and add:
HTTP_CF_CONNECTING_IP
another way to get it in Laravel is simply by reading HTTP_CF_CONNECTING_IP header
$request->server('HTTP_CF_CONNECTING_IP')
you can read more about it here:
How to get real client IP behind Cloudflare in Laravel / PHP

PHP code used in website returns network IP of user and not public IP

I have PHP code that is supposed to detect a user's IP address. The code below returns an IP address, but the IP address is sometimes a local network IP (e.g. 10.0.0.1) and not a public IP. How can I ensure that I always get the public IP? Thanks. BTW, this code is from another StackOverflow post. Also, this code is used in a website that is being accessed over the internet from a completely separate network than that of my Apache web server.
if (isset($_SERVER["HTTP_CLIENT_IP"])){
$ip = $_SERVER["HTTP_CLIENT_IP"];
} elseif (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} elseif (isset($_SERVER["HTTP_X_FORWARDED"])){
$ip = $_SERVER["HTTP_X_FORWARDED"];
} elseif (isset($_SERVER["HTTP_FORWARDED_FOR"])){
$ip = $_SERVER["HTTP_FORWARDED_FOR"];
} elseif (isset($_SERVER["HTTP_FORWARDED"])){
$ip = $_SERVER["HTTP_FORWARDED"];
} else {
$ip = $_SERVER["REMOTE_ADDR"];
}
Eliminate all the if(){} else{} code, and just request the REMOTE_ADDR:
$ip = $_SERVER["REMOTE_ADDR"];
It's the only reliable source of a user's remote IP address as all the other _SERVER keys can be masked by the client.
If the IP address is still local (and youre SURE that you're dealing with clients not in the networks or on a local VPN) the you may be dealing with either a server caching system (Squid Proxy eg). Have a look at http://www.nineteenlabs.com/2007/08/24/high-anonymous-proxy-squid-25/

Getting IP address in php

I am this code to get the IP address on my locolhost and I get
::1
result
code is:
function ip()
{
if (!empty($_SERVER['HTTP_CLIENT_IP']))
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
echo ip();
where is error?
Actually, I want to get country & city name after I get IP... Any other solution?
Thanks
::1 is shorthand for localhost, using IPv6 terminology, so it is working. Try connecting using your hostname, and you should see the address change to be more obviously an address...
As #Roland writes it is an IPv6 address. If you don't intend on using IPv6 in your application then you should tell your web server to stop listening on IPv6 ports. When you send a request the client will try IPv6 first if it doesn't work then it will fall back to IPv4 and you should get the much more familiar looking 127.0.0.1.
You could use the following:
$server_address = $_SERVER['SERVER_ADDR'];
$port_used = $_SERVER['SERVER_PORT'];
$ip_address = $_SERVER['REMOTE_ADDR'];
// on my test machine this gives the following results:
$server_address = 127.0.0.1
$port_used = 80
$ip_address = 127.0.0.1
Edited: to include the geo-location aspect of the question, that I hadn't noticed 'til after I submitted the original answer.
Rather than repeat answers found elsewhere, I'll first link to this (well-answered) SO question:
google-geolocation-api-library, and then to the Google results page for the search terms geolocation php site:stackoverflow.com, which links to many other -probably relevant- answers that might better address your questions than I'm able.
If you print_r($_SERVER) you will see what information is available, what it looks like, and what fields might be empty.

Categories