Определение местоположения. Геотаргетинг.
29.05.2015
Представляю php класс для определения города посетителя по ip адресу. Класс использует сервис ipgeobase.ru.
Чтобы минимизировать количество обращений пользователя к сервису, результат запоминается в куках браузера. Кука подписывается, чтобы посетитель не смог ее подменить.
Использовать класс очень просто:
$arRes = TIpGeo::getIpData();
В результате мы получим массив:
Array
(
[inetnum] => 91.201.201.0 - 91.201.201.255
[country] => RU
[city] => Санкт-Петербург
[region] => Санкт-Петербург
[district] => Северо-Западный федеральный округ
[lat] => 59.939037
[lng] => 30.315784
[ipMask] => 91.201
)
Для удобства тестирования функционала геотаргетинга сайта, в функции определения ip адреса есть закомментированный блок кода с указанием ip адресов по различным городам.
Полный код класса:
class TIpGeo {
private $solt = 'Строка подписывающая куки, смените её на секретную последовательность цифр!!!';//СМЕНИТЬ!!!
static public function getIpData() {
try {
$IpGeo = new TIpGeo();
$ip = $IpGeo->getIp();
//пробуем получить данные из куки
$arRes = $IpGeo->getIpDataFromCookie($ip);
if ($arRes) {
return $arRes;
}
$arRes = $IpGeo->getIpDataFromIpgeobase($ip);
$IpGeo->setIpDataToCookie($ip, $arRes); //Установим в куку
return $arRes;
} catch (Exception $exc) {
return false;
}
}
private function __construct() {
}
private function getIp() {
/*
* Блок для тестирования по городам
*
//$ip = '127.0.0.1';//локальный
//$ip = '178.187.126.72';//Барнаул
//$ip = '78.109.16.154';//Москва
//$ip = '91.201.201.0';//Питер
//$ip = '91.199.232.0';//Новосибирск
//$ip = '193.19.110.0';//Киев
if ( $this->isValidIp($ip)){
return $ip;
}
throw new Exception('Ip определить не удалось');
/* */
//Получим ip из заголовков,
//сначала из HTTP_X_FORWARDED_FOR, для определения реального адреса, за прокси и турбо
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arIp = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($arIp as $ip) {
$ip = trim($ip);
if ($this->isValidIp($ip)) {
return $ip;
}
}
}
if (isset($_SERVER['REMOTE_ADDR']) && $this->isValidIp($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
}
throw new Exception('Ip определить не удалось');
}
/*
* Проверка, ip на его корректность и реальность
*/
private function isValidIp($ip) {
if (preg_match("#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#", $ip)) {
//Убъем локальные ip и другие зарезервированные ip
//http://www.rfc-editor.org/rfc/rfc5735.txt
$arIp = explode('.', $ip);
if (in_array($arIp[0], array('0', '10', '127', '169', '172', '192', '198', '203', '224', '240', '255'))) {
return false;
}
return true;
}
return false;
}
private function getIpDataFromCookie($ip) {
if (!isset($_COOKIE['TIpGeo'])) {
return false;
}
$arRes = json_decode($_COOKIE['TIpGeo'], true);
$hash = $arRes['hash'];
unset($arRes['hash']);
if ($hash !== md5(json_encode($arRes) . $this->solt) ) {
return false; //Хеш не равен
}
$ipMask = $this->getIpMaskToCookie($ip);
if ($arRes['ipMask'] !== $ipMask) {
return false; //Сменился ip
}
//Все хорошо, возвращаем ip из куки
return $arRes;
}
private function getIpDataFromIpgeobase($ip) {
$opts = array('http' =>
array(
'method' => 'GET',
'header' => "Content-Type: text/xml\r\n",
'timeout' => 5
)
);
$context = stream_context_create($opts);
$url = 'http://ipgeobase.ru:7020/geo?ip=' . $ip;
if (!$res = file_get_contents($url, false, $context)) {
throw new Exception('Получить данные по ip не получается, сервис ipgeobase');
}
$xml = simplexml_load_string($res);
if (!$xml) {
throw new Exception('ipgeobase вернул не корректный xml');
}
$res = (array) $xml->ip;
unset($res['@attributes']);
if (!isset($res['city'])) {
throw new Exception('city неопределен');
}
return $res;
}
private function setIpDataToCookie($ip, $arRes) {
$ipMask = $this->getIpMaskToCookie($ip);
$arRes['ipMask'] = $ipMask;
$arRes['hash'] = md5(json_encode($arRes) . $this->solt);
setcookie('TIpGeo', json_encode($arRes), time() + 31536000, '/'); // Кука на год
}
private function getIpMaskToCookie($ip) {
$arIp = explode('.', $ip);
$arIp = array_slice($arIp, 0, 2);
return $ipMask = implode('.', $arIp);
}
}
Оставить комментарий: