How get latitude and longitude by client ip? [duplicate] - php

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.

Related

Why am I getting a random string as IP address with PHP's $_SERVER variable?

I am logging my website visitor's IP addresses along with some other information ($content) with php, so that I could count the number of visitors.
I am using the following code:
<?php
public static function logContent(array $content = null){
try {
$myFile = fopen("visitors.txt", "a");
$txt = "IP: ";
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';
$txt .= $ipAddress;
$txt .= " Time: " . date("Y-m-d h:i:s", time());
$txt .= "\n";
if (!empty($content) && is_array($content)) {
foreach ($content as $k => $v) {
$txt .= "$k : ";
$txt .= $v;
$txt .= "\n";
}
$txt .= "\n";
}
fwrite($myFile, $txt);
fclose($myFile);
} catch (\Exception $e) {
}
}
?>
This code works fine. Normally, I have entries such as below:
IP: 36.80.227.XX Time: 2020-06-19 08:23:52
IP: 191.252.61.XX Time: 2020-06-19 11:25:02
IP: 191.252.61.XX Time: 2020-06-19 11:25:02
But, I recently got the following entry in my log.
IP:
}__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";s:56:"die(md5(DIRECTORY_SEPARATOR));JFactory::getConfig();exit";s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"\0\0\0connection";b:1;}����
Time: 2020-06-19 11:27:37
Is this some kind of malicious injection attack similar to MySQL injection used against Java?
Do I need to look out for anything fishy and patch up my Apache server to improve security?
As far I know, HTTP_X_FORWARDED_FOR headers are sendt by the client/proxy (wiki), you don't make any controls on the content of $_SERVER['HTTP_X_FORWARDED_FOR'].
So yes someone has tried the SQL injection but in this case, it is not sensitive (just output into text file).
You have to check the content of $ipAddress before output into file (with a regular expression for example or with this).
Edit: You can reproduce this behaviour with:
curl -H 'X-Forwarded-For: 1.1.1.1' https://www.example.com/mypage
curl -H 'X-Forwarded-For: <SOME RANDOM INPUT>' https://www.example.com/mypage
Hope this help
This smells like a possible injection attack. You may want to refer to this for some closer look. Although this talks about a joomla setup and pertains to year 2015, the signature is worth talking a look at.
I would possibility recommend going through the logs for any suspicious activity.

Detect two-letter continent code by IP

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

IP Address using PHP not reliable

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);

PHP web site that restricted access to specific country

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;
}

How to get Time Zone through IP Address in PHP [duplicate]

This question already has answers here:
How to find timezone ID from IP address/country name in PHP?
(4 answers)
Closed 5 years ago.
I want to get time zone through an IP Address in PHP. Actually, I have an application which will run at the client machine. I have the IP address of the client machine. But I am not able to get the time zone for each client machine.
$ip = "189.240.194.147"; //$_SERVER['REMOTE_ADDR']
$ipInfo = file_get_contents('http://ip-api.com/json/' . $ip);
$ipInfo = json_decode($ipInfo);
$timezone = $ipInfo->timezone;
date_default_timezone_set($timezone);
echo date_default_timezone_get();
echo date('Y/m/d H:i:s');
Sometime it won't work on local server so try on server.
Edit: This data is coming from ip-api.com, they're free to use as long as you don't exceed 45 requests per minute and not using commercially. See their TOS, not a long a page.
IP address can't even be relied upon to map to a country; you're treading on thin ice if you also want to get timezone. You're better off to have the client send you the time zone, perhaps in a header.
See Tor: anonymity online for yet another reason to stop using IP addresses for things they were not designed for.
If you're running it on the local machine, you can check the configured timezone.
http://www.php.net/manual/en/function.date-default-timezone-get.php
There are a lot better and more reliable methods then trying to guess timezone using GeoIP. If you're feeling lucky, try: http://www.php.net/manual/en/book.geoip.php
$region = geoip_region_by_name('www.example.com');
$tz = geoip_time_zone_by_country_and_region($region['country_code'],
$region['region']);
There's no absolutely certain way to get the client's timezone, but if you have the client submit the date and time from their machine, you can compute it based on what the time it is relative to GMT. So, if it's 7:00pm on their machine and it's 12:00am GMT, then you can determine they are -5 from GMT or (EST/DST)
It is not a good idea for searching the timezone of a user through his or her ip address as he can access his or her account from different places at different times. So it is impossible to locate his timezone through ip address. But I have tried to find a solution and i am giving my code here. Any criticism about the coding technique will be highly appreciated.
<?php
$time_zone = getTimeZoneFromIpAddress();
echo 'Your Time Zone is '.$time_zone;
function getTimeZoneFromIpAddress(){
$clientsIpAddress = get_client_ip();
$clientInformation = unserialize(file_get_contents('http://www.geoplugin.net/php.gp?ip='.$clientsIpAddress));
$clientsLatitude = $clientInformation['geoplugin_latitude'];
$clientsLongitude = $clientInformation['geoplugin_longitude'];
$clientsCountryCode = $clientInformation['geoplugin_countryCode'];
$timeZone = get_nearest_timezone($clientsLatitude, $clientsLongitude, $clientsCountryCode) ;
return $timeZone;
}
function get_client_ip() {
$ipaddress = '';
if (getenv('HTTP_CLIENT_IP'))
$ipaddress = getenv('HTTP_CLIENT_IP');
else if(getenv('HTTP_X_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_X_FORWARDED_FOR');
else if(getenv('HTTP_X_FORWARDED'))
$ipaddress = getenv('HTTP_X_FORWARDED');
else if(getenv('HTTP_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_FORWARDED_FOR');
else if(getenv('HTTP_FORWARDED'))
$ipaddress = getenv('HTTP_FORWARDED');
else if(getenv('REMOTE_ADDR'))
$ipaddress = getenv('REMOTE_ADDR');
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
function get_nearest_timezone($cur_lat, $cur_long, $country_code = '') {
$timezone_ids = ($country_code) ? DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $country_code)
: DateTimeZone::listIdentifiers();
if($timezone_ids && is_array($timezone_ids) && isset($timezone_ids[0])) {
$time_zone = '';
$tz_distance = 0;
//only one identifier?
if (count($timezone_ids) == 1) {
$time_zone = $timezone_ids[0];
} else {
foreach($timezone_ids as $timezone_id) {
$timezone = new DateTimeZone($timezone_id);
$location = $timezone->getLocation();
$tz_lat = $location['latitude'];
$tz_long = $location['longitude'];
$theta = $cur_long - $tz_long;
$distance = (sin(deg2rad($cur_lat)) * sin(deg2rad($tz_lat)))
+ (cos(deg2rad($cur_lat)) * cos(deg2rad($tz_lat)) * cos(deg2rad($theta)));
$distance = acos($distance);
$distance = abs(rad2deg($distance));
// echo '<br />'.$timezone_id.' '.$distance;
if (!$time_zone || $tz_distance > $distance) {
$time_zone = $timezone_id;
$tz_distance = $distance;
}
}
}
return $time_zone;
}
return 'unknown';
}
It's not straight forward but I get the time including daylight saving offset from 2 api calls using jquery and php. All of it could be done in PHP quite easily with a bit of adaptation.
I'm sure this could be laid out differently too but I just grabbed it from existing code which suited my needs at the time.
Jquery/php:
function get_user_time(){
var server_time = <? echo time(); ?>; //accuracy is not important it's just to let google know the time of year for daylight savings time
$.ajax({
url: "locate.php",
dataType: "json",
success: function(user_location) {
if(user_location.statusCode=="OK"){
$.ajax({
url: "https://maps.googleapis.com/maps/api/timezone/json?location="+user_location.latitude+","+user_location.longitude+"&timestamp="+server_time+"&sensor=false",
dataType: "json",
success: function(user_time) {
if(user_time.statusCode=="error"){
//handle error
}else{
user_time.rawOffset /= 3600;
user_time.dstOffset /= 3600;
user_real_offset = user_time.rawOffset+user_time.dstOffset+user_time.utc;
//do something with user_real_offset
}
}
});
}
}
});
}
locate.php
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;
}
$location = file_get_contents('http://api.ipinfodb.com/v3/ip-city/?key=xxxxxxxxx&ip='.get_client_ip().'&format=json');
$location = json_decode($location,true);
if(is_array($location)){
date_default_timezone_set('UTC');
$location['utc'] = time();
echo json_encode($location);
}else{
echo '{"statusCode":"error"}';
}
Register for a free key here: http://ipinfodb.com/register.php (no limits but queued if more than 1 request per second)
If what you need to know is the timezone of users browsing your webpage, then you can use some service like IP2LOCATION to guess the timezone. Keep in mind though, as altCognito said, this is not a 100% accurate way of telling client's timezone. There are some accuracy problems with this approach.
Check out the Maxmind GeoLite2 database. It contains details about the continent/country/city and lat/lon for most IP addresses including the time_zone as you can see below.
I describe how to compile the PHP extension, and how to use the mmdb databases in PHP here:
Intro to Maxmind GeoLite2 with Kohana PHP
Here's an example using a location API that maps IP address to timezone, e.g. send a request to https://ipapi.co/<IP-Address>/timezone/ & get back timezone for that IP address.
PHP Code
file_get_contents('https://ipapi.co/1.2.3.4/timezone/');
Accuracy is not 100% as others have said.

Categories