* accepted parameters (case insensitive):
* - request = string - request type (OGC WFS like), can be kml (default), kmz, icon
* - map = string - path to mapfile
* - typename = string - (can be a csv list) - layer name(s)
* - filter = string - filter encoding
* - bbox = string - (csv) - bounding box csv
* - encoding = string - data and mapfile encoding, defaults to ISO-8859-1
*
*
*
*
* @author Alessandro Pasotti
* @copyright 2007 ItOpen.it - All rights reserved
* @package KMLMAPSERVER
This file is part of KMLMAPSERVER.
KMLMAPSERVER is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
KMLMAPSERVER is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with KMLMAPSERVER; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** Fix a GE bug for filled polygons */
define('TREAT_POLY_AS_LINE', true);
/** Enable cache */
define('ENABLE_CACHE', true);
if (!extension_loaded('MapScript'))
{
dl( 'php_mapscript.' . PHP_SHLIB_SUFFIX );
}
/**
* Main server class
*/
class LayerServer {
/** map file path */
var $map;
/** request */
var $request;
/** map instance */
var $map_object;
/** layer name(s) passed on the request */
var $typename;
/** array of requested layer objects (hash with layer name as key) */
var $layers;
/** filters */
var $filter;
/** bounding box */
var $bbox;
/** error messages */
var $errors;
/** send zipped data */
var $_zipped = false;
/** internal XML buffer */
var $_xml;
/** input projection */
var $in_proj;
/** output projection */
var $out_proj;
/** debug flag */
var $_debug = false;
/** end point */
var $endpoint;
/** custom style counter */
var $style_counter = 0;
/**
* Mapfile and data encoding encoding
* XMl output must be UTF-8, attributes and METADATA based strings
* must be converted to UTF-8, encoding defaults to ISO-8859-1, if
* your encoding is different, you can set it through CGI style parameters
*/
var $encoding;
/**
* send networklink
* wether folder should contain networklinks instead of real geometries
* it is automatically set when all layers are requested
*/
var $_networklink;
/**
* Initialize
*
*/
function LayerServer(){
$this->errors = array();
// Load request parameters
$this->get_request();
$this->style_counter = 0;
// Load map
if(!$this->has_error()) {
$this->load_map();
}
}
/**
* Run the server and sends data
* @return string or void
*/
function run(){
// Check cache
if(ENABLE_CACHE){
$cache_file = $this->get_cache_file_name();
if(file_exists($cache_file)){
// Check if is not expired
$layer = $this->map_object->getLayerByName($this->typename);
if(filectime($cache_file) + $layer->getMetadata('KML_CACHE') < (time())) {
error_log('removing cache ' . $cache_file);
//error_log('ctime : ' . filectime($cache_file) . ' , ' . time() . ' lm ' . $layer->getMetadata('KML_CACHE'));
@unlink($cache_file);
} else {
$this->send_header();
error_log('sending cache ' . $cache_file);
readfile($cache_file);
exit;
}
}
}
// If not layer are requested, send all as networklinks
if(!$this->typename){
$this->_networklink = true;
$this->typename = $this->get_layer_list();
} else {
$this->_networklink = false;
}
$this->_xml = new SimpleXMLElement('
";
return $style_id;
}
}
//print "get_shape_class($classitem) ".$values[$classitem]." no matches
";
return $style_id;
}
/**
* Add the style
* @return the style URL
*/
function add_style(&$layer, &$folder, $style_id, &$style_data){
// Calculare style URL
/*
if($style_data['description_template']){
$this->style_counter++;
$style_id .= '_'.$this->style_counter;
$balloon_data = $this->get_feature_description($attributes[$namecol], $attributes, $style_data['description_template']);
}
*/
// Check if the style already exists
$expr = '//*[@id=\''.$style_id.'\']';
if($folder->xpath($expr)) {
return $style_id;
}
$new_style =& $folder->addChild('Style');
$new_style['id'] = $style_id;
// Switch layer type
switch($layer->type){
case MS_LAYER_POINT:
$this->add_style_point($new_style, $style_data);
break;
case MS_LAYER_POLYGON:
$this->add_style_polygon($new_style, $style_data);
break;
case MS_LAYER_LINE:
$this->add_style_line($new_style, $style_data);
// Add KML_ADD_POINT icon
if($style_data['icon']){
$this->add_style_point($new_style, $style_data);
}
break;
}
return $style_id;
}
/**
* Add style for lines
*/
function add_style_line(&$new_style, &$style_data){
if($style_data['outlinecolor']->red != -1){
$st =& $new_style->addChild('LineStyle');
$st->addChild('color', sprintf('FF%02X%02X%02X', $style_data['outlinecolor']->blue, $style_data['outlinecolor']->green, $style_data['outlinecolor']->red));
if($width) {
$st->addChild('width', $width);
}
} elseif($style_data['color']->red != -1){
$st =& $new_style->addChild('LineStyle');
$st->addChild('color', sprintf('FF%02X%02X%02X', $style_data['color']->blue, $style_data['color']->green, $style_data['color']->red));
if($width) {
$st->addChild('width', $width);
}
}
}
/**
* Add style for points
*/
function add_style_point(&$new_style, &$style_data){
if($style_data['icon']){
$st =& $new_style->addChild('IconStyle');
if($style_data['width'] && $style_data['icon_width'] != 32){
$st->addChild('scale', $style_data['icon_width'] / 32);
}
$icon =& $st->addChild('Icon');
$icon->addChild('href', htmlentities($style_data['icon']));
}
/*/ Add the balloon style if description_template is set
if($style_data['description_template']){
$this->add_balloon_style($new_style, $balloon_data);
}
*/
// Label size and color
if($style_data['label_size'] || $style_data['label_color']){
$ls =& $new_style->addChild('LabelStyle');
if($style_data['label_size'] != -1 && $style_data['label_size'] != 32){
$ls->addChild('scale', $style_data['label_size'] / 32);
}
if($style_data['label_color']->red != -1){
$ls->addChild('color', sprintf('FF%02X%02X%02X', $style_data['label_color']->blue, $style_data['label_color']->green, $style_data['label_color']->red));
}
}
}
/**
* Add style for polygons
*/
function add_style_polygon(&$new_style, &$style_data){
// Get also outline styles
$this->add_style_line($new_style, $style_data);
$st =& $new_style->addChild('PolyStyle');
//die(print_r($backgroundcolor, true));
if($style_data['backgroundcolor']->red != -1){
$st->addChild('color', sprintf('FF%02X%02X%02X', $style_data['backgroundcolor']->blue, $style_data['backgroundcolor']->green, $style_data['backgroundcolor']->red));
$st->addChild('fill', 0);
} else {
$st->addChild('fill', 0);
}
$st->addChild('outline', 1);
}
/**
* Add a WMS raster link
*/
function add_wms_link(&$folder, &$layer, &$link){
// Build up the KML response document.
$icon =& $folder->addChild('Icon');
$icon->addChild('href', $link . 'layers=' . $layer->name);
//$icon->addChild('viewBoundScale', 1.5);
$icon->addChild('viewRefreshMode', 'onStop');
$llbox =& $folder->addChild('LatLonBox');
$ext = $this->map_object->extent;
$ext->project($this->in_proj, $this->out_proj);
$llbox->north = $ext->maxy;
$llbox->south = $ext->miny;
$llbox->east = $ext->maxx;
$llbox->west = $ext->minx;
// Reset original projection
$ext->project($this->out_proj, $this->in_proj);
}
/**
* Get the url for a point icon
*/
function get_icon_url($layer, $classname){
return $this->endpoint . '?service=icon&map=' . $this->map . '&typename=' . urlencode($layer->name) . '&classname=' . urlencode($classname);
}
/**
* Get the layer description
*/
function get_layer_description(&$layer){
$description = $layer->getMetadata('DESCRIPTION');
if(!$description){
$description = $layer->getMetadata('OWS_TITLE');
}
if(!$description){
$description = $layer->getMetadata('WFS_TITLE');
}
if(!$description){
$description = $layer->getMetadata('WMS_TITLE');
}
if(!$description){
$description = $layer->name;
}
return $description;
}
/**
* Add style for balloon
* @param string style XML id
* @param string column name for title
*/
function add_balloon_style(&$style, $balloon_data){
$balloon =& $style->addChild('BalloonStyle');
$balloon->addChild('text', htmlentities($balloon_data));
}
/**
* Get a request parameter
* @param string $name
* @param string $default parameter optional
* @return string the parameter value or empty string if null
*/
function load_parm($name, $default = ''){
if(!isset($_REQUEST[$name])) return $default;
$value = $_REQUEST[$name];
if(get_magic_quotes_gpc() != 1) $value = addslashes($value);
//$value = escapeshellcmd($value);
return $value;
}
/**
* Set error message
* @param string $message
* @param string $layer name
*/
function set_error($message, $layer = 'Error'){
$this->errors[$layer][] = $message;
}
/**
* Load the map and create the map instance
*/
function load_map(){
if(!file_exists($this->map) && is_readable($this->map)){
$this->set_error('Cannot read mapfile '. $this->map);
} else {
$this->map_object = ms_newMapObj($this->map);
if(!$this->map_object){
$this->set_error('Cannot load mapfile '. $this->map);
}
}
}
/**
* Test if has errors
* @return boolean
*/
function has_error(){
return count($this->errors) > 0;
}
/**
* Add error messages to folders TAGS
*/
function add_errors(){
foreach($this->errors as $layer => $errors){
$folder =& $this->_xml->Document->addChild('Folder');
$folder->addChild('name', $layer);
$folder->addChild('description', '
' . join("
\n", $errors) . "
"); } return $errorxml; } /** * Fetch XML and format it */ function get_kml(){ $doc = new DOMDocument('1.0'); $doc->formatOutput = true; $domnode = dom_import_simplexml($this->_xml); $domnode = $doc->importNode($domnode, true); $domnode = $doc->appendChild($domnode); return $doc->saveXML(); } /** * Send header */ function send_header(){ header('Content-type: application/vnd.google-earth.km'.($this->_zipped ? 'z' : 'l').'+XML'); } /** * Calculate cache file name */ function get_cache_file_name(){ return 'cache/'. md5($_SERVER['QUERY_STRING']) . ($this->_zipped ? '.kmz' : '.kml'); } /** * Send stream */ function send_stream($data){ $this->send_header(); // Compress data if($this->_zipped){ include("zip.class.php"); $ziper = new zipfile(); $ziper->addFile($data, 'doc.kml'); $data = $ziper->file(); } // Create cache if needed if(ENABLE_CACHE && count($this->layers) == 1 && $this->layers[$this->typename]->getMetadata('KML_CACHE')) { error_log( 'creating cache ' . $this->get_cache_file_name() ); file_put_contents($this->get_cache_file_name(), $data); } print $data; exit(); } } ?>