Замена стандартных обработчиков геолокации на локальный сервис DaData.ru в Битрикс

23 апреля 2024
BXmeta

Столкнулись с проблемой работы стандартных обработчиков геолокации в России? Или нет возможности оплатить их услуги? В нашей новой статье мы расскажем, как легко и быстро переключиться на локальный сервис DaData.ru.

Мы покажем, как настроить и интегрировать DaData.ru с вашим проектом на Битрикс, чтобы обеспечить точное определение геолокации ваших пользователей. Следуйте нашим пошаговым инструкциям и получите рабочее решение без лишних затрат.

Решение

Создаем личный кабинет на сайте dadata.ru
Создать файл /local/php_interface/lib/dadata_geo.php (скопировать в него код из примера ниже)

<?php

namespace BXmeta\GeoIp;

use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Main\Text\Encoding;
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Service\GeoIp\Result;
use Bitrix\Main\Service\GeoIp\Data;
use Bitrix\Main\Service\GeoIp\ProvidingData;

class DadataGeo extends \Bitrix\Main\Service\GeoIp\Base
{
    /**
     * @return string Title of handler.
     */
    public function getTitle()
    {
        return 'dadata.ru';
    }

    /**
     * @return string Handler description.
     */
    public function getDescription()
    {
        return "https://dadata.ru/";
    }

    /**
     * @param string $ipAddress Ip address
     * @return Main\Result
     */
    protected function sendRequest($ipAddress)
    {
        $result = new Main\Result();
        $httpClient = $this->getHttpClient();
        $httpClient->setHeader('Content-Type', 'application/json');
        $httpClient->setHeader('Accept', 'application/json');
        $httpClient->setHeader('Authorization', 'Token ' . $this->config['API_KEY']);
        $httpClient->setHeader('X-Secret', $this->config['SECRET_KEY']);

        $url = "https://suggestions.dadata.ru/suggestions/api/4_1/rs/iplocate/address";

        $posData = [
            "ip" => $ipAddress
        ];

        $httpRes = $httpClient->post($url, json_encode($posData));
        $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('dadata.ru http status: ' . $status));
            } else {
                $arRes = json_decode($httpRes, true);

                if (is_array($arRes)) {
                    if (mb_strtolower(SITE_CHARSET) != 'utf-8')
                        $arRes = Encoding::convertEncoding($arRes, 'UTF-8', SITE_CHARSET);

                    $result->setData($arRes);
                } else {
                    $result->addError(new Error('Can\'t decode json result'));
                }
            }
        }

        return $result;
    }

    /**
     * @return HttpClient
     */
    protected static function getHttpClient()
    {
        return new HttpClient([
            "version" => "1.1",
            "socketTimeout" => 5,
            "streamTimeout" => 5,
            "redirect" => true,
            "redirectMax" => 5,
        ]);
    }

    /**
     * Languages supported by handler ISO 639-1
     * @return array
     */
    public function getSupportedLanguages()
    {
        return ['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);

        if ($res->isSuccess()) {
            $rowData = $res->getData();
            $data = $rowData['location']['data'];

            if (!empty($data['country']))
                $geoData->countryName = $data['country'];

            if (!empty($data['country_iso_code']))
                $geoData->countryCode = $data['country_iso_code'];

            if (!empty($data["region_with_type"]))
                $geoData->regionName = $data['region_with_type'];

            if (!empty($data["region_iso_code"]))
                $geoData->regionCode = $data['region_iso_code'];

            if (!empty($data["city"]))
                $geoData->cityName = $data['city'];

            if (!empty($data['timezone']))
                $geoData->timezone = $data['timezone'];

            if (!empty($data['geo_lat']))
                $geoData->latitude = $data['geo_lat'];

            if (!empty($data['geo_lon']))
                $geoData->longitude = $data['geo_lon'];

            if (!empty($data['postal_code']))
                $geoData->zipCode = $data['postal_code'];


        } 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 [
            'API_KEY' => isset($postFields['API_KEY']) ? $postFields['API_KEY'] : '',
            'SECRET_KEY' => isset($postFields['SECRET_KEY']) ? $postFields['SECRET_KEY'] : '',
        ];
    }

    /**
     * @return array Set of fields description for administration purposes.
     */
    public function getConfigForAdmin()
    {
        return [
            [
                'NAME' => 'API_KEY',
                'TITLE' => 'Api key',
                'TYPE' => 'TEXT',
                'VALUE' => htmlspecialcharsbx($this->config['API_KEY'])
            ],
            [
                'NAME' => 'SECRET_KEY',
                'TITLE' => 'Secret key',
                'TYPE' => 'TEXT',
                'VALUE' => htmlspecialcharsbx($this->config['SECRET_KEY'])
            ],
        ];
    }

    /**
     * @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 = false;
        $result->zipCode = true;
        $result->ispName = false;
        $result->organizationName = false;
        return $result;
    }
}

В файл init.php добавить обработчик события onMainGeoIpHandlersBuildList (скопировать в него код из примера ниже)

<?php
use \Bitrix\Main\EventManager;

function customGeoIpHandler()
{
    return new \Bitrix\Main\EventResult(
        \Bitrix\Main\EventResult::SUCCESS,
        array(
            '\BXmeta\GeoIp\DadataGeo' => '/local/php_interface/lib/dadata_geo.php'
        ),
        'main'
    );
}

$eventManager = EventManager::getInstance();
$eventManager->addEventHandler('main', 'onMainGeoIpHandlersBuildList', 'customGeoIpHandler');
Переходим в список обработчиков ваш_сайт/bitrix/admin/geoip_handlers_list.php?lang=ru
- Добавляем обработчик
- Указываем ключи полученные в личном кабинете dadata.ru