Formát KML je XML soubor obsahující GPS data, která lze lehce importovat do aplikace Google Earth. Tyto soubory jsou exportovány ze spousty programů podporujících GPS. Rozšířením je pak formát KMZ, který je defacto ZIP soubor, ve kterém je kromě KML souboru i multimediální obsah a setkat se s ním můžete například u nových fotoaparátů s GPS.
V tomto návodu si ukážeme, jak lze KML a KMZ importovat do Visual PHP™ a zobrazit informace pomocí komponenty Google Map.
Formát souborů
Nejprve se podíváme na formát souboru KML. Tento soubor obsahuje značky, cesty a styly, kterými se mají zobrazit.
Výstupní soubor KML z fotoaparátu
<?xml version="1.0" encoding="UTF-8" ?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Document>
<Style id="Line_11_37">
<LineStyle>
<color>ffff0055</color>
<width>5</width>
</LineStyle>
</Style>
<Style id="POI_27_38">
<IconStyle>
<scale>0.7</scale>
<Icon>
<href>icon/push_to_log.png</href>
</Icon>
</IconStyle>
</Style>
<Placemark>
<name>Lat:50.505997, Lon:13.653536, Ele:259.422607</name>
<description>
<![CDATA[ 2010/6/24 15:52:9 <br /><br /><img src="photo/p2.jpg" /><br /><br /><img src="photo/p3.jpg" /><br /><br /><img src="photo/p1.jpg" /><br /> ]]>
</description>
<styleUrl>#POI_27_38</styleUrl>
<LookAt>
<longitude>13.653536</longitude>
<latitude>50.505997</latitude>
<range>6000</range>
<tilt>45</tilt>
<heading>0</heading>
</LookAt>
<Point>
<coordinates>13.653536,50.505997,259.422607</coordinates>
</Point>
</Placemark>
<Folder>
<name>Tracks</name>
<Placemark>
<name>Holux2010/06/24_15:51</name>
<styleUrl>#Line_11_37</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>13.653077,50.505863,264.000732 13.653094,50.505905,259.977295 13.653111,50.505947,261.289795 13.653087,50.505978,259.211670 13.653051,50.505981,257.078857 13.653046,50.505981,256.430420 13.653073,50.505989,256.891357 13.653146,50.506035,257.289795 13.653211,50.506084,256.899170 13.653281,50.506130,256.633545 13.653361,50.506104,257.000732 13.653444,50.506069,258.789795 13.653514,50.506027,259.633545 13.653528,50.505993,259.430420 13.653525,50.506001,259.571045 13.653531,50.505993,259.797607</coordinates>
</LineString>
</Placemark>
</Folder>
</Document>
</kml>Výstupní soubor KML z mobilní aplikace Run.GPS
<?xml version="1.0" encoding="UTF-8"?>
<kml creator="Run.GPS" xmlns="http://earth.google.com/kml/2.1">
<Document>
<name>run</name>
<Style id="trackStyle">
<LineStyle>
<color>d38b3a1b</color>
<width>4</width>
</LineStyle>
</Style>
<Placemark>
<name>run</name>
<styleUrl>#trackStyle</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>17.279413400,49.596376250,0.000000000 17.279422950,49.596364380,0.000000000 17.279430870,49.596398140,225.400004069 17.279400510,49.596390110,225.400004069 17.279409890,49.596403420,225.400004069 17.279422300,49.596401470,225.400004069 17.279446860,49.596418060,225.400004069 17.279502120,49.596442810,225.400004069 17.279505460,49.596458220,225.400004069 17.281490580,49.596821600,223.429515901
17.281523230,49.596823730,223.417749220 17.281546530,49.596831010,223.396781675 17.281582200,49.596826640,223.367749122 17.281606810,49.596804400,223.346781085 17.281647230,49.596798890,223.341942080 17.281681330,49.596785290,223.345167591 17.281700700,49.596773380,223.369361139 17.281717000,49.596783890,223.392069983 17.281748470,49.596761640,223.450800336 17.281792450,49.596747190,223.433339921
</coordinates>
</LineString>
</Placemark>
</Document>
</kml>Soubor KMZ je vlastně ZIP soubor, pouze s jinou příponou. Tento soubor obsahuje ikonky pro značky a případně fotky nebo videa. Struktura vypadá takto:
file.kmz
- [ icon ]
- agriculture.png
- airport.png
- arrow.png
- attraction.png
- bar.png
- ...
- [ photo ]
- p1.jpg
- p2.jpg
- p3.jpg
- p4.jpg
- p5.jpg
- ...
- track.kml
Adresář icon obsahuje ikonky pro značky na mapě a adresář photo potom fotografie z těchto míst. Kde se mají tyto obrázky zobrazit je definováno v souboru track.kml.
Tabulky databáze
Návrh tabulek databáze vypadá takto:
Tabulka kmz
V tabulce
kmz budou jednotlivé importy. V poli
name bude uložen název a v polích
latitude a
longitude pak souřadnice středu pro výchozí zobrazení mapy.
Tabulka kmz_placemarks
V každé mapě pro jednotlivé importy bude seznam míst, které se v mapě zobrazí pomocí značek. Těchto značek bude více, proto budou uloženy v tabulce
kmz_placemarks, která je detail tabulkou tabulky
kmz. Pole
name bude obsahovat název místa, v poli
icon bude importována ikonka pro tuto značku a konečně v polích
latitude a
longitude budou souřadnice. Vazba na master tabulku je realizována polem
parent.
Tabulka kmz_placemark_images
Protože každé místo může obsahovat více fotografií, bude tabulka
kmz_placemark_images detail tabulkou tabulky
kmz_placemarks. Pole
image pak bude obsahovat fotografii. Vazba na master tabulku je opět realizována polem
parent.
Tabulka kmz_paths
Import také může obsahovat trasu určenou seznamem GPS souřadnic. Proto tato data uložíme do tabulky
kmz_paths. Každý import a tedy zobrazení na 1 mapě může obsahovat více cest, proto je tato tabulka detail tabulkou tabulky
kmz. Vazba na master tabulku je realizována polem
parent.
Import souboru KMZ / KML
Skript, který si ukážeme, můžeme použít jak v administraci, tak i pro běžné návštěvníky na frondendu webu. Vytvoříme nový skript v sekci Prezentace -> Skripty a nastavíme mu tid=kmz_import. Samotný skript pak bude vypadat následovně:
echo "<h1>Import KMZ/KML</h1>";
function importPlacemark($PlacemarkNode)
{
global $kmzRecord, $styles, $tmpDir;
global $minLatitude, $maxLatitude, $minLongitude, $maxLongitude;
$styleId = $PlacemarkNode->getChildNodeByName("styleUrl")->getValue();
$styleId = substr($styleId, 1, strlen($styleId));
$LineStringNode = $PlacemarkNode->getChildNodeByName("LineString");
if ($LineStringNode)
{
$kmzPathRecord = array();
$kmzPathRecord["parent"] = $kmzRecord["id"];
$kmzPathRecord["name"] = $PlacemarkNode->getChildNodeByName("name")->getValue();
$kmzPathRecord["color"] = $styles[$styleId]["color"];
$kmzPathRecord["width"] = $styles[$styleId]["width"];
// extrahuji latitude a longitude (výšky v Google Map nevyužijeme - soubor je totiž určený pro 3D aplikaci Google Earth)
$coords = array();
$coordinates = $LineStringNode->getChildNodeByName("coordinates")->getValue();
$coordinates = explode(" ", $coordinates);
foreach($coordinates as $coordinate)
{
$coordinate = explode(",", $coordinate);
if ($coordinate[0] && $coordinate[1])
{
$latitude = trim($coordinate[1]);
$longitude = trim($coordinate[0]);
$minLatitude = min($minLatitude, $latitude);
$maxLatitude = max($maxLatitude, $latitude);
$minLongitude = min($minLongitude, $longitude);
$maxLongitude = max($maxLongitude, $longitude);
$coordinate = array(
"latitude" => $latitude,
"longitude" => $longitude,
);
$coords[] = $latitude.":".$longitude;
}
}
$kmzPathRecord["coordinates"] = implode("|", $coords);
getTable("kmz_paths")->insertRecord($kmzPathRecord);
}
else
{
$kmzPlacemarkRecord = array();
$kmzPlacemarkRecord["parent"] = $kmzRecord["id"];
$kmzPlacemarkRecord["name"] = $PlacemarkNode->getChildNodeByName("name")->getValue();
$LookAtNode = $PlacemarkNode->getChildNodeByName("LookAt");
if ($LookAtNode)
{
$kmzPlacemarkRecord["latitude"] = $LookAtNode->getChildNodeByName("latitude")->getValue();
$kmzPlacemarkRecord["longitude"] = $LookAtNode->getChildNodeByName("longitude")->getValue();
}
if ($styles[$styleId]["icon"])
$kmzPlacemarkRecord["icon"] = "file://".$tmpDir."/".$styles[$styleId]["icon"];
// uložím do databáze
$kmzPlacemarkRecord = getTable("kmz_placemarks")->insertRecord($kmzPlacemarkRecord);
// ziskam vsechny obrazky z popisu (jsou tam uloženy jako HTML kód)
$DescriptionNode = $PlacemarkNode->getChildNodeByName("description");
$description = $DescriptionNode->getValue();
if ($description)
{
if (preg_match_all("|src=\"([^\"]+)\"|ims", $description, $matches, PREG_SET_ORDER))
{
foreach($matches as $match)
{
$kmzPlacemarkImageRecord = array();
$kmzPlacemarkImageRecord["parent"] = $kmzPlacemarkRecord["id"];
$kmzPlacemarkImageRecord["image"] = "file://".$tmpDir."/".$match[1];
// uložím do databáze
getTable("kmz_placemark_images")->insertRecord($kmzPlacemarkImageRecord);
}
}
}
}
}
if ($formSent != "true")
{
echo "<form method='post'>";
echo "Název:<br />";
echo "<input type='text' name='kmzName' value='' /><br />";
echo "Soubor KMZ/KML:<br />";
$Component = getComponent("FILE", "kmzFile");
$Component->setParams("progress=true");
echo $Component->getCode()."<br />";
echo "<input type='submit' value='Importovat' />";
echo "<input type='hidden' name='formSent' value='true' />";
echo "</form>";
}
else
{
$minLatitude = 1000000;
$maxLatitude = 0;
$minLongitude = 1000000;
$maxLongitude = 0;
if (strtolower(getFileExt($kmzFile)) == "kmz")
{
// vytvořím pracovni adresář
$tmpDir = PROJECTPATH."repository/temp/kmz_".createUUID()."/";
_mkdir($tmpDir);
// rozbalím KMZ (je to de facto ZIP archív)
$Zip = createObject("Zip");
$Zip->open($kmzFile);
$Zip->extractTo($tmpDir);
// otevřu XML soubor
$XML = createObject("XML");
$XML->open($tmpDir."/track.kml");
}
else
{
// otevřu XML soubor
$XML = createObject("XML");
$XML->open($kmzFile);
}
$XMLDocument = $XML->documentElement->getChildNodeByName("Document");
// vytvořím nový master záznam v databázi
$kmzRecord = array(
"name" => $kmzName,
);
$kmzRecord = getTable("kmz")->insertRecord($kmzRecord);
// načtu všechny styly
$styles = array();
foreach($XMLDocument->getChildNodesByName("Style") as $ChildNode)
{
$style = array();
$styleId = $ChildNode->getAttribute("id");
$IconStyleNode = $ChildNode->getChildNodeByName("IconStyle");
if ($IconStyleNode)
{
$IconNode = $IconStyleNode->getChildNodeByName("Icon");
if ($IconNode)
{
$HrefNode = $IconNode->getChildNodeByName("href");
$style["icon"] = $HrefNode->getValue();
}
}
$LineStyleNode = $ChildNode->getChildNodeByName("LineStyle");
if ($LineStyleNode)
{
$ColorNode = $LineStyleNode->getChildNodeByName("color");
// barva je ve formatu AABBGGRR (alpha,blue,green,red)
$color = $ColorNode->getValue();
$style["color"] = "#".$color[6].$color[7].$color[4].$color[5].$color[2].$color[3];
$WidthNode = $LineStyleNode->getChildNodeByName("width");
$style["width"] = $WidthNode->getValue();
}
$styles[$styleId] = $style;
}
foreach($XMLDocument->getChildNodesByName("Placemark") as $PlacemarkNode)
{
importPlacemark($PlacemarkNode);
}
foreach($XMLDocument->getChildNodesByName("Folder") as $FolderNode)
{
foreach($FolderNode->getChildNodesByName("Placemark") as $PlacemarkNode)
{
importPlacemark($PlacemarkNode);
}
}
// spočítám střed mapy
$kmzRecord["latitude"] = $minLatitude+($maxLatitude-$minLatitude)/2;
$kmzRecord["longitude"] = $minLongitude+($maxLongitude-$minLongitude)/2;
getTable("kmz")->updateRecord($kmzRecord);
echo "Import byl dokončen";
}
Ve skriptu jsou použity objekty Zip pro rozbalení souboru s příponou kmz a objektu XML pro otevření a čtení KML souboru.
Spuštění importního skriptu
Abychom mohli tento skript v administraci vyvolat, přidáme do Prezentace -> Admin Menu novou položku s přímým odkazem:
scripts.php?tid=kmz_import
Na frondentu pak přehled importů uvidíte na této URL:
http://www.vase-domena.cz/kmz.php
Zdrojové kódy
Pro velmi rychlou implentaci tohoto tutoriálu máte k dispozici XML soubory, které můžete importovat do Vaší prezentace
Ukázkové KMZ a KML soubory
Pro odzkoušení jsme přidali ukázkové KMZ soubory a dokonce jsem si byl i zaběhat pro získání KML souborů :)
Ukázky výstupu map na www
 |
 |
 |
| run.gps.kml |
run.gps.2.kml |
knihovna.kmz |
 |
 |
|
| trasa1.kmz |
trasa2.kmz |
|