Создание поиска по своим меткам на Яндекс.Карте с использованием PHP и MySQL

В этой заметке я хочу рассказать Вам, как можно организовать поиск по своим данным о метках с использованием PHP и MySQL.

Я в своем примере буду использовать данные по некоторым агентствам недвижимости Нижнего Новгорода.

В начале нам необходимо в базе данных MySQL создать таблицу mymetki_ymap, для хранения данных о наших метках.

Сделать это можно используя phpMyAdmin с помощью SQL-запроса:

CREATE TABLE IF NOT EXISTS `mymetki_ymap` (
  `id` int(5) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `adress` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `lat_map` varchar(255) NOT NULL,
  `lng_map` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Поясню значение полей таблицы:

name — служит для хранения наименования организации;
address – здесь хранится адрес расположения организации;
phone — телефоны;
lat_map и lng_map — для хранения значений долготы и широты соответственно

Также используя phpMyAdmin заполним нашу таблицу mymetki_ymap исходными данными:

INSERT INTO `mymetki_ymap` (`id`, `name`, `adress`, `phone`, `lat_map`, `lng_map`) VALUES
(1, 'Абзац ', 'Нижний Новгород, Совнаркомовская,25', '8-915-955-98-95', '43.956211', '56.324411'),
(2, 'Абсолют-НН ', 'Нижний Новгород, пр.Кораблестроителей,26/1', '(831) 227-06-35', '43.810935', '56.363608'),
(3, 'Аверс ', 'Нижний Новгород, Рождественская,24-13', '(831) 430-06-89', '43.988047', '56.327655'),
(4, 'Какаду ', 'Нижний Новгород, ул. Гордеевская, 7, ул. Б. Печерская, 83', '(831) 220-31-17, 220-31-18, 277-26-81, 432-71-97', '43.943006', '56.326348'),
(5, 'Алые паруса ', 'Нижний Новгород, пл.Театральная,5/Пискунова,6', '(831) 419-60-63, 419-57-05', '44.000426', '56.323987'),
(6, 'Альфа недвижимость ', 'Нижний Новгород, Сергея Есенина,32', '(831) 414-55-17, 249-60-02', '43.934382', '56.334867'),
(7, 'Альфа Риэлти ', 'Нижний Новгород, Чаадаева,5-320', '(831) 274-58-51,413-20-71', '43.854378', '56.329188'),
(8, 'Берегиня+ ', 'Нижний Новгород, Адмирала Васюнина,2-212', '(831) 417-55-26,417-41-41', '44.039053', '56.296729'),
(9, 'Благовест ', 'Нижний Новгород, Берёзовская,22', '(831) 274-22-70,413-23-59', '43.881471', '56.318651'),
(10, 'Благострой ', 'Нижний Новгород, Кошелева,2', '(831) 279-50-49', '43.888873', '56.314966'),
(11, 'Большой город ', 'Нижний Новгород, Максима Горького,184', '(831) 439-12-78, 411-96-40', '44.017907', '56.318895'),
(12, 'Ваш жилой континет ', 'Нижний Новгород, Маршала Воронова,3', '(831) 413-94-11,275-49-74', '43.926647', '56.323573'),
(13, 'Гарант плюс ', 'Нижний Новгород, Лескова,18', '(831) 256-36-65,259-10-46', '43.862768', '56.235931'),
(14, 'Гарант риэлти ', 'Нижний Новгород, Варварская,32-414', '(831) 419-81-59,419-81-55', '44.012876', '56.321281'),
(15, 'Геосфера ', 'Нижний Новгород, Полтавская,14-401', '(831) 438-35-35,416-70-94', '44.025273', '56.316634'),
(16, 'Дом-52 ', 'Нижний Новгород, пр.Гагарина,110в', '(831) 278-94-66,278-94-64,413-54-25', '43.977968', '56.270621'),
(17, 'Единство ', 'Нижний Новгород, Рождественская,28а', '(831) 430-50-80,439-77-01,439-77-02', '43.986834', '56.327750'),
(18, 'Жилсервис-НН ', 'Нижний Новгород, пр.Октября,15', '(831) 295-55-83', '43.864825', '56.250272'),
(19, 'Заречье ', 'Нижний Новгород, пер.Райниса,1-3', '(831) 413-62-00,257-99-79,258-50-63', '43.917547', '56.265852'),
(20, 'ЗемСтрой ', 'Нижний Новгород, Максима Горького,151', '(831) 419-42-12,414-12-21', '44.018482', '56.318246'),
(21, 'Золотое руно ', 'Нижний Новгород, Баранова,9а', '(831) 410-82-90', '43.845691', '56.335236'),
(22, 'Золотой ключик ', 'Нижний Новгород, Родионова,191', '(831) 438-47-94,413-97-61', '44.079046', '56.303481'),
(23, 'Император ', 'Нижний Новгород, Октябрьской Революции,56', '(831) 245-01-04,240-03-81', '43.937391', '56.309893'),
(24, 'Камелот Риэлти ', 'Нижний Новгород, Красных Зорь,25-1', '(831) 272-18-88,413-51-18', '43.867394', '56.333395'),
(25, 'Квадри НН ', 'Нижний Новгород, Октябрьская,27-4', '(831) 434-03-97', '44.084634', '56.293277'),
(26, 'Квартирный вопрос ', 'Нижний Новгород, Культуры,5', '(831) 215-06-83', '43.857872', '56.349629'),
(27, 'Кворум ', 'Нижний Новгород, Мечникова,39', '(831) 276-77-40,271-68-83', '43.839286', '56.336403'),
(28, 'Континет ', 'Нижний Новгород, Переходникова,29', '(831) 253-75-55', '43.899527', '56.262632'),
(29, 'Кредо ', 'Нижний Новгород, пр.Ленина,58', '(831) 258-49-29,244-93-86', '43.922057', '56.275404'),
(30, 'Ларец ', 'Нижний Новгород, Бориса Корнилова,8', '(831) 413-09-22,417-82-92,417-73-13', '44.044344', '56.299676'),
(31, 'Лига Лайн ', 'Нижний Новгород, Зайцева,31-718', '(831) 414-29-90', '43.801377', '56.373734'),
(32, 'Титан ', 'Нижний Новгород, Долгополова,24', '(831) 414-28-75,246-52-52', '43.946850', '56.319110'),
(33, 'Титул ', 'Нижний Новгород, пр.Героев,19', '(831) 270-08-33', '43.893508', '56.318106'),
(34, 'Уют-компания ', 'Нижний Новгород, пр.Октября,8-9', '(831) 295-06-47', '43.865274', '56.246891'),
(35, 'Александр Невский ', 'Нижний Новгород, пр.Ленина,56-37', '8-920-059-59-99', '43.922263', '56.276024');

Затем организуем поиск по таблице в базе данных.

YmapsML-файл формировать будем с помощью файла creat-ymapsml-avtosal.php

Код файла:

<?php
 
header("Content-type: text/xml");
 
include("bd.php");
 
echo '<ymaps xmlns="http://maps.yandex.ru/ymaps/1.x" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maps.yandex.ru/schemas/ymaps/1.x/ymaps.xsd"> 
    <Representation xmlns="http://maps.yandex.ru/representation/1.x"> 
        <Style gml:id="agentnedv"> 
            <iconStyle> 
            <href>http://api-maps.yandex.ru/i/0.4/icons/buildings.png</href> 
                <size x="27" y="26"/> 
                <offset x="-13" y="-13"/> 
            </iconStyle> 
 
            <balloonContentStyle> 
                <template>#balloonTemplate</template> 
            </balloonContentStyle> 
        </Style> 
 
        <Template gml:id="balloonTemplate"> 
            <text><![CDATA[
			<div style="font-size:12px;"> 
                        <div style="color:#ff0303;font-weight:bold">$[name]</div>                        
                        <div>Адрес: $[metaDataProperty.AnyMetaData.adres|не задан]</div>
                        <div>Телефон: $[metaDataProperty.AnyMetaData.telefon|не задан]</div>         
                    </div>]]></text> 
        </Template> 
    </Representation> 
 
    <GeoObjectCollection> 
        <gml:name>Объекты карте</gml:name> 
        <style>#agentnedv</style> 
        <gml:featureMembers>';
 
$query1= "SELECT * FROM mymetki_ymap";
$result1 = mysql_query($query1);
while ($par1 = mysql_fetch_array($result1))
{	
 
 
echo '<GeoObject>';
echo '<gml:name>', $par1['name'], '</gml:name>';
echo '<gml:metaDataProperty>';
echo '<AnyMetaData>';
echo '<adres>', $par1['adress'], '</adres>';
echo '<telefon>', $par1['phone'], '</telefon>';
echo '</AnyMetaData>';
echo '</gml:metaDataProperty>';
echo '<gml:Point>';
echo '<gml:pos>', $par1['lat_map'], ' ', $par1['lng_map'], '</gml:pos>';
echo '</gml:Point>';
echo '</GeoObject>';
 
echo "n";
 
}
 
echo '</gml:featureMembers>
    </GeoObjectCollection>
</ymaps>';
 
 
?>

В начале мы объявляем тип файла для браузера text/xml.

Затем подключаем файл bd.php для соединения с базой данных:

<?php
 
$sdb_name = "localhost";
$user_name = "user";
$user_password = "user123";
$db_name = "ymaps_bd";
 
// соединение с сервером базы данных
if(!$link = mysql_connect($sdb_name, $user_name, $user_password))
{
  echo "<br>Не могу соединиться с сервером базы данных<br>";
  exit();
}
 
// выбираем базу данных
if(!mysql_select_db($db_name, $link))
{
  echo "<br>Не могу выбрать базу данных<br>";
  exit();
}
 
mysql_query('SET NAMES utf8');
 
?>

После с помощью оператора echo формируем YMapsML-файл.

Задаем стиль agentnedv для отображения значка метки iconStyle и шаблон содержимого балуна balloonTemplate

Выбираем данные из таблицы mymetki_ymap и формируем объекты геоколлекции.

Подробнее о формате YmapsML можно прочитать в документации

Файл vivagentnedv-ymap.html будет выводить карту с метками из файла YmapsML.

Код:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <title>Поиск по своим меткам на Яндекс.Карте с использованием PHP и MySQL</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 <script src="http://api-maps.yandex.ru/1.1/index.xml?key=ANpUFEkBAAAAf7jmJwMAHGZHrcKNDsbEqEVjEUtCmufxQMwAAAAAAAAAAAAvVrubVT4btztbduoIgTLAeFILaQ==~AMSxmUwBAAAA5WSyQAMAwB5YJ3rvTgSgDcPJynaIsXvmUkYAAAAAAAAAAABv1IbpHjj4ZIFUHyMRhnQtZxjXZg==" type="text/javascript"></script> 
    <script language="JavaScript" type="text/javascript"> 
 
	var map;
 
        // Создание обработчика для события window.onLoad
        YMaps.jQuery(function () {
            // Создание экземпляра карты и его привязка к созданному контейнеру
            map = new YMaps.Map(YMaps.jQuery("#YMapsID")[0]);
 
            // Установка для карты ее центра и масштаба
            map.setCenter(new YMaps.GeoPoint(43.998779,56.316537), 12);
 
			map.addControl(new YMaps.Zoom());
	        map.addControl(new YMaps.TypeControl());
	        map.addControl(new YMaps.ToolBar());
 
            // Создание и добавление YMapsML-документа на карту
            var ml = new YMaps.YMapsML("http://map.cek.ru/files/fs/creat-ymapsml-agentnedv.php");
            map.addOverlay(ml);
 
            // Обработчик неудачной загрузки YMapsML
            YMaps.Events.observe(ml, ml.Events.Fault, function (ml, error) {
                alert('Ошибка: ' + error);
            });
        });
 
</head>
<body>
 
<table> 
    <tr> 
        <td style="vertical-align:top; "> 
    <div id="YMapsID" style="width:500px;height:400px"></div> 
</td> 
<td style="vertical-align:top; "> 
<strong>Поиск поставщиков агенств недвижимости по карте:</strong> 
<form action="#" method="POST" onSubmit="do_search(this.company.value); return false;">  
<input type="text" id="company" name="company" size="30" value="" /><br> 
<em>например: Абзац</em> 
<p><input type="submit" value="Найти" /></p></form> 
<div id="search_res"></div> 
</td> 
</tr> 
 
</table></p> 
 
</body>
</html>

В разделе body расположена таблица в одной ячейке отображается карта , в другой форма поиска с контейнером для результатов.

Замечание: если Вы будете выполнять пример на локальном компьютере нужно чтобы creat-ymapsml-agentnedv.php был доступен из Интернета, т. к. содержимое файла YmapsML обрабатывается сервером Яндекса.

Для осуществления поиска мы добавим в код файла vivagentnedv-ymap.html функцию do_search.

Код функции:

function do_search(company){
map.removeAllOverlays();
YMaps.jQuery('#search_res').html('');
 
YMaps.jQuery.getJSON("http://map.cek.my/files/fs/searcheagentnedv.php", {company:company}, function(json){
 
if (json.status == 'OK') {  
var src_res="<p><strong>результаты поиска: </strong></p>";
src_res=src_res+'<p><strong>Найдено объектов: '+json.markers.length+'</strong></p>';
for (i = 0; i < json.markers.length; i++) {
var placemark=new YMaps.Placemark(new YMaps.GeoPoint(json.markers[i].lat,json.markers[i].lon));
placemark.description='<div style="color:#ff0303;font-weight:bold">'+json.markers[i].cname+'</div>';
placemark.description=placemark.description+'<strong>Адрес:</strong> '+json.markers[i].address+'<br><strong>Телефон:</strong> '+json.markers[i].phone;
map.addOverlay(placemark);
src_res=src_res+'<p><a href="#" onClick="return go_to('+json.markers[i].lat+', '+json.markers[i].lon+",'"+json.markers[i].cname+"','"+json.markers[i].address+"','"+json.markers[i].phone+"','"+json.markers[i].id+"');"+'">'+json.markers[i].cname+'</a><br>'+json.markers[i].address+'</p>';
}
 
}
else
{
var src_res = '<p><strong>результаты поиска</strong></p><font color="red">По Вашему запросу объектов на карте не найдено</font>';
}
YMaps.jQuery('#search_res').html(src_res);
 
});
}

В качестве параметра функции выступает company — название компании из формы поиска.

В функции do_search в начале мы удаляем все оверлеи с карты с помощью
map.removeAllOverlays() и очищаем контейнер с результатами поиска Ymaps.jQuery(‘#search_res’).html(‘ ‘);
После мы осуществляем AJAX запрос к файлу searcheagentnedv.php используя функцию getJSON с
помощью встроенной в API Яндекс.Карт JavaScript-библиотеки jQuery.

В файле searcheagentnedv.php мы осуществляем запрос к базе данных для поиска и формируем файл формата JSON с результатами поиска.

Подробнее о формате JSON можно прочитать здесь

В месте с данными о найденных метках передается параметр успешности поиска status, если он равен OK, то мы обрабатываем переданные значения — наносим найденные метки на карту и выводим список со ссылками в контейнер результатов поиска search_res.

Если поиск завершился неудачно, выводится сообщение: «По Вашему запросу объектов на карте не найдено».

По клику по названию метки в списке результатов поиска вызывается функция go_to — происходит центрирование карты по координатам данной метки и открывается балун с информацией.

Код функции:

function go_to(lat,lon,cname,address,phone,id){
map.setCenter(new YMaps.GeoPoint(lat,lon),17);
map.removeAllOverlays();
var placemark=new YMaps.Placemark(new YMaps.GeoPoint(lat,lon));
placemark.name='<div style="color:#ff0303;font-weight:bold">'+cname+'</div>';
placemark.description='<div><strong>Адрес:</strong> '+address+'<br><strong>Телефон:</strong> '+phone+'</div>';
map.addOverlay(placemark);
placemark.openBalloon();
return false;
}

Теперь приведу код файла searcheagentnedv.php, который осуществляет запрос к базе данных и формирует результаты поиска в формате JSON:

Код

<?php
 
include("bd.php");
 
header('Content-Type: text/html; charset=utf-8');
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 
$company = $_GET['company'];
 
$name_remont = htmlspecialchars(trim($company));
 
$json = '{markers:['."n";
 
$query1= "SELECT * FROM mymetki_ymap where  name LIKE '%$name_remont%'  ORDER BY name";
$result1 = mysql_query($query1);
 
if(mysql_num_rows($result1)>0)
{
while ($par1 = mysql_fetch_array($result1)){
 
$cname =  htmlspecialchars($par1['name']);
 
$json.= "n".'{'.'"id": "'.$par1['id'].'",';
 
$json.= '"cname": "'.$cname.'",';
 
$json.= '"address": "'.$par1['adress'].'",';
 
$json.= '"phone": "'.$par1['phone'].'",';
 
$json.= '"lat": "'.$par1['lat_map'].'",';
 
$json.=  '"lon": "'.$par1['lng_map'].'"';
 
$json.= '},';
 
}
 
$json = substr($json, 0,-1);
 
echo  $json;
 
echo '], ', "n",  '"status": "OK"', "n", '}';
 
}
else
{
echo '{"status": "false"}';
}
 
}
 
?>

Вид JSON-файла с результатами поиска (запрос: альфа):

{markers:[

{"id": "6","cname": "Альфа недвижимость ","address": "Нижний Новгород, Сергея Есенина,32","phone": "(831) 414-55-17, 249-60-02","lat": "43.934382","lon": "56.334867"},
{"id": "7","cname": "Альфа Риэлти ","address": "Нижний Новгород, Чаадаева,5-320","phone": "(831) 274-58-51,413-20-71","lat": "43.854378","lon": "56.329188"}],
"status": "OK"
}

В коде файла searcheagentnedv.php все предельно ясно.

Проверяем как отправлено значение переменной company, если через AJAX, то $_SERVER[‘HTTP_X_REQUESTED_WITH’] == ‘XMLHttpRequest’.

Мы получаем переданные методом GET данные, удаляем из строки $company лишние пробелы и производим преобразование спецсимволов в их HTML эквиваленты, на всякий случий, если кто-то захочет в нашу форму написать какой-либо код.

Затем мы посылаем запрос к таблице mymetki_ymap и если результат найден с помощью оператора echo формируем содержимое JSON-файла.

Если результат не найден, отправляем строку {"status": "false"}.

Посмотреть работу примера в действии

Загрузить исходные файлы примера

  • Гость: У YMaps.SearchControl (http://api.yandex.ru/maps/jsapi/doc/ref/reference/searchcontrol.xml) можно указать опции геокодирования. Одна из них, позволяет переопределить используемый сервис геокодирования - geocodeProvider. Для этого нужно реализовать несложный интерфейс YMaps.IGeocodeProvider (http://api.yandex.ru/maps/jsapi/doc/ref/reference/igeocodeprovider.xml). Таким образом, вы можете "научить" SearchControl искать по своей базе объектов, а если в базе ничего не было найдено, то пробовать произвести обычное геокодирование. Думаю, что это будет неплохим продолжением вашей статьи.
  • Гость: Большое спасибо авторам за объемную работу по кластерам, очень полезные скрипты, а самое главное работают без отказно!!! РЕСПЕКТ!
  • Гость: Подскажите пож-та, после обработки поиска можно ли выводить данные с различными иконками? например иконка кафе и кинотеатра. можете помочь с примером? эти данные надо добавлять в вывод JSON-файла??
  • Гость: это же апи 1