Определение местоположения. Геотаргетинг.

Представляю 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);
	}
}

Оставить комментарий:

Представьтесь пожалуйста:
Электронная почта:
Электронный адрес не публикуются
Текст сообщения:
Для подсветки кода, оборачивайте ваш код в теги <code></code>
Введите 5 цифр с картинки:

Рекомендую:

Поддержать проект:

бесполезная кнопка, которую еще никто не нажал:)
Нажали! Кнопку нажали уже 7 человек!!! Спасибо, очень мотивирует!