Pull to refresh

Использование связки из PHP и MySQL совместно с Google Maps

Reading time 13 min
Views 16K
Original author: Pamela Fox, Google Maps API Team

Отсебятина


А вот и перевод третьего урока по Google Maps API. Этот урок — как видно из названия — посвящен созданию карт при помощи данных, хранящихся в БД. Как и предыдущие — кросс-пост из моего блога.

Этот урок предназначен для людей, знакомых со связкой PHP/MySQL и желающих научиться использовать Google Maps API вместе с базами данных MySQL. После завершения этого урока у Вас будет карта, основанная на базе данных. На карте будут расположены маркеры разных цветов. Одни из них будут указывать на рестораны, другие – на бары. При клике по маркеру будет появляться инфо-окно, показывающее название места и его адрес.
Урок разбит на следующие параграфы:
  • Создание таблицы БД;
  • Наполнение таблицы;
  • Вывод информации в XML с помощью PHP;
  • Создание карты.

СОЗДАНИЕ ТАБЛИЦЫ


Когда создаете таблицу, прежде всего, Вы должны уделить внимание параметрам lat (широта) и lng (долгота) карты. При текущей разрешающей способности Google Maps нам понадобятся только 6 цифр после десятичного знака. Чтобы свести дисковое пространство, занимаемое БД к минимуму, для значений lat (широты) и lng (долготы) рекомендуется выбрать тип данных FLOAT с параметром 10,6. Этот тип позволяет хранить до 6-ти знаков после запятой и до 4-х перед запятой, например -123,456789 градуса. Ваша таблица должна иметь поле id, которое будет первичным ключом для доступа к записям, а также – поле type, в котором будет записан тип заведения (ресторан или бар).
Примечание: в этом уроке используются места, значения широты и долготы которых уже известно и используются для нанесения маркеров на карту. Если же Вы попробуете использовать свою информацию, не имея данных о координатах места, то воспользуйтесь сервисом геокодинга для преобразования адреса места в его координаты. Вот список некоторых геокодинг-сервисов: http://groups.google.com/group/Google-Maps-API/web/resources-non-google-geocoders.
Если Вы предпочитаете создавать таблицы в БД с помощью phpMyAdmin, то ниже расположен скриншот создания таблицы:
picture
Если же Вы не имеете доступ к phpMyAdmin или отдаете предпочтение чистому SQL, то ниже приведен код SQL-запроса:
CREATE TABLE `markers` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR( 60 ) NOT NULL,
`address` VARCHAR( 80 ) NOT NULL,
`lat` FLOAT( 10, 6 ) NOT NULL,
`lng` FLOAT( 10, 6 ) NOT NULL,
`type` VARCHAR( 30 ) NOT NULL
) ENGINE = MYISAM ;

НАПОЛНЕНИЕ ТАБЛИЦЫ


После создания таблицы пришло время наполнить ее информацией. Данные о 10 заведениях Сиэтла приведены ниже. В phpMyAdmin Вы можете использовать опцию ИМПОРТ для того, чтобы вставить в таблицу данные, хранящиеся в различных форматах, включая и CSV. Приложения MS Excel и Google Spreadsheets поддерживают экспорт данных в CSV-формат. Так что Вы легко можете передавать данные из этих приложений в БД MySQL, используя опции экспорта/импорта.
Вот информация, представленная в формате CSV:
Pan Africa Market,&#034 1521 1st Ave, Seattle, WA&#034,47.608941,-122.340145,restaurant
Buddha Thai & Bar,&#034 2222 2nd Ave, Seattle, WA&#034,47.613591,-122.344394,bar
The Melting Pot,&#034 14 Mercer St, Seattle, WA&#034,47.624562,-122.356442,restaurant
Ipanema Grill,&#034 1225 1st Ave, Seattle, WA&#034,47.606366,-122.337656,restaurant
Sake House,&#034 2230 1st Ave, Seattle, WA&#034,47.612825,-122.34567,bar
Crab Pot,&#034 1301 Alaskan Way, Seattle, WA&#034,47.605961,-122.34036,restaurant
Mama's Mexican Kitchen,&#034 2234 2nd Ave, Seattle, WA &#034,47.613975,-122.345467,bar
Wingdome,&#034 1416 E Olive Way, Seattle, WA&#034,47.617215,-122.326584,bar
Piroshky Piroshky,&#034 1908 Pike pl, Seattle, WA&#034,47.610127,-122.342838,restaurant

А вот скриншот, показывающий импорт данных из CSV в таблицу БД:
picture
Если же Вы не используете phpMyAdmin, то ниже расположен код запроса к БД на языке SQL:
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Pan Africa Market', '1521 1st Ave, Seattle, WA', '47.608941', '-122.340145', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Buddha Thai & Bar', '2222 2nd Ave, Seattle, WA', '47.613591', '-122.344394', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('The Melting Pot', '14 Mercer St, Seattle, WA', '47.624562', '-122.356442', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Ipanema Grill', '1225 1st Ave, Seattle, WA', '47.606366', '-122.337656', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Sake House', '2230 1st Ave, Seattle, WA', '47.612825', '-122.34567', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Crab Pot', '1301 Alaskan Way, Seattle, WA', '47.605961', '-122.34036', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Mama Mexican Kitchen', '2234 2nd Ave, Seattle, WA', '47.613975', '-122.345467', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Wingdome', '1416 E Olive Way, Seattle, WA', '47.617215', '-122.326584', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Piroshky Piroshky', '1908 Pike pl, Seattle, WA', '47.610127', '-122.342838', 'restaurant');

ВЫВОД ИНФОРМАЦИИ В XML C ПОМОЩЬЮ PHP


К этому моменту у Вас должна быть таблица (которая называется markers) базы данных, заполненная данными. Сейчас Вам нужно написать некоторый PHP-код, который позволит подключиться к БД, взять из нее необходимую информацию и экспортировать ее в XML-файл, с которым будет взаимодействовать карта с помощью асинхронных JavaScript-запросов. Если же Вы никогда не писали на PHP код, позволяющий подключиться к БД, то Вам необходимо посетить сайт php.net и почитать о функциях mysql_connect(), mysql_select_db(), my_sql_query(), и mysql_error().
Примечание: некоторые уроки предлагают Вам создать страницу с картой как PHP-файл и использовать JavaScript для вывода каждого маркера в отдельности. Такой подход может быть проблематичен. Используя же XML-файл в качестве посредника между БД и картой, Вы ускоряете первоначальную загрузку страницы и облегчаете себе отладку приложения. Вы можете проверять данные, записанные из БД в XML-файл и результат анализа этого файла на JavaScript. И на любой стадии Вы можете обойтись без БД, управляя картой только с помощью статичного XML-файла.
Во-первых, Вы должны вынести информацию о подключении к БД в отдельный файл. Ниже приведен PHP-код, в котором Вы должны прописать собственные имя пользователя, пароль и имя БД:
<?
$username="username";
$password="password";
$database="username-databaseName";
?>

Использование XML-функций PHP для создания XML-файла
Проверьте конфигурацию PHP или попытайтесь использовать функцию domxml_new_doc() для того, чтобы проверить dom_xml-функциональность. Если Вы имеете доступ к dom_xml-функциям, то Вы можете использовать их для создания XML-узлов и вывода XML-документа на экран. С помощью функций dom_xml Вы можете создавать XML-документы практически любой сложности.
В PHP, для начала, нужно инициализировать новый XML-документ и создать родительский узел “marlers”. Затем нужно подключиться к БД и произвести выбор необходимых данных при помощи запроса вида SELECT * (выбрать все) к таблице с именем “markers” и пройтись по всем результатам этой выборки. Для каждой записи в таблице (каждого заведения) будет создаваться свой узел в XML-документе, атрибуты которого будут полями из соответствующей записи таблицы, — этот узел будет присоединяться к родительскому узлу. После этого Вы получите готовый XML-документ.
Примечание: если в БД Вы используете международные символы, то нужно применить кодировку UTF-8 к выводимым данным. Вот функция перекодировки в UTF-8.
Ваш PHP-код должен быть похож на тот, что представлен ниже:
<?php
require(&#034phpsqlajax_dbinfo.php&#034);
// Создание XML-файла и родительского элемента
$doc = domxml_new_doc(&#034 1.0 &#034);
$node = $doc->create_element(&#034markers&#034);
$parnode = $doc->append_child($node);

// Открытие соединения с MySQL-сервером
$connection=mysql_connect (localhost, $username, $password);
if (!$connection) {
die('Нет соединения : ' . mysql_error());
}

// Подключение к конкретной БД
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Невозможно использовать БД : ' . mysql_error());
}

// Выборка всех записей из таблицы markers
$query = &#034SELECT * FROM markers WHERE 1"
$result = mysql_query($query);
if (!$result) {
die('Неверный запрос: ' . mysql_error());
}

header(&#034Content-type: text/xml&#034);

// Цикл прохода по всем выбранным записи; создание узла для каждой
while ($row = @mysql_fetch_assoc($result)){
// Добавление нового узла в XML
$node = $doc->create_element(&#034marker&#034);
$newnode = $parnode->append_child($node);

$newnode->set_attribute(&#034name&#034, $row['name']);
$newnode->set_attribute(&#034address&#034, $row['address']);
$newnode->set_attribute(&#034lat&#034, $row['lat']);
$newnode->set_attribute(&#034lng&#034, $row['lng']);
$newnode->set_attribute(&#034type&#034, $row['type']);
}

$xmlfile = $doc->dump_mem();
echo $xmlfile;

?>

Использование PHP-функции echo для создания XML-файла
Если Вы не имеете доступ к функциям dom_xml, то XML-файл можно создать с помощью функции echo. При использовании функции echo нужно будет написать функцию-помощник (например, parseToXML), которая будет декодировать некоторые специальные символы (>,<,’,”), чтобы не возникало ошибок XML.
В PHP, для начала, нужно подключиться к БД и произвести выбор необходимых данных при помощи запроса вида SELECT * (выбрать все) к таблице с именем “markers” и пройтись по всем результатам этой выборки. Затем необходимо вывести родительский узел при помощи функции echo и пройтись по результатам выборки. При этом необходимо использовать написанную нами функцию parseToXML. Выполнение этого скрипта должно закончиться выводом закрывающего тэга markers.
Примечание: если в БД Вы используете международные символы, то нужно применить кодировку UTF-8 к выводимым данным. Вот функция перекодировки в UTF-8.
Ваш PHP-код должен быть похож на тот, что представлен ниже:
<?php
require(&#034phpsqlajax_dbinfo.php&#034);

function parseToXML($htmlStr)
{
$xmlStr=str_replace('<','&lt;',$htmlStr);
$xmlStr=str_replace('>','&gt;',$xmlStr);
$xmlStr=str_replace('&#034','&quot;',$xmlStr);
$xmlStr=str_replace(&#034'&#034,'&#39;',$xmlStr);
$xmlStr=str_replace(&#034&&#034,'&amp;',$xmlStr);
return $xmlStr;
}

// Открываем соединение с MySQL-сервером
$connection=mysql_connect (localhost, $username, $password);
if (!$connection) {
die('Нет соединения : ' . mysql_error());
}

// Устанавливаем соединение с БД
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Невозможно использовать БД : ' . mysql_error());
}

// Выборка всех записей из таблицы markers
$query = &#034SELECT * FROM markers WHERE 1"
$result = mysql_query($query);
if (!$result) {
die('Неверный запрос: ' . mysql_error());
}

header(&#034Content-type: text/xml&#034);

// Создание XML-кода, вывод родительского элемента
echo '<markers>';

// Цикл прохода по всем выбранным записи; создание узла для каждой
while ($row = @mysql_fetch_assoc($result)){
// Вывод нового узла XML
echo '<marker ';
echo 'name=&#034' . parseToXML($row['name']) . '&#034 ';
echo 'address=&#034' . parseToXML($row['address']) . '&#034 ';
echo 'lat=&#034' . $row['lat'] . '&#034 ';
echo 'lng=&#034' . $row['lng'] . '&#034 ';
echo 'type=&#034' . $row['type'] . '&#034 ';
echo '/>';
}

// Конец XML-файла
echo '</markers>';

?>

Использование DOM-функций PHP для создания XML-файла
Во-первых, необходимо убедиться в том, что Вы используете PHP версии 5. Если Ваша версия PHP ниже, то используйте какой-либо из предыдущих способов.
В PHP, для начала, нужно инициализировать новый XML-документ и создать родительский узел “markers”. Затем нужно подключиться к БД и произвести выбор необходимых данных при помощи запроса вида SELECT * (выбрать все) к таблице с именем “markers” и пройтись по всем результатам этой выборки. Для каждой записи в таблице (каждого заведения) будет создаваться свой узел в XML-документе, атрибуты которого будут полями из соответствующей записи таблицы, — этот узел будет присоединяться к родительскому узлу. После этого Вы получите готовый XML-документ.
Примечание: если в БД Вы используете международные символы, то нужно применить кодировку UTF-8 к выводимым данным. Вот функция перекодировки в UTF-8.
<?php

require(&#034phpsqlajax_dbinfo.php&#034);

// Создание XML-файла и родительского элемента

$dom = new DOMDocument(&#034 1.0 &#034);
$node = $dom->createElement(&#034markers&#034);
$parnode = $dom->appendChild($node);

// Открытие соединения с MySQL-сервером

$connection=mysql_connect (localhost, $username, $password);
if (!$connection) { die(' Нет соединения: ' . mysql_error());}

// Подключение к конкретной БД

$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Невозможно использовать БД : ' . mysql_error());
}

// Выборка всех записей из таблицы markers

$query = &#034SELECT * FROM markers WHERE 1"
$result = mysql_query($query);
if (!$result) {
die('Неверный запрос: ' . mysql_error());
}

header(&#034Content-type: text/xml&#034);

// Цикл прохода по всем выбранным записи; создание узла для каждой

while ($row = @mysql_fetch_assoc($result)){
// Добавление нового узла в XML
$node = $dom->createElement(&#034marker&#034);
$newnode = $parnode->appendChild($node);
$newnode->setAttribute(&#034name&#034,$row['name']);
$newnode->setAttribute(&#034address&#034, $row['address']);
$newnode->setAttribute(&#034lat&#034, $row['lat']);
$newnode->setAttribute(&#034lng&#034, $row['lng']);
$newnode->setAttribute(&#034type&#034, $row['type']);
}

echo $dom->saveXML();

?>

Проверка вывода XML
Запустите этот скрипт, чтобы убедиться в правильности результатов вывода. Если существуют какие-нибудь проблемы с подключением к БД, то можно попробовать удалить строку с заголовком содержимого (text/xml), т.к. она может мешать Вашему браузеру отображать сообщения об ошибках.
Если же скрипт правильно выполнил свою работу, то Вы должны увидеть следующее:
<markers>
<marker name=&#034 Pan Africa Market&#034 address=&#034 1521 1st Ave, Seattle, WA&#034 lat=&#034 47.608940&#034 lng=&#034 -122.340141&#034 type=&#034 restaurant&#034/>
<marker name=&#034 Buddha Thai & Bar&#034 address=&#034 2222 2nd Ave, Seattle, WA&#034 lat=&#034 47.613590&#034 lng=&#034 -122.344391&#034 type=&#034 bar&#034/>
<marker name=&#034 The Melting Pot&#034 address=&#034 14 Mercer St, Seattle, WA&#034 lat=&#034 47.624561&#034 lng=&#034 -122.356445&#034 type=&#034 restaurant&#034/>
<marker name=&#034 Ipanema Grill&#034 address=&#034 1225 1st Ave, Seattle, WA&#034 lat=&#034 47.606365&#034 lng=&#034 -122.337654&#034 type=&#034 restaurant&#034/>
<marker name=&#034 Sake House&#034 address=&#034 2230 1st Ave, Seattle, WA&#034 lat=&#034 47.612823&#034 lng=&#034 -122.345673&#034 type=&#034 bar&#034/>
<marker name=&#034 Crab Pot&#034 address=&#034 1301 Alaskan Way, Seattle, WA&#034 lat=&#034 47.605961&#034 lng=&#034 -122.340363&#034 type=&#034 restaurant&#034/>
<marker name=&#034 Mama's Mexican Kitchen&#034 address=&#034 2234 2nd Ave, Seattle, WA&#034 lat=&#034 47.613976&#034 lng=&#034 -122.345467&#034 type=&#034 bar&#034/>
<marker name=&#034 Wingdome&#034 address=&#034 1416 E Olive Way, Seattle, WA&#034 lat=&#034 47.617214&#034 lng=&#034 -122.326584&#034 type=&#034 bar&#034/>
<marker name=&#034 Piroshky Piroshky&#034 address=&#034 1908 Pike pl, Seattle, WA&#034 lat=&#034 47.610126&#034 lng=&#034 -122.342834&#034 type=&#034 restaurant&#034/>
</markers>

СОЗДАНИЕ КАРТЫ


Раз XML-файл правильно отображается в браузере, то пришло время создать карту, используя JavaScript. Если Вы никогда не имели дела с Google Maps API, то изучите, пожалуйста, основы при помощи официальной документации.
Подгрузка XML-файла
Для того, чтобы загрузить XML-файл на страницу, необходимо использовать API-функцию GDownloadURL. GDownloadURL является как бы оболочкой для метода XMLHttpRequest, который используется для отправки запросов в XML-форме. Первым параметром функции GDownloadURL является путь к XML-файлу. Второй же параметр – это функция, которая будет выполняться при получении ответа от XML.
Примечание: очень важно понять, что GDownloadURL работает асинхронно – функция, являющаяся вторым параметром GDownloadURL, не будет срабатывать, как только Вы применили этот метод. Чем объемней Ваш XML-файл, тем больше потребуется времени для вызова этой функции-параметра. Не следует помещать никакого кода, отвечающего за размещение маркеров на карте, после метода GDownloadURL – его нужно помещать в функцию-параметр.
Функция-параметр необходима для того, чтобы отыскать все элементы “markers” в XML. Для каждого маркера мы восстанавливаем значения названия, адреса, типа и координат, а затем мы передаем эти значения функции creatMarker, которая помещает маркеры на карту.
GDownloadUrl(&#034phpsqlajax_genxml.php&#034, function(data) {
var xml = GXml.parse(data);
var markers = xml.documentElement.getElementsByTagName(&#034marker&#034);
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute(&#034name&#034);
var address = markers[i].getAttribute(&#034address&#034);
var type = markers[i].getAttribute(&#034type&#034);
var point = new GLatLng(parseFloat(markers[i].getAttribute(&#034lat&#034)),
             parseFloat(markers[i].getAttribute(&#034lng&#034)));
var marker = createMarker(point, name, address, type);
map.addOverlay(marker);
}
});

Создаем иконки для маркеров
Вы можете использовать класс GIcon для определения произваольных изображений, которые будут отображаться в качестве маркера. Для начала определим два объекта: iconBlue и iconRed.
Предупреждение: Вы можете и не определять столько свойств, сколько показано в примере, но, делая так, Вы рискуете столкнуться с различными ошибками позже.
Также можно создать ассоциативный массив, который будет связывать каждый объект GIcon с определенным типом заведения: рестораном или баром. Такой подход поможет Вам в дальнейшем легко разбираться с маркерами, созданными с использованием данных из внешнего XML-файла.
var iconBlue = new GIcon();
iconBlue.image = 'http://labs.google.com/ridefinder/images/mm_20_blue.png';
iconBlue.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
iconBlue.iconSize = new GSize(12, 20);
iconBlue.shadowSize = new GSize(22, 20);
iconBlue.iconAnchor = new GPoint(6, 20);
iconBlue.infoWindowAnchor = new GPoint(5, 1);

var iconRed = new GIcon();
iconRed.image = 'http://labs.google.com/ridefinder/images/mm_20_red.png';
iconRed.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
iconRed.iconSize = new GSize(12, 20);
iconRed.shadowSize = new GSize(22, 20);
iconRed.iconAnchor = new GPoint(6, 20);
iconRed.infoWindowAnchor = new GPoint(5, 1);

var customIcons = [];
customIcons[&#034restaurant&#034] = iconBlue;
customIcons[&#034bar&#034] = iconRed;

Создание маркеров и инфо-окон
Вы должны поместить весь код, который необходим для создания маркеров в функцию createMarker. Так как массив customIcons был определен глобально, то мы без помех можем передавать его элементы конструктору класса GMarker. Затем нужно написать HTML-код, который будет отображаться в инфо-окне.
Подсказка: некоторые уроки советуют Вам хранить информацию, отформатированную в виде HTML. Но это не есть хорошо, так как Вы не можете свободно манипулировать HTML-форматированием.
После написания отображаемого HTML-кода нужно добавить события для маркеров, чтобы при щелчке по маркеру появлялось инфо-окно.
function createMarker(point, name, address, type) {
var marker = new GMarker(point, customIcons[type]);
var html = &#034<b>&#034 + name + &#034</b> <br/>&#034 + address;
GEvent.addListener(marker, 'click', function() {
marker.openInfoWindowHtml(html);
});
return marker;
}

Собираем все в кучу
Ниже приведен код, который связывает все, что мы написали выше, в единое целое. Как только страница загружается – срабатывает функция загрузки карты load. Эта функция отображает карту, а затем вызывает метод GDownloadUrl. Удостоверьтесь, что функция GDownloadUrl правильно выполняет свою работу и XML-файл отображается в браузере корректно.
А вот и ссылка на готовый пример.
Счасливого Вам коддинга!
Tags:
Hubs:
+35
Comments 23
Comments Comments 23

Articles