Определяем локацию пользователя по IP


В функционал многих сайтов закладывают функцию определения города посетителя (клиента). Плюсы этого очевидны, фирмы с филиалами в разных городах могут показывать разные номера телефонов, интернет магазины могут сразу предложить подходящий тариф доставки и многое другое. Для решения данного рода задачи подойдет использование баз GeoIP, но главное помнить что точность данных не будет 100%.

Для определения локации пользователя по его IP-адресу нужно, где то раздобыть базу данных GeoIP или обратится к сервису.

Сервис ipinfo.io есть возможность пользоваться и бесплатно если запросов не много.

Пример как можно получить данные в PHP:

$ip = $_SERVER['REMOTE_ADDR']; //Ip – клиента 
$result = (array)json_decode(file_get_contents("http://ipinfo.io/{$ip}/json")); 
echo "<pre>";
	print_r($result);
echo "</pre>";

В ответ мы получаем данные ( пример):

Array
(
    [ip] => 8.8.8.8
    [hostname] => google-public-dns-a.google.com
    [city] => Mountain View
    [region] => California
    [country] => US
    [loc] => 37.3860,-122.0838
    [org] => AS15169 Google Inc.
    [postal] => 94035
)

ДЕМО

Так же данные можно получить и на стороне клиента с использованием jQuery:

$.get("http://ipinfo.io", function (response) {
    $("#ip").html("IP: " + response.ip);
    $("#address").html("Location: " + response.city + ", " + response.region);
    $("#details").html(JSON.stringify(response, null, 4));
}, "jsonp");

Сервис ipgeobase.ru

Класс на PHP для работы с сервисом:

class Geo
{
        public function __construct($options = null) {
            
            $this->dirname = dirname(__file__);
            
            // ip
            if(!isset($options['ip']) OR !$this->is_valid_ip($options['ip']))
                $this->ip = $this->get_ip(); 
            elseif($this->is_valid_ip($options['ip']))          
                $this->ip = $options['ip'];
            // кодировка
            if(isset($options['charset']) && $options['charset'] && $options['charset']!='windows-1251')
                $this->charset = $options['charset'];
        }
        
        
        /**
         * функция возвращет конкретное значение из полученного массива данных по ip
         * @param string - ключ массива. Если интересует конкретное значение. 
         * Ключ может быть равным 'inetnum', 'country', 'city', 'region', 'district', 'lat', 'lng'
         * @param bolean - устанавливаем хранить данные в куки или нет
         * Если true, то в куки будут записаны данные по ip и повторные запросы на ipgeobase происходить не будут.
         * Если false, то данные постоянно будут запрашиваться с ipgeobase
         * @return array OR string - дополнительно читайте комментарии внутри функции.
         */
        function get_value($key = false, $cookie = true)
        {
            $key_array = array('inetnum', 'country', 'city', 'region', 'district', 'lat', 'lng');
            if(!in_array($key, $key_array))
                $key = false;            
            
            // если используем куки и параметр уже получен, то достаем и возвращаем данные из куки
            if($cookie && isset($_COOKIE['geobase']))
            {
                $data = unserialize($_COOKIE['geobase']);
            } 
            else
            {
                $data = $this->get_geobase_data();
                setcookie('geobase', serialize($data), time()+3600*24*7); //устанавливаем куки на неделю
            }            
            if($key)
                return $data[$key]; // если указан ключ, возвращаем строку с нужными данными
            else
                return $data; // иначе возвращаем массив со всеми данными            
        }
        
        /**
         * функция получает данные по ip.
         * @return array - возвращает массив с данными
         */
        function get_geobase_data()
        {
            // получаем данные по ip
            $link = 'ipgeobase.ru:7020/geo?ip='.$this->ip;
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $link);
            curl_setopt($ch, CURLOPT_HEADER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
            $string = curl_exec($ch);    
            
            // если указана кодировка отличная от windows-1251, изменяем кодировку
            if($this->charset)       
                $string = iconv('windows-1251', $this->charset, $string);
                       
            $data = $this->parse_string($string);
                
            return $data;
        }
        
        /**
         * функция парсит полученные в XML данные в случае, если на сервере не установлено расширение Simplexml
         * @return array - возвращает массив с данными
         */
        
        function parse_string($string)
        {
	      $xml = simplexml_load_string($string);
	      $xml = (array)$xml->ip;
	      return $xml;
        }
        
        /**
         * функция определяет ip адрес по глобальному массиву $_SERVER
         * ip адреса проверяются начиная с приоритетного, для определения возможного использования прокси
         * @return ip-адрес
         */
        function get_ip()
        {
            $ip = false;
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
                $ipa[] = trim(strtok($_SERVER['HTTP_X_FORWARDED_FOR'], ','));
            
            if (isset($_SERVER['HTTP_CLIENT_IP']))
                $ipa[] = $_SERVER['HTTP_CLIENT_IP'];       
            
            if (isset($_SERVER['REMOTE_ADDR']))
                $ipa[] = $_SERVER['REMOTE_ADDR'];
            
            if (isset($_SERVER['HTTP_X_REAL_IP']))
                $ipa[] = $_SERVER['HTTP_X_REAL_IP'];
            
            // проверяем ip-адреса на валидность начиная с приоритетного.
            foreach($ipa as $ips)
            {
                //  если ip валидный обрываем цикл, назначаем ip адрес и возвращаем его
                if($this->is_valid_ip($ips))
                {                    
                    $ip = $ips;
                    break;
                }
            }
            return $ip;
            
        }
        
        /**
         * функция для проверки валидности ip адреса
         * @param ip адрес в формате 1.2.3.4
         * @return bolean : true - если ip валидный, иначе false
         */
        function is_valid_ip($ip=null)
        {
            if(preg_match("#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#", $ip))
                return true; // если ip-адрес попадает под регулярное выражение, возвращаем true
            
            return false; // иначе возвращаем false
        }       
}

Пример использования класса:

$geo = new Geo('utf-8'); // указываем кодировку если надо

$IP = $geo->get_ip(); // IP - Клиента
$result = $geo->get_geobase_data();

echo "<pre>";
	print_r($result);
echo "</pre>";

ДЕМО

#GeoIP #Geolocation

Copyright © 2019