Context:
I want to detect the two letter continent code of my user(s) to allow me to conditionally display an American or more general phone number.
E.g. If continent code is North America or South America, display North American phone number. Else, display general international phone number.
What I've tried:
A similar question on Stack Overflow was resolved using a light-weight function however in my case, the function did not output anything (i.e. blank).
The PHP manual lists the geoip_continent_code_by_name function of GEOIP extension however installation of this extension seems overkill and besides, I'm in no way familiar with command line installs for WHM/cPanel.
My question:
Is there an easier and lighter-weight method of detecting the two-letter continent code by IP?
You can use official API by MaxMind
https://maxmind.github.io/GeoIP2-php/
example of code
<?php
require_once 'vendor/autoload.php';
use GeoIp2\Database\Reader;
// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader('GeoLite2-Country.mmdb');
// Replace "city" with the appropriate method for your database, e.g.,
// "country".
$record = $reader->country('128.101.101.101');
echo ($record->continent->code);
You can use this function:
function get_continent_by_ip($ip = false) {
$code = false;
if (!$ip) {
$client = #$_SERVER['HTTP_CLIENT_IP'];
$forward = #$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = #$_SERVER['REMOTE_ADDR'];
if (filter_var($client, FILTER_VALIDATE_IP)) {
$ip = $client;
} elseif (filter_var($forward, FILTER_VALIDATE_IP)) {
$ip = $forward;
} else {
$ip = $remote;
}
}
$response = #json_decode(file_get_contents("http://www.geoplugin.net/json.gp?ip={$ip}"));
if ($response && isset($response->geoplugin_continentCode)) {
$code = $response->geoplugin_continentCode;
}
return $code;
}
It detects IP of user and returns code of continent
Related
I have a small website (using HTML, PHP and MySQL), and would like to display a specific banner image according to the country of the visitor. Each country has a different banner image.
I have searched Google for solutions and found quite some API's (such as HostIP) that allow to return the country based upon the IP address. That's nice, but I could not find how to implement it for my purpose to make the image switch according to the country...
I have no developer knowledge. Can anyone help me out?
Get Geo-IP Information
Requests a geo-IP-server (netip.de) to check, returns where an IP is located (host, state, country, town).
<?php
$ip='94.219.40.96';
print_r(geoCheckIP($ip));
//Array ( [domain] => dslb-094-219-040-096.pools.arcor-ip.net [country] => DE - Germany [state] => Hessen [town] => Erzhausen )
//Get an array with geoip-infodata
function geoCheckIP($ip)
{
//check, if the provided ip is valid
if(!filter_var($ip, FILTER_VALIDATE_IP))
{
throw new InvalidArgumentException("IP is not valid");
}
//contact ip-server
$response=#file_get_contents('http://www.netip.de/search?query='.$ip);
if (empty($response))
{
throw new InvalidArgumentException("Error contacting Geo-IP-Server");
}
//Array containing all regex-patterns necessary to extract ip-geoinfo from page
$patterns=array();
$patterns["domain"] = '#Domain: (.*?) #i';
$patterns["country"] = '#Country: (.*?) #i';
$patterns["state"] = '#State/Region: (.*?)<br#i';
$patterns["town"] = '#City: (.*?)<br#i';
//Array where results will be stored
$ipInfo=array();
//check response from ipserver for above patterns
foreach ($patterns as $key => $pattern)
{
//store the result in array
$ipInfo[$key] = preg_match($pattern,$response,$value) && !empty($value[1]) ? $value[1] : 'not found';
}
return $ipInfo;
}
?>
to complete the anwer of Avinash, is this the right solution to switch image based upon country?
function switchImage($var) {
switch ($var)
{
case "United states":
$source = '/images/US.png';
$class = 'myClass';
$alt = 'myAlt';
break;
case "United Kingdom":
$source = '/images/UK.png';
$class = 'myClass';
$alt = 'myAlt';
break;
.
.
.
default:
return "Default"; //default case
}
}
This question already has answers here:
What's the simplest way to get a user's latitude and longitude from an ip address [closed]
(3 answers)
Closed 8 years ago.
i use this function to get client IP it work
function get_client_ip() {
$ipaddress = '';
if ($_SERVER['HTTP_CLIENT_IP'])
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
else if($_SERVER['HTTP_X_FORWARDED_FOR'])
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if($_SERVER['HTTP_X_FORWARDED'])
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
else if($_SERVER['HTTP_FORWARDED_FOR'])
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if($_SERVER['HTTP_FORWARDED'])
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else if($_SERVER['REMOTE_ADDR'])
$ipaddress = $_SERVER['REMOTE_ADDR'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
$ip = get_client_ip();
but how i can get latitude and longitude by sever side and not client side ?
PHP does not have the in-built support for that. You could make use of third party libraries like ip2location to grab the longitude and latitude from the ip address.
Sidenote : Determining the latitude - longitude through an IP Address may not fetch you accurate information.
Uses geoplugin.net. See if this suits you.
<?php
$new_arr[]= unserialize(file_get_contents('http://www.geoplugin.net/php.gp?ip='.$_SERVER['REMOTE_ADDR']));
echo "Latitude:".$new_arr[0]['geoplugin_latitude']." and Longitude:".$new_arr[0]['geoplugin_longitude'];
OUTPUT :
Latitude:180.240601 and Longitude:12.9819
Best option from php.net which is also open source: Geo IP
You can install it using following steps. Which are given on the link I have provided:
Run these commands in terminal.
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
sudo mkdir -v /usr/share/GeoIP
sudo mv -v GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat
sudo apt-get install php5-geoip
Hope it helps!!
You should consider getting the exact location of the user from client side using Javascript API navigator.geolocation. The advantage of using this is, it will be accurate.
The issue with IP to Geo is that, there is no guarantee that the info will be accurate. It depends on how updated the data is.
On the other hand, the javascript API directly takes the geo based on GPS or Network address (whichever is accurate). But the user will have to give permission to access to his GPS.
You can use the Javascript (if user gives permission) or fall back to ip to geo conversion
How to Use
if (navigator.geolocation && navigator.geolocation.getCurrentPosition) {
navigator.geolocation.getCurrentPosition(function(position) {
// save location by sending to server
}, function() { alert("Couldn't get your position!"); });
}
For a quick, copy-and-paste solution, I have written code for accomplishing this task.
I use this function:
function getUserIP()
{
$client = #$_SERVER['HTTP_CLIENT_IP'];
$forward = #$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if(filter_var($client, FILTER_VALIDATE_IP))
{
$ip = $client;
}
elseif(filter_var($forward, FILTER_VALIDATE_IP))
{
$ip = $forward;
}
else
{
$ip = $remote;
}
return $ip;
}
$ipAddr = getUserIP();
$geoIP = json_decode(file_get_contents("http://freegeoip.net/json/$ipAddr"), true);
echo 'lat: ' . $geoIP['latitude'] . '<br />';
echo 'long: ' . $geoIP['longitude'];
Outputs:
34.0731
118.3994
It uses the (free) freegeoip.net API which I have found to be extremely fast with a comprehensive database. Being free, it has a limit of 10000 requests per hour (just under 3 per second), which should suffice for most projects' needs.
I use a javascript API from (http://www.iplocationtools.com) to give me the location data from a visitors IP. For some reason, their API won't give me the actual IP of the visitor, just the other info, which is why I have to use PHP and CodeIgniter to give me the IP instead.
So I use CodeIgniter/PHP to get the IP of a visitor and add it to the database along with location data from above by using PHP's ip2long([the ip code igniter gives me])
I'm confused when my database table looks like this: http://pulse.media.mit.edu/images/1.png
Which is wrong? I'm tempted to believe CodeIgniter is wrong since it gives me the same IP so many times. Age and sex are self reported and I doubt one person is making up all this information.
At the end of the day, all we really need is the users IP and location, preferably from the same source, so we don't compound errors.
Anybody have a better idea on how to do this?
EDIT: Here is the code that I'm using to get the IP address from CodeIgniter
$data['ip_address'] = ip2long($this->input->ip_address());
$this->pulse_model->voter_info($data);
Then the voter_info function just inserts it into the database where it's stored as an INT(11).
And here is the function ip_address:
function ip_address()
{
if ($this->ip_address !== FALSE)
{
return $this->ip_address;
}
if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR'))
{
$proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY);
$proxies = is_array($proxies) ? $proxies : array($proxies);
$this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
}
elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))
{
$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
}
elseif ($this->server('REMOTE_ADDR'))
{
$this->ip_address = $_SERVER['REMOTE_ADDR'];
}
elseif ($this->server('HTTP_CLIENT_IP'))
{
$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
}
elseif ($this->server('HTTP_X_FORWARDED_FOR'))
{
$this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if ($this->ip_address === FALSE)
{
$this->ip_address = '0.0.0.0';
return $this->ip_address;
}
if (strpos($this->ip_address, ',') !== FALSE)
{
$x = explode(',', $this->ip_address);
$this->ip_address = trim(end($x));
}
if ( ! $this->valid_ip($this->ip_address))
{
$this->ip_address = '0.0.0.0';
}
return $this->ip_address;
}
$_SERVER['REMOTE_ADDR'] is the PHP code to return the IP address of the person viewing the page.
Old versions of ip2long() will return -1 if the IPv4 address is invalid. You may want to use inet_pton instead and expand the field used to hold it to 128 bits.
Based on your code, it looks like $this->input->ip_address() has the possibility of returning '0.0.0.0' if the IP is not valid or could not be determined. However, your comments also state that you need to record the ip address even if the above method returns '0.0.0.0'.
First, I'd recommend checking to see if $this->input->ip_address() and $this->valid_ip() are working as expected. Is $this->valid_ip() returning false for IP's that should be considered valid?
Second, I'd update your code to always fall back to $_SERVER['REMOTE_ADDR'] if $this->input->ip_address() returns '0.0.0.0'.
$ip_address = $this->input->ip_address();
if($ip_address == '0.0.0.0') {
$ip_address = $_SERVER['REMOTE_ADDR'];
}
$data['ip_address'] = ip2long($ip_address);
$this->pulse_model->voter_info($data);
Or if you wanted, you could not use $this->input->ip_address() and do as #rockerest suggests and just use $_SERVER['REMOTE_ADDR'] to being with.
$data['ip_address'] = ip2long($_SERVER['REMOTE_ADDR']);
$this->pulse_model->voter_info($data);
I'm going to block all bots except the big search engines. One of my blocking methods will be to check for "language": Accept-Language: If it has no Accept-Language the bot's IP address will be blocked until 2037. Googlebot does not have Accept-Language, I want to verify it with DNS lookup
<?php
gethostbyaddr($_SERVER['REMOTE_ADDR']);
?>
Is it ok to use gethostbyaddr, can someone pass my "gethostbyaddr protection"?
function detectSearchBot($ip, $agent, &$hostname)
{
$hostname = $ip;
// check HTTP_USER_AGENT what not to touch gethostbyaddr in vain
if (preg_match('/(?:google|yandex)bot/iu', $agent)) {
// success - return host, fail - return ip or false
$hostname = gethostbyaddr($ip);
// https://support.google.com/webmasters/answer/80553
if ($hostname !== false && $hostname != $ip) {
// detect google and yandex search bots
if (preg_match('/\.((?:google(?:bot)?|yandex)\.(?:com|ru))$/iu', $hostname)) {
// success - return ip, fail - return hostname
$ip = gethostbyname($hostname);
if ($ip != $hostname) {
return true;
}
}
}
}
return false;
}
In my project, I use this function to identify Google and Yandex search bots.
The result of the detectSearchBot function is caching.
The algorithm is based on Google’s recommendation - https://support.google.com/webmasters/answer/80553
In addition to Cristian's answer:
function is_valid_google_ip($ip) {
$hostname = gethostbyaddr($ip); //"crawl-66-249-66-1.googlebot.com"
return preg_match('/\.googlebot|google\.com$/i', $hostname);
}
function is_valid_google_request($ip=null,$agent=null){
if(is_null($ip)){
$ip=$_SERVER['REMOTE_ADDR'];
}
if(is_null($agent)){
$agent=$_SERVER['HTTP_USER_AGENT'];
}
$is_valid_request=false;
if (strpos($agent, 'Google')!==false && is_valid_google_ip($ip)){
$is_valid_request=true;
}
return $is_valid_request;
}
Note
Sometimes when using $_SERVER['HTTP_X_FORWARDED_FOR'] OR $_SERVER['REMOTE_ADDR'] more than 1 IP address is returned, for example '155.240.132.261, 196.250.25.120'. When this string is passed as an argument for gethostbyaddr() PHP gives the following error:
Warning: Address is not a valid IPv4 or IPv6 address in...
To work around this I use the following code to extract the first IP address from the string and discard the rest. (If you wish to use the other IPs they will be in the other elements of the $ips array).
if (strstr($remoteIP, ', ')) {
$ips = explode(', ', $remoteIP);
$remoteIP = $ips[0];
}
https://www.php.net/manual/en/function.gethostbyaddr.php
The recommended way by Google is to do a reverse dns lookup (gethostbyaddr) in order to get the associated host name AND then resolve that name to an IP (gethostbyname) and compare it to the remote_addr (because reverse lookups can be faked, too).
But beware, end lokups take time and can severely slow down your webpage (maybe check for user agent first).
Google also publishes a machine readable file containing the IP addresses of their crawlers, see the link below.
See:
https://developers.google.com/search/docs/advanced/crawling/verifying-googlebot
https://webmasters.googleblog.com/2006/09/how-to-verify-googlebot.html
//The function
function is_google() {
return strpos($_SERVER['HTTP_USER_AGENT'],"Googlebot");
}
How to verify Googlebot.
If you have a site that has thousands of pages then going for reverse DNS will be costly, So I think the best method is to hard code ips list. (Php code example)
function googleBotIPsList(){
return "ips"; //hard coded IPs here.
}
Also you can make another function which gets the latest ips. Now upto you how frequently you call this function.
function getLatestGoogleBotIPsList(){
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL,"https://developers.google.com/static/search/apis/ipranges/googlebot.json");
$result=curl_exec($ch);
curl_close($ch);
$result = (json_decode($result, true));
$ips='';
for($i=0;$i<count($result['prefixes']);$i++) {
$ips .= ($result['prefixes'][$i]['ipv6Prefix'] ? $result['prefixes'][$i]['ipv6Prefix'] : $result['prefixes'][$i]['ipv4Prefix']).',';
}
return rtrim($ips,',');
}
Then use strpos to check from the hardcoded list
if(strpos(googleBotIPsList(),zen_get_ip_address()) !==false){
// Insert into your table etc.
}
Since IP can be spoofed, how can one build a PHP website that correctly identifies the visitor's country?
That's inherently a problem given the anonymity of the internet, but spoofing IP addresses to obtain content not legally available in your country is technically a crime in most places anyways.
It's up to you to make every reasonable effort to ensure your site follows distribution restrictions on media and information, but there are some things that are just impractical to guard against. The closest you could get is by doing an actual physical address verification such as a billing address on a credit card or physically mailing someone a pin number for registration, but both of those options incur expenses on behalf of either the user or yourself.
Joomla has been using below function to get IP addresses, it is very versatile good function, that can avoid possible cheats, you can use it:
function get_ip()
{
$ip = false;
if (!empty($_SERVER['HTTP_CLIENT_IP']))
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$ips = explode (', ', $_SERVER['HTTP_X_FORWARDED_FOR']);
if ($ip != false)
{
array_unshift($ips,$ip);
$ip = false;
}
$count = count($ips);
# exclude IP addresses reserved for LANs
for ($i = 0; $i < $count; $i++)
{
if (!preg_match("/^(10|172\.16|192\.168)\./i", $ips[$i]))
{
$ip = $ips[$i];
break;
}
}
}
if (false == $ip AND isset($_SERVER['REMOTE_ADDR']))
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}