Использование геолокации Битрикс, написание собственного обработчика
Одна из распространенных задач в Bitrix - это определение местоположения пользователя по его ip (геолокация). В компоненте оформления заказа sale.order.ajax
есть возможность включить геолокацию, значит где то в составе фреймворка она уже реализована.
Если зайти в админку Настройки > Настройки продукта > Геолокация, то можно увидеть такой список:
Для Sypex Geo и MaxMind нужны ключи для доступа к сервисам. Сами обработчики являются классами наследниками от \Bitrix\Main\Service\GeoIp\Base
Свои обработчики можно добавить с помощью события onMainGeoIpHandlersBuildList
модуля main. Событие вызывается при инициализации списка обработчиков геолокации. Ожидается получение результата тип \Bitrix\Main\EventResult тип - \Bitrix\Main\EventResult::SUCCESS
в качестве параметров - массив со списком обработчиков.
Пример:
<?
function addCustomGeoIpHandler()
{
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::SUCCESS,
array(
'\Custom\GeoIP\Handler' => '/local/custom/geoip/handler.php'
),
'main'
);
}
$eventManager->addEventHandler('main', 'onMainGeoIpHandlersBuildList', 'addCustomGeoIpHandler');
?>
Использование
Чтобы определить местоположение с помощью этих обработчиков требуется IP пользователя. Его можно получить так:
$ip = \Bitrix\Main\Service\GeoIp\Manager::getRealIp();
Чтобы получить информацию по этому ip от обработчиков нужно исползовать следующий метод:
$geolocationResult = \Bitrix\Main\Service\GeoIp\Manager::getDataResult($ip, "ru");
В результате будет возвращен объект класса \Bitrix\Main\Service\GeoIp\Result
\Bitrix\Main\Service\GeoIp\Manager
будет перебирать доступные обработчики геолокации до тех пор пока не получит результат на заданном языке (второй параметр) с заданными полями (3й параметр).
А вот так вот может выглядеть готовый обработчик:
<?
namespace Gricuk\GeoIp;
use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Main\Text\Encoding;
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Service\GeoIp\Result;
use Bitrix\Main\Service\GeoIp\Data;
use Bitrix\Main\Service\GeoIp\ProvidingData;
class IpApi extends \Bitrix\Main\Service\GeoIp\Base
{
public static function onMainGeoIpHandlersBuildListHandlers()
{
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::SUCCESS,
array(
'\Gricuk\GeoIp\IpApi' => "local/php_interface/lib/Gricuk/GeoIp/IpApi.php",
)
);
}
/**
* @return string Title of handler.
*/
public function getTitle()
{
return 'ip-api.com';
}
/**
* @return string Handler description.
*/
public function getDescription()
{
return "ip-api.com";
}
/**
* @param string $ipAddress Ip address
* @param string $userId user identifier obtained from www.maxmind.com
* @param string $licenseKey
* @return Main\Result
*/
protected function sendRequest($ipAddress, $userId, $licenseKey)
{
$result = new Main\Result();
$httpClient = $this->getHttpClient();
$httpRes = $httpClient->get("http://ip-api.com/php/" . $ipAddress . '?lang=ru');
$errors = $httpClient->getError();
if (!$httpRes && !empty($errors)) {
$strError = "";
foreach ($errors as $errorCode => $errMes)
$strError .= $errorCode . ": " . $errMes;
$result->addError(new Error($strError));
} else {
$status = $httpClient->getStatus();
if ($status != 200)
$result->addError(new Error('Http status: ' . $status));
$arRes = @unserialize($httpRes);
if (is_array($arRes)) {
if (strtolower(SITE_CHARSET) != 'utf-8')
$arRes = Encoding::convertEncoding($arRes, 'UTF-8', SITE_CHARSET);
if ($arRes["status"] == "success") {
$result->setData($arRes);
} else {
$result->addError(new Error('[' . $arRes['code'] . '] ' . $arRes['error']));
}
} else {
$result->addError(new Error('Can\'t unserialize result'));
}
}
return $result;
}
/**
* @return HttpClient
*/
protected static function getHttpClient()
{
return new HttpClient(array(
"version" => "1.1",
"socketTimeout" => 5,
"streamTimeout" => 5,
"redirect" => true,
"redirectMax" => 5,
));
}
/**
* Languages supported by handler ISO 639-1
* @return array
*/
public function getSupportedLanguages()
{
return array('ru');
}
/**
* @param string $ipAddress Ip address
* @param string $lang Language identifier
* @return Result | null
*/
public function getDataResult($ipAddress, $lang = '')
{
$dataResult = new Result();
$geoData = new Data();
$geoData->ip = $ipAddress;
$geoData->lang = $lang = strlen($lang) > 0 ? $lang : 'en';
$res = $this->sendRequest($ipAddress, $this->config['USER_ID'], $this->config['LICENSE_KEY']);
if ($res->isSuccess()) {
$data = $res->getData();
if (!empty($data['country']))
$geoData->countryName = $data['country'];
if (!empty($data['countryCode']))
$geoData->countryCode = $data['countryCode'];
if (!empty($data["regionName"]))
$geoData->regionName = $data['regionName'];
if (!empty($data["region"]))
$geoData->regionCode = $data['region'];
if (!empty($data["city"]))
$geoData->cityName = $data['city'];
if (!empty($data['org']))
$geoData->organizationName = $data['org'];
if (!empty($data['isp']))
$geoData->ispName = $data['isp'];
if (!empty($data['timezone']))
$geoData->timezone = $data['timezone'];
if (!empty($data['lat']))
$geoData->latitude = $data['lat'];
if (!empty($data['lon']))
$geoData->longitude = $data['lon'];
if (!empty($data['zip']))
$geoData->zipCode = $data['zip'];
} else {
$dataResult->addErrors($res->getErrors());
}
$dataResult->setGeoData($geoData);
return $dataResult;
}
/**
* Is this handler installed and ready for using.
* @return bool
*/
public function isInstalled()
{
return true;
}
/**
* @param array $postFields Admin form posted fields during saving process.
* @return array Field CONFIG for saving to DB in admin edit form.
*/
public function createConfigField(array $postFields)
{
return array(
);
}
/**
* @return array Set of fields description for administration purposes.
*/
public function getConfigForAdmin()
{
return array(
);
}
/**
* @return ProvidingData Geolocation information witch handler can return.
*/
public function getProvidingData()
{
$result = new ProvidingData();
$result->countryName = true;
$result->countryCode = true;
$result->regionName = true;
$result->regionCode = true;
$result->cityName = true;
$result->latitude = true;
$result->longitude = true;
$result->timezone = true;
$result->zipCode = true;
$result->ispName = true;
$result->organizationName = true;
return $result;
}
}