Гео-модуль для PHP приложений

    image Вопрос «Где?» возникает сразу же после вопроса «Что?» эта закономерность верна и в вебразработке. Многие сайты запрашивают информацию у пользователя, предлагая ему ввести свой адрес, т. е. страну, регион, город, улицу, дом почтовый индекс. Но как потом обрабатывать эти данные, если они были указаны в свободной форме? В своих первых проектах мы использовали свой «велосипед», но по мере роста и развития это «чудо» превратилось в «чудовище», которое поставило крест на эффективной обработке гео-информации о наших пользователях. Мне была поставлена задача прибить этого монстра, заменив его стандартизованной гео-базой и простым интерфейсом для работы с ней. Гугление на эту тему не дали готового решения, поэтому пришлось отбросить простой вариант и сделать свой гео-модуль.

    База адресов России


    Для начала, нужно было найти базу адресов России. В поисках базы адресов я наткнулся на две и вполне возможно, что единственные:
    1. КЛАДР (Классификатор адресов РФ) распространяется в *.dbf формате
    2. ФИАС (Федеральная информационная адресная система). По умолчанию распространятся в виде xml структуры, но видать пришлось еще подстраиваться под КЛАДР и из-за его архаизма ФИАС стал распространятся еще и в dbf формате

    Разница между ними такая: 400 Мб КЛАДР-а против 9 Гб ФИАС-а — существенно, не правда ли? По этому определённо хочется пользоваться ФИАС-ом, т. к. по объёму можно полагать, что данные у него более избыточны, что соответственно и лучше. Но работа с ФИАС у меня не сложилась. Запросы по таблице адресов, были ужасно долгие и ни расстановка индексов, ни оптимизация запросов мне не помогли, пользовался я при этом MySQL 5.5

    С КЛАДР-ом же, работа сложилась и как выяснилось позже, его детализации для моих (стандартных) задач, вполне хватает. Обзор по структуре таблиц КЛАДР-а можно почитать здесь/ Для него же кто-то сделал api, которое не работает :-), но авось ребята допилят, думаю многим будет полезно.

    Для того, что бы можно было использовать КЛАДР в проекте, нужно его из распространяемого dbf формата конвертировать в что-то понятное MySQL. Впрочем можно залить базу напрямую, для этого можно использовать navicat или mydbf2mysql.

    Таким образом, я сделал простой гео-модуль, который можно докрутить под любые нужды.
    Проект можно получить на Github.

    Что из себя представляет модуль?


    Проект писался с использованием php 5.3, что важно.
    СУБД MySQL 5.5, что не очень важно.

    Используемые библиотеки

    • php Data Layer Doctrine 2
    • js jquery
    • js jquery.form
    • js jquery.autocomplete
    • css 960cs

    Структура файлов проекта
    .project # Корень проекта
    -css\ 
    -js\
    --plugins
    ---autocomplete 
    ----jquery.autocomplete.js
    ---jquery.form.js
    --cabinet.js # скрипт для страницы с формой
    --initialize.js # скрипт инициализации
    --jquery-1.7.2.js 
    -Entities\ 
    --GeoLocation.php # Сущность с данными локации ip адреса
    --UserLocation.php # Сущность с данными локации пользователя
    --Kladr.php # Сущность содержит записи с объектами первых четырех уровней классификации
    --Socrbase.php # Сущность содержит записи с краткими наименованиями типов адресных объектов
    --Street.php # Сущность содержит записи с объектами пятого уровня классификации
    --Doma.php # Сущность содержит записи с объектами шестого уровня классификации
    --KladrRepository.php 
    --HomeRepository.php 
    --StreetRepository.php 
    -Geo\
    --Providers\
    ---Deliveries # Поставщики услуг доставки 
    ----Ems\ 
    -----EmsDeliveryDecorator.php # Класс декоратор рассчитывающий EMS доставку 
    -----EmsDiliveryProvider.php # Класс реализующий API сервиса EMS для расчёта доставки 
    -----ENUM_EMS.php # перечисления команд
    ----RussianPost\ 
    -----RussianPostDeliveryDecorator.php # Класс декоратор рассчитывающий доставку Почты России
    -----RussianPostDeliveryProvider.php # Класс реализующий API сервиса PostCalc для расчёта доставки 
    ---Geocoder\ # Поставщики сервисов гео-кодирования
    ----Yandex\ 
    -----Geocoder.php
    ----MapApiBase.php # Абстрактный класс для гео-кодирования
    ---Delivery.php 
    ---DeliveryBase.php
    ---DeliveryDecoratorBase.php
    ---DeliveryDecoratorRound.php
    ---DeliveryProviderBase.php 
    --common.php
    --Geo.php
    --GoecoderCreater.php # Фабрика для объекта гео-кодирования
    --ILocationBuilder.php 
    --Location.php # класс умеющий делать запросы в сервис geo-ip
    --LocationBuilder.php # строитель объкта \Entities\UserLocation, по данным полученны от геокодера
    -_content.php 
    -autobox.php # точка входа для запросов плагина выпадающих списков(оркуг/город)
    -autocomlete.php # точка входа для
    -Autoloader.php # мой авто-загрузчик классов
    -delivery.php # точка входа для запросов на расчёт доставки
    -index.php # основная точка входа
    -popup.php # пример реализации через модальное popup окно colorbox 
    -run.php # bootstrap example приложения
    -String.php # строковые общие статические методы
    


    Используемые api сервисы

    • Geo IP сервис — этих ребят blog.ipgeobase.ru
    • EMS расчёт доставки emspost.ru
    • RussianPost(иначе почта России) расчёт доставки postcalc.ru
    • Yandex карта 2.0

    Что умеем

    • Делать запросы в КЛАДР
    • Делать запросы в ipgeo, для получения расположения пользователя по его ip
    • Делать запросы в EMS API для расчёта доставки
    • Делать запросы в PostCalc для расчёта доставки
    • Серверное гео-кодирование yandex map

    Процесс устроен так: при загрузки страницы, получаем по ip адресу geo расположения пользователя, для этого сначала смотрим существует ли запись с ключом(ip адресом) в таблице geoLocation, если есть берём от туда, если нет, делаем запрос в сервис ipGeo полученные данные сохраняем в табличке geoLocation, для последующего сокращения трафика запросов в ipgeo сервис. Имеющиеся данные о расположении пользователя используем для предсказания расположения пользователя, т.е. три (регион/округ/город) выпадающих списках, заполняем данными и выделяем в них нужное расположение. Если расположение угадано верно, то пользователю останется указать только улицу и дом, а индекс (если он есть в кладре) подставится автоматически. Впрочем если по ip адресу расположение было не угадано, то регион/округ/город можно изменить. Для этого был написал простенки js плагин, который согласно выбранного региона запрашивает округ и большие города региона, а согласно выбранного округа, города округа.

    Есть yandex карта для отображения сохраненного расположения пользователя. Впрочем, можно сделать что бы карта на лету реагировала, на выбор пользователем локации.

    В конце страницы с формой задания адреса, для демонстрации имеется блок с расчётом доставки. Сам пакет доставки реализован, как «декоратор», поэтому можно настраивать калькуляцию сумм или время доставки. Собственно как работает калькуляция, должно быть понятно, нужно знать откуда и куда, а далее дело техники. Расчёт доставки можно расширить, путём добавления нового *поставщика*.

    Удачно то, что структура указания адресов ФИАС схожа с КЛАДР, прошу заметить не идентична, а схожа поэтому если немного от-рефакторить код репозитория \Entities\KadrRepository, то можно использовать и ФИАС как хранилище адресов, вопрос только нужно ли это.

    Подробное описание API модуля публикую в WiKi проекта на github

    Надеюсь, что кому-то этот модуль будет полезен, но не претендую на идеальное решение, буду рад услышать замечания и предложения.
    Pokupo
    0.00
    Торговая платформа полного цикла Pokupo
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 36

      +11
      Впервые вижу, чтобы платежная система что-то отдавала бесплатно, да еще и через Github.

      Так держать!
        –44
        <offtop>
        Только я прочитал гей-модуль вместо гео?
          +22
          ты спалился )
            +19
            У Фрейда для вас плохие новости
              –12
              мда…
              порой шутки обходятся слишком дорого.
              • UFO just landed and posted this here
                0
                «Your problem is quite clear...» © Joey Friends

                www.youtube.com/watch?v=-wkcobSvExM
                0
                а почему вы не использовали браузерное определение местоположения через GeoLocation API?
                  0
                  Ммм… Вероятно, потому что на серверной стороне нет никакого браузера?
                    0
                    ну вообще-то тут форма клиентская, с jquery плагинами, можно было в клиентской форме определять местоположение, потом уж по IP
                      0
                      Что определять-то? ymaps.geolocation покажет положение человека, открывшего форму. Там нет функционала пробить конкретный ip.
                        0
                        показывать способ доставки от места твоего расположенеия или до твоего места, не догоняете зачем это здесь pix.am/P3ph/? почему бы это в модуль доставки не встроить? очень удобно и точно
                    0
                    Стояла задача помочь пользователю указать полный почтовый адрес (включая улицу, дом, индекс) для сохранения строки адреса и ключей, а определение его местонахождения по IP это уже прикрутили для удобства. Соглашусь эту фичу можно было и по другому реализовать.
                    +4
                    Doma.php

                    Ну чтож вы так то?

                    P.S. По самому модулю — спасибо!
                      +2
                      А это из КЛАДР, самого улыбнуло, таблица домов doma, а улиц street видимо в ФНС такой проф. сленг ) не стал переименовывать такую «фишку» только для простоты восприятия.
                      0
                      А почему вы не использовали формат geoip (его maxmind использует)? Он быстрый и готовая библиотека в PHP есть: www.php.net/manual/en/ref.geoip.php
                        0
                        Он вроде как не всегда и везде установлен, видимо поэтому, но автору виднее.
                          0
                          Также есть независимая библиотека на чистом PHP, тоже на удивление быстро работающая.
                          У автора могли быть причины ее не использовать, вопрос как раз в том — в чем эти причины заключаются.
                            0
                            Ага я в курсе, применял пару раз бесплатную версию:)
                          0
                          не полная база, иногда врет
                            0
                            Я не про содержание базы говорю, а про формат хранения.
                              0
                              ясен пень, что бинарное дерево по доступу быстрее, чем SQL (хотя там тоже в индексах исп бинарное дерево)
                              на мой взгляд тут вылезает проблема перевода данных из одного офрмата в другой.
                          0
                          Эх, опередили. Пару месяцев назад пытался сконструировать похожий велосипед. Импорт фиасовской базы в мускуль (импортировал из xml, не смог совладать с dbf-ными кодировками — хотелось юникод везде) вообще пеня была. Сервер на неделю ушел в себя
                          Потом время свободное кончилось, забросил это.
                          А сейчас, кажется, гугл начал отдавать почтовые индексы, нет?
                            +1
                            Обработку данных адреса в произвольном формате я решил так
                            1) Зарегистрировался тут api.yandex.ru/maps/ и получил API key
                            2) Дальше воспользовался их геокодированием, кормил его адресом введенным вручную
                            3) В ответе геокодер передавал координаты, но ГЛАВНОЕ разбирал руками введенный адрес.
                            Хотя описывается задача, которая работает налету, и более приспособлена для работы, мне хватило решения с яндексом
                              +1
                              спасибо, все очень полезно…
                              я решал гео-задачу через ngx_geoip
                              использовал КЛАДР, ФИАС не использовал.
                                –3
                                Я надеюсь, вы приобрели это изображение для статьи: www.shutterstock.com/pic-74757313/stock-vector-map-of-the-world-and-signs-in-the-form-of-a-teaser-for-the-website.html
                                Если не купили, то хотя бы скажите, пожалуйста, где взяли.
                                  0
                                  Взял из поиска, сейчас воткнул ссылку на исходник где он и был, не было цели нанести какой-либо материальный ущерб использованием изображения для статьи Open Source проекта.

                                  P.S. Кстати подскажите как проверить изображение на предмет его свободности для публикации? Понятно, что любая картинка чей-то труд, но не все же являются воинствующими правообладателями.
                                    –1
                                    У меня не было претензий лично к вам, так как я понимаю, что скорее всего вы просто взяли картинку в интернете. Именно потому и попросил указать, где взяли.
                                    Дело в том, что я лично знаю иллюстратора, который является автором изображения. Знаю, сколько труда вкладывается в их создание. Очень обидно, когда иллюстрация не выкладывалась автором на публичных источниках, но каким-то образом там оказывается.
                                      –1
                                      Спасибо, что указали источник. Теперь все встало на свои места.
                                      Картинка использовалась для статьи: www.webimax.com/blog/seo/geo-targeted-keywords-in-domains-relevant-for-local-according-to-study и была приобретена.
                                      Если вам для проекта понадобится данное изображение в большем разрешении, то напишите в личку.
                                    0
                                    А что не сложилось с ФИАС?
                                    Какие именно запросы вы совершали?

                                    Я пока туда не лазил, но распарсил в древовидную структуру и засунул в mongodb.
                                      +1
                                      Демку кто-нибудь у себя может поднять?
                                        0
                                        еще в тему, вот сегодня наткнулся geocoder-php.org
                                          0
                                          не определяет мой город… я делал такое с maxmind — самое полное издание!
                                          • UFO just landed and posted this here
                                              0
                                              Подскажите более безгрешную альтернативу.
                                                0
                                                Да вот вроде: post-api.ru

                                            Only users with full accounts can post comments. Log in, please.