The KML format is an XML file containing GPS data that can be imported with ease into Google Earth. These files are exported from many programs that support GPS. Its extension is then the KMZ format that is de facto a ZIP file that contains multi-medium content in addition to a KML file and can be seen in case of new cameras with GPS, for example.
In these instructions we will show you how to import KML and KMZ into Visual PHP™ and display the information by means of the Google Map component.
File Formats
First we will look at the KML file format. This file contains marks, paths and styles in which they are to be displayed.
A camera output KML file
<?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>An output KML file from the Run.GPS mobile application
<?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>A KMZ file is in effect a ZIP file, with a different extension only. This file contains icons for marks and, if necessary, photographs or videos. The structure looks as follows:
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
The
icon directory contains icons for marks on a map and the
photo directory photographs from such places. Where these images are to be displayed is defined in the
track.kml file.
Database Tables
The database design looks as follows:
kmz Table
The
kmz table will contain individual imports. The name will be saved in the
name field and the centre coordinates for initial map displaying in the
latitude and
longitude fields.
kmz_placemarks Table
Every map for individual exports will have a list of places that are displayed on the map by means of marks. There will be more marks; therefore, they will be saved in the
kmz_placemarks table that is a detail table of the
kmz table. The
name field will contain the name of a place, the
icon field will contain the icon for this mark imported into it and finally the
latitude and
longitude fields will contain coordinates. The relation to the master table is ensured by the
parent field.
kmz_placemark_images Table
As each place may contain more photographs, the
kmz_placemark_images table will be a detail table of the
kmz_placemarks table. The
image field will then contain a photograph. The relation to the master table is also ensured by the
parent field.
kmz_paths Table
Any import may also contain a path defined by a GPS coordinate list. So we save this data to the
kmz_paths table. Every import and consequently a display on 1 map can contain more paths and that is why this table is a detail table of the
kmz table. The relation to the master table is ensured by the
parent field.
Importing a KMZ/KML File
The script we will show you can be used both in administration and for common visitors to the web front end. We will create a new script in the
Presentation -> Scripts section and set
tid=kmz_import for it. The script itself will then look as follows:
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"];
// I’m extracting the latitude and longitude (we do not make use of altitudes in Google Maps – the file is intended for the Google Earth 3D application)
$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"];
// I will save to the database
$kmzPlacemarkRecord = getTable("kmz_placemarks")->insertRecord($kmzPlacemarkRecord);
// I will get all images from the description (they are stored as an HTML code there)
$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];
// I will save to the database
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")
{
// I will create a working directory
$tmpDir = PROJECTPATH."repository/temp/kmz_".createUUID()."/";
_mkdir($tmpDir);
// I will extract KMZ (this is de facto a ZIP archive)
$Zip = createObject("Zip");
$Zip->open($kmzFile);
$Zip->extractTo($tmpDir);
// I will open an XML file
$XML = createObject("XML");
$XML->open($tmpDir."/track.kml");
}
else
{
// I will open an XML file
$XML = createObject("XML");
$XML->open($kmzFile);
}
$XMLDocument = $XML->documentElement->getChildNodeByName("Document");
// I will create a new master record in the database
$kmzRecord = array(
"name" => $kmzName,
);
$kmzRecord = getTable("kmz")->insertRecord($kmzRecord);
// I will upload all styles
$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");
// Colour is in the AABBGGRR format (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);
}
}
// I will calculate the centre of the map
$kmzRecord["latitude"] = $minLatitude+($maxLatitude-$minLatitude)/2;
$kmzRecord["longitude"] = $minLongitude+($maxLongitude-$minLongitude)/2;
getTable("kmz")->updateRecord($kmzRecord);
echo "Import byl dokončen";
}
Zip objects to expand a file with the
kmz extension and an XML object to open and read a KML file are used in the script.
Running an Import Script
To be able to call this script in administration, we will add to the
Presentation -> Admin Menu a new item with a direct link:
scripts.php?tid=kmz_import
The list of imports can then be seen on the following URL at the front end:
http://www.vase-domena.cz/kmz.php
Source Codes
To implement this tutorial very quickly, you have available XML files that you can import into your presentation
Sample KMZ and KML Files
We have added sample KMZ files for testing and I have even gone jogging to get KML files :).
Examples of Map Outputs on WWW
 |
 |
 |
| run.gps.kml |
run.gps.2.kml |
knihovna.kmz |
 |
 |
|
| trasa1.kmz |
trasa2.kmz |
|