2

Хочу поделиться своими наработками. так же хотелось доработать скрипт.

Если есть желающие, то подключайтесь. (хочу разложить адрес на составляющие, ещё было бы лучше анализировать все результаты с google и yandex и собрать максимальную информацию)

  • 1
    Эту информацию вам следовало оформить в виде ответа на свой же вопрос, так как тутошная система автоматически может через определенный период времени удалять вопросы без ответов. Вот впример такого вопроса-ответа https://ru.stackoverflow.com/q/435546/186083 – Visman Nov 30 '17 at 04:37
  • Спасибо за информацию, на будущее учту. – Александр Зарифулли Nov 30 '17 at 08:11

1 Answers1

1

Как это работает:

Размещаете файл geocoder на сервере/хостинге или на своё сервере apache с поддержкой PHP

Файл принимает как $_POST (отдельные параметры) так и тело JSON

Обязательные ключи:

  • api - yandex или google
  • type - adrress или LL
  • lat - Широта - число с разделителем "." (Если тип LL то обязательное поле)
  • lng - Долгота - число с разделителем "." (Если тип LL то обязательное поле)
  • name - Наименование - строка (Название адреса) - (Если тип adrress то обязательное поле)
  • key - Ключ google API

Возвращаемое значение JSON (Ключи):

  • [response] - Ответ сервиса API
  • [data][address] - Результат обработки (Название адреса)
  • [data][lat] - Результат обработки (Широта)
  • [data][lng] - Результат обработки (Долгота)

Содержание фала geocoder.php:

<? 

    # Получаем массив с заголовками headers
    $headers = getallheaders();

    # Определяем переменные по умолчанию для входящего JSON
    $isJSON = false;
    $php_input = null;

    if (isset($headers['Content-Type'])) {
        if ($headers['Content-Type'] = 'application/json') { # Проверяем заголовк на тип JSON
            $php_input = file_get_contents('php://input'); # Получаем не обработанные данные
            $isJSON = true; # Это JSON
        }        
    }

    # Генерируем массив для ответа
    $result = array();
    $result[msg] = 'Невозможно определить данный формат запроса';

    if ($isJSON && $php_input != null) { # Если входящий запрос в формате JSON
        $postJSON = json_decode($php_input, true);

        $result[success] = true;
        $result[msg] = 'Данные обработаны';
        $result[query][type] = $postJSON['type'];
        $result[query][api] = $postJSON['api'];
        $result[query][name] = $postJSON['name'];
        $result[query][lat] = (real) $postJSON['lat'];
        $result[query][lng] = (real) $postJSON['lng'];
        $result[query][key] = $postJSON['key'];
    } else {
        $result[success] = true;
        $result[msg] = 'Данные обработаны';
        $result[query][type] = $_POST['type'];
        $result[query][api] = $_POST['api'];
        $result[query][name] = $_POST['name'];
        $result[query][lat] = (real) $_POST['lat'];
        $result[query][lng] = (real) $_POST['lng'];
        $result[query][key] = $_POST['key'];
    }

    # Проверяем сгенерированный ключ 'query'
    if (array_key_exists('query', $result)) {

        # Проверяем тип получаемых данных и какой api использовать
        if (isset($result[query][type]) && isset($result[query][api])) {

            # Используем API yandex
            if ($result[query][api] == 'yandex') {

                # Формируем тело запроса 
                if ($result[query][type] == 'LL') {
                    $query = $result[query][lng]. ',' .$result[query][lat];    
                } else if ($result[query][type] == 'address') {
                    $query = urlencode($result[query][name]);
                }

                # Выполняем запрос к серверу API
                $geocoder = 'https://geocode-maps.yandex.ru/1.x/';
                # 1. инициализация
                $ch = curl_init(); # Создаем дескриптор cURL
                # 2. устанавливаем опции, включая урл
                curl_setopt($ch, CURLOPT_URL, $geocoder);
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_POSTFIELDS, "geocode=$query&format=json");
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); # Устанавливаем параметр, чтобы curl возвращал данные, вместо того, чтобы выводить их в браузер.
                curl_setopt($ch, CURLOPT_TIMEOUT, 10);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
                # 3. выполнение запроса и получение ответа
                $response = curl_exec($ch); # Запускаем

                if ($response === FALSE) {
                    $result[success] = false;
                    $result[msg] = curl_error($ch);
                } else {
                    # Если тело ответа не пустое
                    if (!empty($response)) {
                        # Преобразуем в массив
                        $json = json_decode($response, true); 
                        # Устанавливаем ответ сервера
                        $result[response] = $json;

                        # Если результат является массивом
                        if (is_array($json)) {
                            $found = $json[response][GeoObjectCollection][featureMember];
                            $components = $found[0][GeoObject][metaDataProperty][GeocoderMetaData][Address];
                            $point = $found[0][GeoObject][Point][pos];
                            $pos = explode(' ', $point);

                            $address = array();
                            $address[address] = $components[formatted];
                            $address[lat] = (real) $pos[1];
                            $address[lng] = (real) $pos[0]; 

                            $result[data] = $address;
                        }

                    } else {
                        $result[success] = false;
                        $result[msg] = 'Пустой ответ сервера';   
                    }    
                }

                # 4. очистка ресурсов
                curl_close($ch); # Закрываем дескриптор                           
            }

            # Используем API google
            if ($result[query][api] == 'google') {

                # Определяем тип запроса 
                if ($result[query][type] == 'LL') {
                    $query = 'latlng=';
                    $query .= $result[query][lat];
                    $query .= ',';
                    $query .= $result[query][lng];
                    $query .= '&key=';
                    $query .= $result[query][key];
                    $query .= '&language=ru';
                }
                # Определяем тип запроса
                if ($result[query][type] == 'address') {
                    $query = 'address=';
                    $query .= urlencode($result[query][name]);
                    $query .= '&key=';
                    $query .= $result[query][key];
                    $query .= '&language=ru';
                }


                # Выполняем запрос к серверу API
                $geocoder = 'https://maps.googleapis.com/maps/api/geocode/json'. '?' .$query;
                # 1. инициализация
                $ch = curl_init(); # Создаем дескриптор cURL
                # 2. устанавливаем опции, включая урл
                curl_setopt($ch, CURLOPT_URL, $geocoder);
                curl_setopt($ch, CURLOPT_POST, 0);
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); # Устанавливаем параметр, чтобы curl возвращал данные, вместо того, чтобы выводить их в браузер.
                curl_setopt($ch, CURLOPT_TIMEOUT, 10);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
                # 3. выполнение запроса и получение ответа
                $response = curl_exec($ch); # Запускаем


                if ($response === FALSE) {
                    $result[success] = false;
                    $result[msg] = curl_error($ch);
                } else {
                   # Если тело ответа не пустое
                    if (!empty($response)) {
                        # Преобразуем в массив
                        $json = json_decode($response, true); 
                        # Устанавливаем ответ сервера
                        $result[response] = $json;

                        # Если результат является массивом
                        if (is_array($json)) {
                            $components = $json[results][0];                

                            $address = array();
                            $address[address] = $components[formatted_address];
                            $address[lat] = (real) $components[geometry][location][lat];
                            $address[lng] = (real) $components[geometry][location][lng];                            

                            $result[data] = $address;
                        }

                    } else {
                        $result[success] = false;
                        $result[msg] = 'Пустой ответ сервера';   
                    }    
                }

                # 4. очистка ресурсов
                curl_close($ch); # Закрываем дескриптор            
            }
        }


    }


    /* с этим я не стал пока разбираться, хотел разложить */

    # Класс для работы с результатом JSON
    class Response {
        # GeoObject[]
        protected $_list = array();
        protected $_data;

        public function __construct(array $data) {
            $this->_data = $data;
            if (isset($data['response']['GeoObjectCollection']['featureMember'])) {
                foreach ($data['response']['GeoObjectCollection']['featureMember'] as $entry) {
                    $this->_list[] = new GeoObject($entry['GeoObject']);
                }
            }
        }

        # Исходные данные
        public function getData() {
            return $this->_data;
        }

        # GeoObject[]
        public function getList() {
            return $this->_list;
        }

        # @return null|GeoObject
        public function getFirst() {
            $result = null;

            if (count($this->_list)) {
                $result = $this->_list[0];
            }

            return $result;
        }

        # Возвращает исходный запрос
        public function getQuery() {
            $result = null;

            if (isset($this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['request'])) {
                $result = $this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['request'];
            }

            return $result;
        }

        # Кол-во найденных результатов
        public function getFoundCount() {
            $result = null;
            if (isset($this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['found'])) {
                $result = (int)$this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['found'];
            }

            return $result;
        }

        # Широта в градусах. Имеет десятичное представление с точностью до семи знаков после запятой
        public function getLatitude() {
            $result = null;
            if (isset($this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['Point']['pos'])) {
                list(,$latitude) = explode(' ', $this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['Point']['pos']);
                $result = (float) $latitude;
            }
            return $result;
        }

        # Долгота в градусах. Имеет десятичное представление с точностью до семи знаков после запятой
        public function getLongitude() {
            $result = null;

            if (isset($this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['Point']['pos'])) {
                list($longitude,) = explode(' ', $this->_data['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['Point']['pos']);
                $result = (float)$longitude;
            }

            return $result;
        }
    }
    # Дополнительный класс
    class GeoObject {
        protected $_addressHierarchy = [
            'Country' => array('AdministrativeArea'),
            'AdministrativeArea' => array('SubAdministrativeArea', 'Locality'),
            'SubAdministrativeArea' => array('Locality'),
            'Locality' => array('DependentLocality', 'Thoroughfare'),
            'DependentLocality' => array('DependentLocality', 'Thoroughfare'),
            'Thoroughfare' => array('Premise'),
            'Premise' => array(),
        ];
        protected $_data;
        protected $_rawData;

        public function __construct(array $rawData) {
            $data = array(
                'Address' => $rawData['metaDataProperty']['GeocoderMetaData']['text'],
                'Kind' => $rawData['metaDataProperty']['GeocoderMetaData']['kind']
            );
            array_walk_recursive(
                $rawData,
                function ($value, $key) use (&$data) {
                    if (in_array(
                        $key,
                        array(
                            'CountryName',
                            'CountryNameCode',
                            'AdministrativeAreaName',
                            'SubAdministrativeAreaName',
                            'LocalityName',
                            'DependentLocalityName',
                            'ThoroughfareName',
                            'PremiseNumber',
                        )
                    )) {
                        $data[$key] = $value;
                    }
                }
            );
            if (isset($rawData['Point']['pos'])) {
                $pos = explode(' ', $rawData['Point']['pos']);
                $data['Longitude'] = (float)$pos[0];
                $data['Latitude'] = (float)$pos[1];
            }
            $this->_data = $data;
            $this->_rawData = $rawData;
        }
        public function __sleep() {
            return array('_data');
        }

        # Необработанные данные
        # @return array
        public function getRawData() {
            return $this->_rawData;
        }

        # Обработанные данные
        # @return array
        public function getData() {
            return $this->_data;
        }

        # Широта в градусах. Имеет десятичное представление с точностью до семи знаков после запятой
        # @return float|null
        public function getLatitude() {
            return isset($this->_data['Latitude']) ? $this->_data['Latitude'] : null;
        }

        # Долгота в градусах. Имеет десятичное представление с точностью до семи знаков после запятой
        # @return float|null
        public function getLongitude() {
            return isset($this->_data['Longitude']) ? $this->_data['Longitude'] : null;
        }

        # Полный адрес
        # @return string|null
        public function getAddress() {
            return isset($this->_data['Address']) ? $this->_data['Address'] : null;
        }

        # Тип
        # @return string|null
        public function getKind() {
            return isset($this->_data['Kind']) ? $this->_data['Kind'] : null;
        }

        # Страна
        # @return string|null
        public function getCountry() {
            return isset($this->_data['CountryName']) ? $this->_data['CountryName'] : null;
        }

        # Код страны
        # @return string|null
        public function getCountryCode() {
            return isset($this->_data['CountryNameCode']) ? $this->_data['CountryNameCode'] : null;
        }

        # Административный округ
        # @return string|null
        public function getAdministrativeAreaName() {
            return isset($this->_data['AdministrativeAreaName']) ? $this->_data['AdministrativeAreaName'] : null;
        }

        # Область/край
        # @return string|null
        public function getSubAdministrativeAreaName() {
            return isset($this->_data['SubAdministrativeAreaName']) ? $this->_data['SubAdministrativeAreaName'] : null;
        }

        # Населенный пункт
        # @return string|null
        public function getLocalityName() {
            return isset($this->_data['LocalityName']) ? $this->_data['LocalityName'] : null;
        }

        # @return string|null
        public function getDependentLocalityName() {
            return isset($this->_data['DependentLocalityName']) ? $this->_data['DependentLocalityName'] : null;
        }

        # Улица
        # @return string|null
        public function getThoroughfareName() {
            return isset($this->_data['ThoroughfareName']) ? $this->_data['ThoroughfareName'] : null;
        }

        # Номер дома
        # @return string|null
        public function getPremiseNumber() {
            return isset($this->_data['PremiseNumber']) ? $this->_data['PremiseNumber'] : null;
        }

        # Полный адрес
        # @return array
        public function getFullAddressParts() {
            return array_unique(
                $this->_parseLevel(
                    $this->_rawData['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country'],
                    'Country'
                )
            );
        }

        # @param array $level
        # @param String $levelName
        # @param array $address
        # @return array
        protected function _parseLevel(array $level, $levelName, &$address = []) {
            if (!isset($this->_addressHierarchy[$levelName])) {
                return;
            }

            $nameProp = $levelName === 'Premise' ? 'PremiseNumber' : $levelName.'Name';
            if (isset($level[$nameProp])) {
                $address[] = $level[$nameProp];
            }

            foreach ($this->_addressHierarchy[$levelName] as $child) {
                if (!isset($level[$child])) {
                    continue;
                }
                $this->_parseLevel($level[$child], $child, $address);
            }

            return $address;
        }
    }


    # Возвращаем результат
    echo json_encode($result);

?>

получение данные из JavaScript

data = new FormData();
data.append('api', 'google');
data.append('type', 'address');
data.append('lat', $('#lat').val());
data.append('lng', $('#lng').val());
data.append('name', $('#name').val());
data.append('key', 'lkjahfjghjahljkfhadshfljkasd-5wFhzayGf0');

$.ajax({
    type: 'POST',
    method: 'POST',
    url: '/api/geocoder',
    headers: {'Cache-Control': 'no-cache'},
    data: data,
    dataType: 'json', 
    contentType: false,
    processData: false,
    cache: false,
    success: function(response) {
        /* response - Это JS объект*/
        process_the_answer_of_a_geo_server(response);
    }
});

Получение данных из 1С 8.3

&НаКлиенте
Процедура ПолучитьДанные(Команда)

    Данные = Новый Структура;
    Данные.Вставить("api", "google");
    Данные.Вставить("type", "address");
    Данные.Вставить("lat", "");
    Данные.Вставить("lng", "");
    Данные.Вставить("name", "105120, Москва г, Мрузовский пер");
    Данные.Вставить("key", "lkjbhfsdkjhgkjsdfhgjhlsdfhgjfdsl");


    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, Данные);

    JSON = ЗаписьJSON.Закрыть();

    Соединение = Новый HTTPСоединение("eta.api", 8080);

    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Content-Type", "application/json");

    Запрос = Новый HTTPЗапрос("/api/geocoder", Заголовки);  
    Запрос.УстановитьТелоИзСтроки(JSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

    Ответ = Соединение.ОтправитьДляОбработки(Запрос);

    Результат = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);  

    СообщениеПользователю = Новый СообщениеПользователю;
    СообщениеПользователю.Текст = Результат;
    СообщениеПользователю.Сообщить();

    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(Результат);
    Параметр = ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();   

КонецПроцедуры

Да и в каталоге где лежит файл geocoder.php там я ещё файл такой создал .htaccess

содержание .htaccess

RewriteEngine On 
RewriteCond %{REQUEST_FILENAME} 
!-f RewriteRule ^([^\.]+)$ $1.php [NC,L]" 

Это я вызываю его без расширения *.php