В функционал многих сайтов закладывают функцию определения города посетителя (клиента). Плюсы этого очевидны, фирмы с филиалами в разных городах могут показывать разные номера телефонов, интернет магазины могут сразу предложить подходящий тариф доставки и многое другое. Для решения данного рода задачи подойдет использование баз 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>";