Commit 035d3cd4c2b6f64e01797b100d598958231023bd

Authored by Edmar Moretti
1 parent 0bd5f4eb

Adicionada a biblioteca kmlmapserver em pacotes

pacotes/kmlmapserver/LICENCE 0 → 100644
... ... @@ -0,0 +1,165 @@
  1 + GNU LESSER GENERAL PUBLIC LICENSE
  2 + Version 3, 29 June 2007
  3 +
  4 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
  5 + Everyone is permitted to copy and distribute verbatim copies
  6 + of this license document, but changing it is not allowed.
  7 +
  8 +
  9 + This version of the GNU Lesser General Public License incorporates
  10 +the terms and conditions of version 3 of the GNU General Public
  11 +License, supplemented by the additional permissions listed below.
  12 +
  13 + 0. Additional Definitions.
  14 +
  15 + As used herein, "this License" refers to version 3 of the GNU Lesser
  16 +General Public License, and the "GNU GPL" refers to version 3 of the GNU
  17 +General Public License.
  18 +
  19 + "The Library" refers to a covered work governed by this License,
  20 +other than an Application or a Combined Work as defined below.
  21 +
  22 + An "Application" is any work that makes use of an interface provided
  23 +by the Library, but which is not otherwise based on the Library.
  24 +Defining a subclass of a class defined by the Library is deemed a mode
  25 +of using an interface provided by the Library.
  26 +
  27 + A "Combined Work" is a work produced by combining or linking an
  28 +Application with the Library. The particular version of the Library
  29 +with which the Combined Work was made is also called the "Linked
  30 +Version".
  31 +
  32 + The "Minimal Corresponding Source" for a Combined Work means the
  33 +Corresponding Source for the Combined Work, excluding any source code
  34 +for portions of the Combined Work that, considered in isolation, are
  35 +based on the Application, and not on the Linked Version.
  36 +
  37 + The "Corresponding Application Code" for a Combined Work means the
  38 +object code and/or source code for the Application, including any data
  39 +and utility programs needed for reproducing the Combined Work from the
  40 +Application, but excluding the System Libraries of the Combined Work.
  41 +
  42 + 1. Exception to Section 3 of the GNU GPL.
  43 +
  44 + You may convey a covered work under sections 3 and 4 of this License
  45 +without being bound by section 3 of the GNU GPL.
  46 +
  47 + 2. Conveying Modified Versions.
  48 +
  49 + If you modify a copy of the Library, and, in your modifications, a
  50 +facility refers to a function or data to be supplied by an Application
  51 +that uses the facility (other than as an argument passed when the
  52 +facility is invoked), then you may convey a copy of the modified
  53 +version:
  54 +
  55 + a) under this License, provided that you make a good faith effort to
  56 + ensure that, in the event an Application does not supply the
  57 + function or data, the facility still operates, and performs
  58 + whatever part of its purpose remains meaningful, or
  59 +
  60 + b) under the GNU GPL, with none of the additional permissions of
  61 + this License applicable to that copy.
  62 +
  63 + 3. Object Code Incorporating Material from Library Header Files.
  64 +
  65 + The object code form of an Application may incorporate material from
  66 +a header file that is part of the Library. You may convey such object
  67 +code under terms of your choice, provided that, if the incorporated
  68 +material is not limited to numerical parameters, data structure
  69 +layouts and accessors, or small macros, inline functions and templates
  70 +(ten or fewer lines in length), you do both of the following:
  71 +
  72 + a) Give prominent notice with each copy of the object code that the
  73 + Library is used in it and that the Library and its use are
  74 + covered by this License.
  75 +
  76 + b) Accompany the object code with a copy of the GNU GPL and this license
  77 + document.
  78 +
  79 + 4. Combined Works.
  80 +
  81 + You may convey a Combined Work under terms of your choice that,
  82 +taken together, effectively do not restrict modification of the
  83 +portions of the Library contained in the Combined Work and reverse
  84 +engineering for debugging such modifications, if you also do each of
  85 +the following:
  86 +
  87 + a) Give prominent notice with each copy of the Combined Work that
  88 + the Library is used in it and that the Library and its use are
  89 + covered by this License.
  90 +
  91 + b) Accompany the Combined Work with a copy of the GNU GPL and this license
  92 + document.
  93 +
  94 + c) For a Combined Work that displays copyright notices during
  95 + execution, include the copyright notice for the Library among
  96 + these notices, as well as a reference directing the user to the
  97 + copies of the GNU GPL and this license document.
  98 +
  99 + d) Do one of the following:
  100 +
  101 + 0) Convey the Minimal Corresponding Source under the terms of this
  102 + License, and the Corresponding Application Code in a form
  103 + suitable for, and under terms that permit, the user to
  104 + recombine or relink the Application with a modified version of
  105 + the Linked Version to produce a modified Combined Work, in the
  106 + manner specified by section 6 of the GNU GPL for conveying
  107 + Corresponding Source.
  108 +
  109 + 1) Use a suitable shared library mechanism for linking with the
  110 + Library. A suitable mechanism is one that (a) uses at run time
  111 + a copy of the Library already present on the user's computer
  112 + system, and (b) will operate properly with a modified version
  113 + of the Library that is interface-compatible with the Linked
  114 + Version.
  115 +
  116 + e) Provide Installation Information, but only if you would otherwise
  117 + be required to provide such information under section 6 of the
  118 + GNU GPL, and only to the extent that such information is
  119 + necessary to install and execute a modified version of the
  120 + Combined Work produced by recombining or relinking the
  121 + Application with a modified version of the Linked Version. (If
  122 + you use option 4d0, the Installation Information must accompany
  123 + the Minimal Corresponding Source and Corresponding Application
  124 + Code. If you use option 4d1, you must provide the Installation
  125 + Information in the manner specified by section 6 of the GNU GPL
  126 + for conveying Corresponding Source.)
  127 +
  128 + 5. Combined Libraries.
  129 +
  130 + You may place library facilities that are a work based on the
  131 +Library side by side in a single library together with other library
  132 +facilities that are not Applications and are not covered by this
  133 +License, and convey such a combined library under terms of your
  134 +choice, if you do both of the following:
  135 +
  136 + a) Accompany the combined library with a copy of the same work based
  137 + on the Library, uncombined with any other library facilities,
  138 + conveyed under the terms of this License.
  139 +
  140 + b) Give prominent notice with the combined library that part of it
  141 + is a work based on the Library, and explaining where to find the
  142 + accompanying uncombined form of the same work.
  143 +
  144 + 6. Revised Versions of the GNU Lesser General Public License.
  145 +
  146 + The Free Software Foundation may publish revised and/or new versions
  147 +of the GNU Lesser General Public License from time to time. Such new
  148 +versions will be similar in spirit to the present version, but may
  149 +differ in detail to address new problems or concerns.
  150 +
  151 + Each version is given a distinguishing version number. If the
  152 +Library as you received it specifies that a certain numbered version
  153 +of the GNU Lesser General Public License "or any later version"
  154 +applies to it, you have the option of following the terms and
  155 +conditions either of that published version or of any later version
  156 +published by the Free Software Foundation. If the Library as you
  157 +received it does not specify a version number of the GNU Lesser
  158 +General Public License, you may choose any version of the GNU Lesser
  159 +General Public License ever published by the Free Software Foundation.
  160 +
  161 + If the Library as you received it specifies that a proxy can decide
  162 +whether future versions of the GNU Lesser General Public License shall
  163 +apply, that proxy's public statement of acceptance of any version is
  164 +permanent authorization for you to choose that version for the
  165 +Library.
... ...
pacotes/kmlmapserver/README 0 → 100644
... ... @@ -0,0 +1,92 @@
  1 +KML mapserver wrapper
  2 +-------------------------------------
  3 +
  4 +* What is this thing?
  5 + this is a wrapper around UNM Mapserver, to serve KML data in a WFS-like manner
  6 +
  7 +* Requirements
  8 + PHP5 with simplexml
  9 +
  10 +* Configuration
  11 + Configuration is done through CGI-style calls and through some optional metadata in the mapfile
  12 +
  13 + METADATA:
  14 + RESULT_FIELDS # from which field take the name for the feature
  15 + # defaults to the first field
  16 +
  17 + DESCRIPTION_TEMPLATE # if present, this is used for placemark features
  18 + # tooltip. Parameters surrounded by "%" char are substituted
  19 + # with real values from the corresponding field for the feature
  20 +
  21 + DESCRIPTION # All those metadata are searched (in this order) to get a layer
  22 + OWS_TITLE # description
  23 + WFS_TITLE
  24 + WMS_TITLE
  25 +
  26 + KML_CACHE # number of second the cache will lasts
  27 + # if empty or not exists, the cache will be disabled for that layer
  28 +
  29 + KML_SKIP # if equals to "true", kml output is disabled for this layer,
  30 + # default is false
  31 +
  32 + KML_ADD_POINT # If not empty, add a point with balloon to start and end
  33 + # line geometries. Value is the icon url.
  34 +
  35 +
  36 + CGI-PARAMETERS:
  37 + * - request = string - optional - request type (OGC WFS like)
  38 + * - map = string - required - path to mapfile
  39 + * - typename = string - optional - (can be a csv list) - layer name(s), if empty, all layers are returned
  40 + * - filter = string - optional - filter encoding (single layer requests only)
  41 + * - bbox = string - optional - standard bbox specification (Not yet implemented)
  42 + * - encoding = string - optional - default to ISO-8859-1
  43 +
  44 +* Filters
  45 + Only PropertyIsEqualTo and PropertyIsLike are supported ATM.
  46 +
  47 +* Encoding
  48 + kml is UTF-8, mapfile and attributes could have other encodings, you can set encoding via request parameter, otherwise ISO-8859-1 is used as default.
  49 +
  50 +* Raster support
  51 + Raster layer are supported as standard WMS network links, it is necessary to add EPSG:4326 to WMS_SRS metadata on all mapfile layers.
  52 + Mapfile must be correctly configured as WMS server (i.e. all required metadata must be set).
  53 +
  54 +* KMZ compressed output
  55 +
  56 +* Styles and classes
  57 + There is limited support for classes and style:
  58 + * only one style for each class is parsed, if you have multiple styles in one class, the values of the last one are used
  59 + * only color, outlinecolor, backgroundcolor, symbol, size and width are parsed
  60 +
  61 +* Cache
  62 + A simple caching for single layer requests is available.
  63 + If you want to use the cache, set KML_CACHE layer metadata to the number of seconds the cache should last.
  64 + A web server writeable "cache" directory must exists at the same level of the main script
  65 +
  66 +* Know issues
  67 + * Filled polygons fail to wrap on the mountains (this seems a GE bug), a define('TREAT_POLY_AS_LINE', true) control this behaviour
  68 +
  69 +EXAMPLE CALLS
  70 +------------------------------------
  71 +Single layer:
  72 +http://localhost/kmlserver/service.php?map=/map/mapfile-ogc.map&typename=sfumo,vngeo_ospitalita
  73 +
  74 +Two layers (one raster and one vector):
  75 +http://localhost/kmlserver/service.php?map=/map/mapfile-ogc.map&typename=vngeo_ospitalita
  76 +
  77 +All layers as network links:
  78 +http://localhost/kmlserver/service.php?map=/map/mapfile-ogc.map
  79 +
  80 +Single layer with filter:
  81 +http://localhost/kmlserver/service.php?map=/map/mapfile-ogc.map&typename=comuni&filter=<Filter><PropertyIsLike><PropertyName>toponimo</PropertyName><Literal>Riederalp</Literal></PropertyIsLike></Filter>
  82 +
  83 +
  84 +ICON SERVER
  85 +-------------------------------------
  86 +Returns a PNG icon for a give poin layer/class combination
  87 +Example calls:
  88 +http://localhost/kmlserver/symbolservice.php?map=/map/mapfile-ogc.map&typename=vngeo_ospitalita&class=Alberghi
  89 +
  90 +If you want transparent icons, set PNG output format to RGBA and IMAGECOLOR to the transparent color
  91 +
  92 +
... ...
pacotes/kmlmapserver/cache/index.html 0 → 100644
pacotes/kmlmapserver/classes/kmlserver.class.php 0 → 100644
... ... @@ -0,0 +1,102 @@
  1 +<?php
  2 +/**
  3 +* Mapserver wrapper to KML/KMZ data
  4 +*
  5 +* Returns KML or KMZ representation of common OGC requests
  6 +*
  7 +* <pre>
  8 +* accepted parameters (case insensitive):
  9 +* - request = string - request type (OGC WFS like), can be kml (default), kmz, icon
  10 +* - map = string - path to mapfile
  11 +* - typename = string - (can be a csv list) - layer name(s)
  12 +* - filter = string - filter encoding
  13 +* - bbox = string - (csv) - bounding box csv
  14 +*
  15 +*
  16 +* </pre>
  17 +*
  18 +* @author Alessandro Pasotti
  19 +* @copyright 2007 ItOpen.it - All rights reserved
  20 +* @package KMLMAPSERVER
  21 +
  22 +This file is part of KMLMAPSERVER.
  23 +
  24 + KMLMAPSERVER is free software; you can redistribute it and/or modify
  25 + it under the terms of the GNU Lesser General Public License as published by
  26 + the Free Software Foundation; either version 3 of the License, or
  27 + (at your option) any later version.
  28 +
  29 + KMLMAPSERVER is distributed in the hope that it will be useful,
  30 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  31 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  32 + GNU Lesser General Public License for more details.
  33 +
  34 + You should have received a copy of the GNU Lesser General Public License
  35 + along with KMLMAPSERVER; if not, write to the Free Software
  36 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  37 +
  38 +*/
  39 +
  40 +
  41 +if (!extension_loaded('MapScript'))
  42 +{
  43 + dl( 'php_mapscript.' . PHP_SHLIB_SUFFIX );
  44 +}
  45 +
  46 +
  47 +/**
  48 +* Main server class, wraps real kml or icon servers
  49 +*/
  50 +
  51 +class KmlServer {
  52 +
  53 + /** server instance */
  54 + var $service;
  55 +
  56 + /** request */
  57 + var $request;
  58 +
  59 + /** debug flag */
  60 + var $_debug = false;
  61 +
  62 + /**
  63 + * Initialize
  64 + *
  65 + */
  66 + function KmlServer(){
  67 + $this->get_request();
  68 + if($this->service == 'icon'){
  69 + include 'symbolserver.class.php';
  70 + $this->service = new SymbolServer();
  71 + $this->service->run();
  72 + } else {
  73 + include 'layerserver.class.php';
  74 + $this->service = new LayerServer();
  75 + $this->service->run();
  76 + }
  77 + }
  78 +
  79 + /**
  80 + * Get all request parameters
  81 + */
  82 + function get_request(){
  83 + $this->service = $this->load_parm('service');
  84 + if(!$this->service){
  85 + $this->service= 'kml';
  86 + }
  87 + }
  88 +
  89 + /**
  90 + * Get a request parameter
  91 + * @param string $name
  92 + * @return string the parameter value or empty string if null
  93 + */
  94 + function load_parm($name){
  95 + if(!isset($_REQUEST[$name])) return '';
  96 + $value = $_REQUEST[$name];
  97 + if(get_magic_quotes_gpc() != 1) $value = addslashes($value);
  98 + //$value = escapeshellcmd($value);
  99 + return $value;
  100 + }
  101 +}
  102 +?>
0 103 \ No newline at end of file
... ...
pacotes/kmlmapserver/classes/layerserver.class.php 0 → 100644
... ... @@ -0,0 +1,908 @@
  1 +<?php
  2 +/**
  3 +* Mapserver wrapper to KML/KMZ data
  4 +*
  5 +* Returns KML or KMZ representation of common OGC requests
  6 +*
  7 +* <pre>
  8 +* accepted parameters (case insensitive):
  9 +* - request = string - request type (OGC WFS like), can be kml (default), kmz, icon
  10 +* - map = string - path to mapfile
  11 +* - typename = string - (can be a csv list) - layer name(s)
  12 +* - filter = string - filter encoding
  13 +* - bbox = string - (csv) - bounding box csv
  14 +* - encoding = string - data and mapfile encoding, defaults to ISO-8859-1
  15 +*
  16 +*
  17 +* </pre>
  18 +*
  19 +* @author Alessandro Pasotti
  20 +* @copyright 2007 ItOpen.it - All rights reserved
  21 +* @package KMLMAPSERVER
  22 +
  23 +This file is part of KMLMAPSERVER.
  24 +
  25 + KMLMAPSERVER is free software; you can redistribute it and/or modify
  26 + it under the terms of the GNU Lesser General Public License as published by
  27 + the Free Software Foundation; either version 3 of the License, or
  28 + (at your option) any later version.
  29 +
  30 + KMLMAPSERVER is distributed in the hope that it will be useful,
  31 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  32 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  33 + GNU Lesser General Public License for more details.
  34 +
  35 + You should have received a copy of the GNU Lesser General Public License
  36 + along with KMLMAPSERVER; if not, write to the Free Software
  37 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  38 +
  39 +*/
  40 +
  41 +
  42 +/** Fix a GE bug for filled polygons */
  43 +define('TREAT_POLY_AS_LINE', true);
  44 +
  45 +/** Enable cache */
  46 +define('ENABLE_CACHE', true);
  47 +
  48 +if (!extension_loaded('MapScript'))
  49 +{
  50 + dl( 'php_mapscript.' . PHP_SHLIB_SUFFIX );
  51 +}
  52 +
  53 +
  54 +/**
  55 +* Main server class
  56 +*/
  57 +
  58 +class LayerServer {
  59 +
  60 + /** map file path */
  61 + var $map;
  62 +
  63 + /** request */
  64 + var $request;
  65 +
  66 + /** map instance */
  67 + var $map_object;
  68 +
  69 + /** layer name(s) passed on the request */
  70 + var $typename;
  71 +
  72 + /** array of requested layer objects (hash with layer name as key) */
  73 + var $layers;
  74 +
  75 + /** filters */
  76 + var $filter;
  77 +
  78 + /** bounding box */
  79 + var $bbox;
  80 +
  81 + /** error messages */
  82 + var $errors;
  83 +
  84 + /** send zipped data */
  85 + var $_zipped = false;
  86 +
  87 + /** internal XML buffer */
  88 + var $_xml;
  89 +
  90 + /** input projection */
  91 + var $in_proj;
  92 +
  93 + /** output projection */
  94 + var $out_proj;
  95 +
  96 + /** debug flag */
  97 + var $_debug = false;
  98 +
  99 + /** end point */
  100 + var $endpoint;
  101 +
  102 + /** custom style counter */
  103 + var $style_counter = 0;
  104 +
  105 + /**
  106 + * Mapfile and data encoding encoding
  107 + * XMl output must be UTF-8, attributes and METADATA based strings
  108 + * must be converted to UTF-8, encoding defaults to ISO-8859-1, if
  109 + * your encoding is different, you can set it through CGI style parameters
  110 + */
  111 + var $encoding;
  112 +
  113 + /**
  114 + * send networklink
  115 + * wether folder should contain networklinks instead of real geometries
  116 + * it is automatically set when all layers are requested
  117 + */
  118 + var $_networklink;
  119 +
  120 +
  121 + /**
  122 + * Initialize
  123 + *
  124 + */
  125 + function LayerServer(){
  126 + $this->errors = array();
  127 + // Load request parameters
  128 + $this->get_request();
  129 +
  130 + $this->style_counter = 0;
  131 +
  132 + // Load map
  133 + if(!$this->has_error()) {
  134 + $this->load_map();
  135 + }
  136 +
  137 + }
  138 +
  139 + /**
  140 + * Run the server and sends data
  141 + * @return string or void
  142 + */
  143 + function run(){
  144 + // Check cache
  145 + if(ENABLE_CACHE){
  146 + $cache_file = $this->get_cache_file_name();
  147 + if(file_exists($cache_file)){
  148 + // Check if is not expired
  149 + $layer = $this->map_object->getLayerByName($this->typename);
  150 + if(filectime($cache_file) + $layer->getMetadata('KML_CACHE') < (time())) {
  151 + error_log('removing cache ' . $cache_file);
  152 + //error_log('ctime : ' . filectime($cache_file) . ' , ' . time() . ' lm ' . $layer->getMetadata('KML_CACHE'));
  153 + @unlink($cache_file);
  154 + } else {
  155 + $this->send_header();
  156 + error_log('sending cache ' . $cache_file);
  157 + readfile($cache_file);
  158 + exit;
  159 + }
  160 + }
  161 + }
  162 +
  163 + // If not layer are requested, send all as networklinks
  164 + if(!$this->typename){
  165 + $this->_networklink = true;
  166 + $this->typename = $this->get_layer_list();
  167 + } else {
  168 + $this->_networklink = false;
  169 + }
  170 +
  171 + $this->_xml = new SimpleXMLElement('<kml xmlns="http://earth.google.com/kml/2.0"><Document ></Document></kml>');
  172 + // Prepare projection
  173 + $this->in_proj = ms_newProjectionObj($this->map_object->getProjection());
  174 + // Set projection to GOOGLE earth's projection
  175 + $this->out_proj = ms_newProjectionObj("init=epsg:4326");
  176 + // Set endpoint
  177 + //die($_SERVER['REQUEST_URI']);
  178 + $this->endpoint = ($_SERVER['HTTPS'] ? 'https' : 'http') . '://'.$_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] ? ':'.$_SERVER['SERVER_PORT'] : '') . $_SERVER['PHP_SELF'];
  179 +
  180 +
  181 + // Process request
  182 + if(!$this->has_error()) {
  183 + $this->process_request();
  184 + }
  185 + if($this->has_error()){
  186 + $this->add_errors();
  187 + }
  188 + return $this->send_stream($this->get_kml());
  189 + }
  190 +
  191 + /**
  192 + * Set debug flag
  193 + * @param boolean $value
  194 + */
  195 + function set_debug($value){
  196 + $this->_debug = $value;
  197 + }
  198 +
  199 + /**
  200 + * Get all request parameters
  201 + */
  202 + function get_request(){
  203 + $this->map = $this->load_parm('map');
  204 + $this->bbox = $this->load_parm('bbox');
  205 + $this->filter = $this->load_parm('filter');
  206 + $this->typename = $this->load_parm('typename');
  207 + $this->encoding = $this->load_parm('encoding', 'ISO-8859-1');
  208 + $this->request = $this->load_parm('request', 'kml');
  209 +
  210 + if($this->request == 'kmz') {
  211 + $this->_zipped = true;
  212 + }
  213 +
  214 + if(!$this->map){
  215 + $this->set_error('No mapfile specified');
  216 + }
  217 + }
  218 +
  219 + /**
  220 + * Apply filter
  221 + * @return array
  222 + */
  223 + function apply_filter(&$layer, &$filter){
  224 + if($layer->connectiontype == MS_POSTGIS){
  225 + if($filter->PropertyIsEqualTo){
  226 + $searchstring = '"'.$filter->PropertyIsEqualTo->PropertyName . ' = ' . '\''.addslashes($filter->PropertyIsEqualTo->Literal).'\''.'"';
  227 + $searchfield = $filter->PropertyIsEqualTo->PropertyName;
  228 + } elseif($filter->PropertyIsLike){
  229 + $searchfield = $filter->PropertyIsLike->PropertyName;
  230 + $searchstring ='"'.$filter->PropertyIsLike->PropertyName . ' LIKE \'%' . addslashes($filter->PropertyIsLike->Literal) . '%\''.'"';
  231 + }
  232 + } elseif($layer->connectiontype == MS_SHAPEFILE || $layer->connectiontype == MS_OGR){
  233 + if($filter->PropertyIsEqualTo){
  234 + $searchstring = $filter->PropertyIsEqualTo->Literal;
  235 + $searchfield = $filter->PropertyIsEqualTo->PropertyName;
  236 + } elseif($filter->PropertyIsLike){
  237 + $searchstring = $filter->PropertyIsLike->Literal;
  238 + $searchfield = $filter->PropertyIsLike->PropertyName;
  239 + }
  240 + }
  241 + return array($searchfield, $searchstring);
  242 + }
  243 +
  244 + /**
  245 + * Process request
  246 + */
  247 + function process_request(){
  248 + // Get layer(s)
  249 + $layers = split(',', $this->typename);
  250 + if($this->_networklink){
  251 + foreach($layers as $layer){
  252 + $this->add_networklink($layer);
  253 + }
  254 + } else {
  255 + foreach($layers as $layer){
  256 + $this->process_layer_request($layer);
  257 + }
  258 + }
  259 + }
  260 +
  261 + /**
  262 + * Add a networklink
  263 + */
  264 + function add_networklink(&$layer_name){
  265 + $nl =& $this->_xml->Document->addChild('NetworkLink');
  266 +
  267 + $layer = @$this->map_object->getLayerByName($layer_name);
  268 + $nl->addChild('name', $this->get_layer_description($layer));
  269 + $nl->addChild('visibility', 0);
  270 + $link =& $nl->addChild('Link');
  271 + $link->addChild('href', $this->endpoint . '?map=' . $this->map . '&amp;typename=' . urlencode($layer_name) . '&amp;request=' . ($this->_zipped ? 'kmz' : 'kml'));
  272 + }
  273 +
  274 +
  275 + /**
  276 + * Process a single layer
  277 + * @return boolean false on error
  278 + */
  279 + function process_layer_request(&$layer_name){
  280 +
  281 + $layer = @$this->map_object->getLayerByName($layer_name);
  282 +
  283 + if(!$layer){
  284 + $this->set_error('Layer not found ' . $layer_name, $layer_name);
  285 + return false;
  286 + }
  287 +
  288 + // Add to layer list
  289 + $this->layers[$layer_name] =& $layer;
  290 +
  291 + // Get custom template if any
  292 + $description_template = $layer->getMetadata('DESCRIPTION_TEMPLATE');
  293 +
  294 + // Set on
  295 + $layer->set( 'status', MS_ON );
  296 +
  297 + // Set kml title from layer description (default to layer name)
  298 + $layer_desc = $this->get_layer_description($layer);
  299 +
  300 + // Now switch raster layers
  301 + //var_dump($layer->type == MS_LAYER_RASTER);
  302 + if($layer->type == MS_LAYER_RASTER){
  303 + // Check if wms_onlineresource metadata is set
  304 + $wms_link = $this->map_object->getMetadata('wms_onlineresource');
  305 + if(!$wms_link){
  306 + $wms_link = $this->map_object->getMetadata('ows_onlineresource');
  307 + }
  308 + if(!$wms_link){
  309 + $this->set_error('No WMS server available for ' . $layer_name, $layer_name);
  310 + return false;
  311 + }
  312 + // Add parameters to OGC server call
  313 + // Fix &
  314 + $wms_link = preg_replace('/&/', '&amp;', $wms_link);
  315 + $wms_link .= 'VERSION=1.1.1&amp;REQUEST=GetMap&amp;SRS=EPSG:4326&amp;STYLES=&amp;BGCOLOR=0xFFFFFF&amp;FORMAT=image/png&amp;TRANSPARENT=TRUE&amp;';
  316 + // Link ok, create folder
  317 + $folder =& $this->_xml->Document->addChild('GroundOverlay');
  318 + $folder->addChild('description', $this->get_layer_description($layer));
  319 + $folder->addChild('name', $layer_desc);
  320 + $this->add_wms_link($folder, $layer, $wms_link);
  321 + } else {
  322 +
  323 + // Apply filter
  324 + if($this->filter){
  325 + // Try loading as XML
  326 + try {
  327 + $filter = @new SimpleXMLElement($this->filter);
  328 + list($searchfield, $searchstring) = $this->apply_filter($layer, $filter);
  329 + if(! ($searchfield && $searchstring)){
  330 + $this->set_error('Error parsing filter', $layer_name);
  331 + return false;
  332 + }
  333 + } catch (Exception $e) {
  334 + $this->set_error('Wrong XML filter', $layer_name);
  335 + $this->filter = null;
  336 + return false;
  337 + }
  338 + }
  339 +
  340 + // Get results
  341 + if(MS_SUCCESS == $layer->open()){
  342 + // Search which column to use to identify the feature
  343 + $namecol = $layer->getMetadata('RESULT_FIELDS');
  344 + if(!$namecol){
  345 + $cols = array_values($layer->getItems());
  346 + $namecol = $cols[0];
  347 + }
  348 + // Add classes
  349 + $folder =& $this->_xml->Document->addChild('Folder');
  350 + $class_list = $this->parse_classes($layer, $folder, $namecol, $title_field, $description_template);
  351 +
  352 + //die(print_r($class_list, true));
  353 + $folder->addChild('description', $this->get_layer_description($layer));
  354 + $folder->addChild('name', $layer_desc);
  355 +
  356 + //print("$searchfield && $searchstring");
  357 + if($searchfield && $searchstring){
  358 + if(@$layer->queryByAttributes($searchfield, $searchstring, MS_MULTIPLE) == MS_SUCCESS){
  359 + $layer->open();
  360 + //var_dump($layer->getItems()); die();
  361 + for ($j=0; $j < $layer->getNumResults(); $j++)
  362 + {
  363 + // get next shape row
  364 + $result = $layer->getResult($j);
  365 + $shape = $layer->getShape($result->tileindex, $result->shapeindex);
  366 + $this->process_shape($layer, $shape, $class_list, $folder, $namecol);
  367 + // end for loop
  368 + }
  369 + } else {
  370 + $this->set_error('Query returned no data', $layer_name);
  371 + return false;
  372 + }
  373 + } else { // Get all shapes
  374 + $status = $layer->whichShapes($this->map_object->extent);
  375 + while ($shape = $layer->nextShape()) {
  376 + $this->process_shape($layer, $shape, $class_list, $folder,$namecol );
  377 + }
  378 + }
  379 + $layer->close();
  380 + } else {
  381 + $this->set_error('Layer cannot be opened', $layer_name);
  382 + return false;
  383 + }
  384 + }
  385 + return true;
  386 + }
  387 +
  388 + /**
  389 + * Process the shape
  390 + */
  391 + function process_shape(&$layer, &$shape, &$class_list, &$folder, &$namecol){
  392 + $shape->project($this->in_proj, $this->out_proj);
  393 + // Assign style
  394 + if($layer->classitem){
  395 + $style_id = $this->get_shape_class($layer->classitem, $shape->values, $class_list);
  396 + }
  397 + if(!$style_id){
  398 + // Get first class
  399 + $class_keys = array_keys($class_list);
  400 + $style_id = $class_keys[0];
  401 + }
  402 + // Add the feature
  403 + if(array_key_exists('folder', $class_list[$style_id])) {
  404 + $feature_folder =& $class_list[$style_id]['folder'];
  405 + } else {
  406 + //die('missing folder for ' . $style_id);
  407 + $feature_folder =& $folder;
  408 + }
  409 + if(!is_object($feature_folder)){
  410 + $folder_name = $feature_folder;
  411 + $feature_folder =& $folder ->addChild('Folder');
  412 + $feature_folder->addChild('name', $folder_name);
  413 + }
  414 + // Add style class
  415 + $style_url =& $this->add_style($layer, $feature_folder, $style_id, $class_list[$style_id], $namecol, $shape->values);
  416 +
  417 + $wkt = $shape->toWkt();
  418 + $placemark =& $this->add_feature($feature_folder, $wkt, $shape->values[$namecol], $shape->values, $description_template, $class_list[$style_id]);
  419 +
  420 + $placemark->addChild('styleUrl', '#'. $style_url);
  421 +
  422 + }
  423 +
  424 + /**
  425 + * Add the feature to the result set
  426 + * @return reference to placemark object
  427 + */
  428 + function &add_feature(&$folder, &$wkt, $featurename, $attributes, $description_template, $style_data){
  429 + $pm = $folder->addChild('Placemark');
  430 + //if($featurename == 'VERCELLI') {var_dump($wkt); die();}
  431 + $pm->addChild('name', iconv($this->encoding, 'utf-8', $featurename));
  432 + $pm->addChild('description', $this->get_feature_description($featurename, $attributes, $description_template));
  433 + // Now parse the wkt
  434 + if(strpos($wkt, 'MULTILINESTRING') !== false){
  435 + $this->add_multilinestring($wkt, $pm, $featurename, $style_data['icon']);
  436 + } elseif(strpos($wkt, 'LINESTRING') !== false){
  437 + $this->add_linestring($wkt, $pm, $featurename, $style_data['icon']);
  438 + } elseif(strpos($wkt, 'POINT') !== false){
  439 + $this->add_point($wkt, $pm, $featurename);
  440 + } elseif(strpos($wkt, 'MULTIPOLYGON') !== false){
  441 + if(TREAT_POLY_AS_LINE){
  442 + $ml = $pm->addChild('MultiGeometry');
  443 + foreach(split('\), \(', $wkt) as $line){
  444 + $this->add_multilinestring($line, $ml, $featurename );
  445 + }
  446 + } else {
  447 + $this->add_multipolygon($wkt, $pm, $featurename);
  448 + }
  449 + } elseif(strpos($wkt, 'POLYGON') !== false){
  450 + if(TREAT_POLY_AS_LINE){
  451 + $this->add_multilinestring($wkt, $pm, $featurename);
  452 + } else {
  453 + $this->add_polygon($wkt, $pm, $featurename);
  454 + }
  455 + } else {
  456 + // Error?
  457 + }
  458 + return $pm;
  459 + }
  460 +
  461 + /**
  462 + * Add a linestring
  463 + */
  464 + function add_linestring(&$wkt, &$element, $featurename, $add_points){
  465 + preg_match('/(\d+[^\(\)]*\d)/', $wkt, $data);
  466 + $data = str_replace(', ', '#', $data[1]);
  467 + $data = str_replace(' ', ',', $data);
  468 + $data = str_replace('#', ' ', $data);
  469 + if($add_points){
  470 + preg_match('/^(\d+\.\d+,\d+\.\d+).*(\d+\.\d+,\d+\.\d+)$/', $data, $points);
  471 + if(count($points) == 3){
  472 + $mg = $element->addChild('MultiGeometry');
  473 + $ls = $mg->addChild('LineString');
  474 + $pt1 = $mg->addChild('Point');
  475 + $pt1->addChild('coordinates', $points[1]);
  476 + $pt2 = $mg->addChild('Point');
  477 + $pt2->addChild('coordinates', $points[2]);
  478 + } else {
  479 + die('errore');
  480 + $ls = $element->addChild('LineString');
  481 + }
  482 + //print_r($points);die();
  483 + } else {
  484 + $ls = $element->addChild('LineString');
  485 + }
  486 + $ls->addChild('coordinates', $data);
  487 + }
  488 +
  489 + /**
  490 + * Add a multilinestring
  491 + */
  492 + function add_multilinestring(&$wkt, &$element, $featurename, $add_points){
  493 + $ml = $element->addChild('MultiGeometry');
  494 + foreach(split('\), \(', $wkt) as $line){
  495 + $this->add_linestring($line, $ml, $featurename, $add_points );
  496 + }
  497 + }
  498 +
  499 + /**
  500 + * Add a point
  501 + */
  502 + function add_point(&$wkt, &$element, $featurename){
  503 + $pt = $element->addChild('Point');
  504 + preg_match('/(\d\.?\d+\s\d+\.?\d+)/', $wkt, $data);
  505 + $data = str_replace(' ', ',', $data[1]);
  506 + $pt->addChild('coordinates', $data);
  507 + }
  508 +
  509 +
  510 + /**
  511 + * Add a polygon
  512 + */
  513 + function add_polygon(&$wkt, &$element, $featurename){
  514 + $ml = $element->addChild('Polygon');
  515 + foreach(split('\), \(', $wkt) as $line){
  516 + preg_match('/(\d+[^\(\)]*\d)/', $wkt, $data);
  517 + $data = str_replace(', ', '#', $data[1]);
  518 + $data = str_replace(' ', ',', $data);
  519 + // Add 1 meter height
  520 + $data = str_replace('#', ',1 ', $data) . ',1';
  521 + $ml->addChild('tessellate', 1);
  522 + //$element->addChild('altitudeMode', 'relativeToGround');
  523 + $element->addChild('altitudeMode', 'clampToGround');
  524 + $ob = $ml->addChild('outerBoundaryIs');
  525 + $ls = $ob->addChild('LinearRing');
  526 + $ls->addChild('coordinates', $data);
  527 + }
  528 + }
  529 +
  530 +
  531 + /**
  532 + * Add a multipolygon
  533 + * FIXME: untested, should take holes into account
  534 + */
  535 + function add_multipolygon(&$wkt, &$element, $featurename){
  536 + $ml = $element->addChild('MultiGeometry');
  537 + foreach(split('\), \(', $wkt) as $line){
  538 + $this->add_polygon($line, $ml, $featurename );
  539 + }
  540 + }
  541 +
  542 +
  543 + /**
  544 + * Get the feature description
  545 + */
  546 + function get_feature_description($featurename, $attributes, $description_template){
  547 + // Compute hyperlink
  548 + if($description_template){
  549 + $description = $description_template;
  550 + foreach($attributes as $k => $val){
  551 + $description = str_replace("%$k%", iconv($this->encoding, 'utf-8', $val), $description);
  552 + }
  553 + } else {
  554 + $description = iconv($this->encoding, 'utf-8', $featurename);
  555 + }
  556 + return htmlentities($description);
  557 + }
  558 +
  559 +
  560 + /**
  561 + * Parse classes
  562 + * @return array hash of 'style_id' => style_data)
  563 + */
  564 + function parse_classes(&$layer, &$folder, &$namecol, &$title_field, &$description_template ){
  565 + $style_ar = array();
  566 + $numclasses = $layer->numclasses;
  567 + for($i = 0; $i < $numclasses; $i++){
  568 + $class = $layer->getClass($i);
  569 + $label = $class->label;
  570 + if($label){
  571 + $style['label_color'] = $label->color;
  572 + $style['label_size'] = $label->size;
  573 + }
  574 + // Get styles
  575 + for($j = 0; $j < $class->numstyles; $j++){
  576 + $_style = $class->getStyle($j);
  577 + $style['color'] = $_style->color;
  578 + $style['outlinecolor'] = $_style->outlinecolor;
  579 + $style['width'] = $_style->size; // Lines
  580 + $style['backgroundcolor'] = $_style->backgroundcolor;
  581 + $style['icon'] = $this->get_icon_url($layer, $class->name);
  582 + $style['icon_width'] = $_style->size; // Points
  583 +
  584 + }
  585 + $style['expression'] = $class->getExpression();
  586 + // Set description_template if any
  587 + $style['description_template'] = $description_template;
  588 + // Get icon for lines if any
  589 + if($icon = $layer->getMetadata('KML_ADD_POINT')){
  590 + $style['icon'] = $icon;
  591 + $style['icon_width'] = 32;
  592 + }
  593 + // Create style element
  594 + $style_id = preg_replace('/[^A-z0-9]/', '_', $layer->name . $class->name);
  595 + //$this->add_style($layer, $folder, $style_id, $style, $namecol, $title_field );
  596 + // create folder if more than one class
  597 + if($numclasses > 1){
  598 + $style['folder'] =& $class->name;
  599 + //$folder->addChild('Folder');
  600 + //$style['folder']->addChild('name', $class->name);
  601 + }
  602 + $style_ar[$style_id] = $style;
  603 + }
  604 + return $style_ar;
  605 + }
  606 +
  607 + /**
  608 + * Return a CSV list of all layer names in the mapfile
  609 + * FIXME: filter out ANNOTATIONS and other "strange" layers
  610 + */
  611 + function get_layer_list(){
  612 + $layer_list = array();
  613 + for($i = 0; $i < $this->map_object->numlayers; $i++){
  614 + $layer =& $this->map_object->getLayer($i);
  615 + $kml_skip = $layer->getMetadata('KML_SKIP');
  616 + if(strtolower($kml_skip) !== 'true'){
  617 + $layer_list[] = $layer->name;
  618 + }
  619 + }
  620 + return join(',', $layer_list);
  621 + }
  622 +
  623 +
  624 + /**
  625 + * Return the class for the shape, default to last class if not match
  626 + */
  627 + function get_shape_class(&$classitem, &$values, &$class_list){
  628 + //var_dump($class_list); die();
  629 + foreach($class_list as $style_id => $style_data){
  630 + if($style_data['expression'] && preg_match($style_data['expression'], $values[$classitem])){
  631 + //print "get_shape_class($classitem) ".$values[$classitem]." matches<br>";
  632 + return $style_id;
  633 + }
  634 + }
  635 + //print "get_shape_class($classitem) ".$values[$classitem]." no matches<br>";
  636 + return $style_id;
  637 + }
  638 +
  639 + /**
  640 + * Add the style
  641 + * @return the style URL
  642 + */
  643 + function add_style(&$layer, &$folder, $style_id, &$style_data){
  644 + // Calculare style URL
  645 + /*
  646 + if($style_data['description_template']){
  647 + $this->style_counter++;
  648 + $style_id .= '_'.$this->style_counter;
  649 + $balloon_data = $this->get_feature_description($attributes[$namecol], $attributes, $style_data['description_template']);
  650 + }
  651 + */
  652 + // Check if the style already exists
  653 + $expr = '//*[@id=\''.$style_id.'\']';
  654 + if($folder->xpath($expr)) {
  655 + return $style_id;
  656 + }
  657 + $new_style =& $folder->addChild('Style');
  658 + $new_style['id'] = $style_id;
  659 + // Switch layer type
  660 + switch($layer->type){
  661 + case MS_LAYER_POINT:
  662 + $this->add_style_point($new_style, $style_data);
  663 + break;
  664 + case MS_LAYER_POLYGON:
  665 + $this->add_style_polygon($new_style, $style_data);
  666 + break;
  667 + case MS_LAYER_LINE:
  668 + $this->add_style_line($new_style, $style_data);
  669 + // Add KML_ADD_POINT icon
  670 + if($style_data['icon']){
  671 + $this->add_style_point($new_style, $style_data);
  672 + }
  673 + break;
  674 + }
  675 + return $style_id;
  676 + }
  677 +
  678 + /**
  679 + * Add style for lines
  680 + */
  681 + function add_style_line(&$new_style, &$style_data){
  682 + if($style_data['outlinecolor']->red != -1){
  683 + $st =& $new_style->addChild('LineStyle');
  684 + $st->addChild('color', sprintf('FF%02X%02X%02X', $style_data['outlinecolor']->blue, $style_data['outlinecolor']->green, $style_data['outlinecolor']->red));
  685 + if($width) {
  686 + $st->addChild('width', $width);
  687 + }
  688 + } elseif($style_data['color']->red != -1){
  689 + $st =& $new_style->addChild('LineStyle');
  690 + $st->addChild('color', sprintf('FF%02X%02X%02X', $style_data['color']->blue, $style_data['color']->green, $style_data['color']->red));
  691 + if($width) {
  692 + $st->addChild('width', $width);
  693 + }
  694 + }
  695 + }
  696 +
  697 + /**
  698 + * Add style for points
  699 + */
  700 + function add_style_point(&$new_style, &$style_data){
  701 + if($style_data['icon']){
  702 + $st =& $new_style->addChild('IconStyle');
  703 + if($style_data['width'] && $style_data['icon_width'] != 32){
  704 + $st->addChild('scale', $style_data['icon_width'] / 32);
  705 + }
  706 + $icon =& $st->addChild('Icon');
  707 + $icon->addChild('href', htmlentities($style_data['icon']));
  708 + }
  709 + /*/ Add the balloon style if description_template is set
  710 + if($style_data['description_template']){
  711 + $this->add_balloon_style($new_style, $balloon_data);
  712 + }
  713 + */
  714 + // Label size and color
  715 + if($style_data['label_size'] || $style_data['label_color']){
  716 + $ls =& $new_style->addChild('LabelStyle');
  717 + if($style_data['label_size'] != -1 && $style_data['label_size'] != 32){
  718 + $ls->addChild('scale', $style_data['label_size'] / 32);
  719 + }
  720 + if($style_data['label_color']->red != -1){
  721 + $ls->addChild('color', sprintf('FF%02X%02X%02X', $style_data['label_color']->blue, $style_data['label_color']->green, $style_data['label_color']->red));
  722 + }
  723 + }
  724 + }
  725 +
  726 + /**
  727 + * Add style for polygons
  728 + */
  729 + function add_style_polygon(&$new_style, &$style_data){
  730 + // Get also outline styles
  731 + $this->add_style_line($new_style, $style_data);
  732 + $st =& $new_style->addChild('PolyStyle');
  733 + //die(print_r($backgroundcolor, true));
  734 + if($style_data['backgroundcolor']->red != -1){
  735 + $st->addChild('color', sprintf('FF%02X%02X%02X', $style_data['backgroundcolor']->blue, $style_data['backgroundcolor']->green, $style_data['backgroundcolor']->red));
  736 + $st->addChild('fill', 0);
  737 + } else {
  738 + $st->addChild('fill', 0);
  739 + }
  740 + $st->addChild('outline', 1);
  741 + }
  742 +
  743 + /**
  744 + * Add a WMS raster link
  745 + */
  746 + function add_wms_link(&$folder, &$layer, &$link){
  747 + // Build up the KML response document.
  748 + $icon =& $folder->addChild('Icon');
  749 + $icon->addChild('href', $link . 'layers=' . $layer->name);
  750 + //$icon->addChild('viewBoundScale', 1.5);
  751 + $icon->addChild('viewRefreshMode', 'onStop');
  752 + $llbox =& $folder->addChild('LatLonBox');
  753 + $ext = $this->map_object->extent;
  754 + $ext->project($this->in_proj, $this->out_proj);
  755 + $llbox->north = $ext->maxy;
  756 + $llbox->south = $ext->miny;
  757 + $llbox->east = $ext->maxx;
  758 + $llbox->west = $ext->minx;
  759 + // Reset original projection
  760 + $ext->project($this->out_proj, $this->in_proj);
  761 + }
  762 +
  763 + /**
  764 + * Get the url for a point icon
  765 + */
  766 + function get_icon_url($layer, $classname){
  767 + return $this->endpoint . '?service=icon&map=' . $this->map . '&typename=' . urlencode($layer->name) . '&classname=' . urlencode($classname);
  768 + }
  769 +
  770 + /**
  771 + * Get the layer description
  772 + */
  773 + function get_layer_description(&$layer){
  774 + $description = $layer->getMetadata('DESCRIPTION');
  775 + if(!$description){
  776 + $description = $layer->getMetadata('OWS_TITLE');
  777 + }
  778 + if(!$description){
  779 + $description = $layer->getMetadata('WFS_TITLE');
  780 + }
  781 + if(!$description){
  782 + $description = $layer->getMetadata('WMS_TITLE');
  783 + }
  784 + if(!$description){
  785 + $description = $layer->name;
  786 + }
  787 + return $description;
  788 + }
  789 +
  790 +
  791 +
  792 + /**
  793 + * Add style for balloon
  794 + * @param string style XML id
  795 + * @param string column name for title
  796 + */
  797 + function add_balloon_style(&$style, $balloon_data){
  798 + $balloon =& $style->addChild('BalloonStyle');
  799 + $balloon->addChild('text', htmlentities($balloon_data));
  800 + }
  801 +
  802 +
  803 + /**
  804 + * Get a request parameter
  805 + * @param string $name
  806 + * @param string $default parameter optional
  807 + * @return string the parameter value or empty string if null
  808 + */
  809 + function load_parm($name, $default = ''){
  810 + if(!isset($_REQUEST[$name])) return $default;
  811 + $value = $_REQUEST[$name];
  812 + if(get_magic_quotes_gpc() != 1) $value = addslashes($value);
  813 + //$value = escapeshellcmd($value);
  814 + return $value;
  815 + }
  816 +
  817 + /**
  818 + * Set error message
  819 + * @param string $message
  820 + * @param string $layer name
  821 + */
  822 + function set_error($message, $layer = 'Error'){
  823 + $this->errors[$layer][] = $message;
  824 + }
  825 +
  826 +
  827 + /**
  828 + * Load the map and create the map instance
  829 + */
  830 + function load_map(){
  831 + if(!file_exists($this->map) && is_readable($this->map)){
  832 + $this->set_error('Cannot read mapfile '. $this->map);
  833 + } else {
  834 + $this->map_object = ms_newMapObj($this->map);
  835 + if(!$this->map_object){
  836 + $this->set_error('Cannot load mapfile '. $this->map);
  837 + }
  838 + }
  839 + }
  840 +
  841 + /**
  842 + * Test if has errors
  843 + * @return boolean
  844 + */
  845 + function has_error(){
  846 + return count($this->errors) > 0;
  847 + }
  848 +
  849 + /**
  850 + * Add error messages to folders TAGS
  851 + */
  852 + function add_errors(){
  853 + foreach($this->errors as $layer => $errors){
  854 + $folder =& $this->_xml->Document->addChild('Folder');
  855 + $folder->addChild('name', $layer);
  856 + $folder->addChild('description', '<p>' . join("</p>\n<p>", $errors) . "</p>");
  857 + }
  858 + return $errorxml;
  859 + }
  860 +
  861 + /**
  862 + * Fetch XML and format it
  863 + */
  864 + function get_kml(){
  865 + $doc = new DOMDocument('1.0');
  866 + $doc->formatOutput = true;
  867 + $domnode = dom_import_simplexml($this->_xml);
  868 + $domnode = $doc->importNode($domnode, true);
  869 + $domnode = $doc->appendChild($domnode);
  870 + return $doc->saveXML();
  871 + }
  872 +
  873 + /**
  874 + * Send header
  875 + */
  876 + function send_header(){
  877 + header('Content-type: application/vnd.google-earth.km'.($this->_zipped ? 'z' : 'l').'+XML');
  878 + }
  879 +
  880 + /**
  881 + * Calculate cache file name
  882 + */
  883 + function get_cache_file_name(){
  884 + return 'cache/'. md5($_SERVER['QUERY_STRING']) . ($this->_zipped ? '.kmz' : '.kml');
  885 + }
  886 +
  887 + /**
  888 + * Send stream
  889 + */
  890 + function send_stream($data){
  891 + $this->send_header();
  892 + // Compress data
  893 + if($this->_zipped){
  894 + include("zip.class.php");
  895 + $ziper = new zipfile();
  896 + $ziper->addFile($data, 'doc.kml');
  897 + $data = $ziper->file();
  898 + }
  899 + // Create cache if needed
  900 + if(ENABLE_CACHE && count($this->layers) == 1 && $this->layers[$this->typename]->getMetadata('KML_CACHE')) {
  901 + error_log( 'creating cache ' . $this->get_cache_file_name() );
  902 + file_put_contents($this->get_cache_file_name(), $data);
  903 + }
  904 + print $data;
  905 + exit();
  906 + }
  907 +}
  908 +?>
0 909 \ No newline at end of file
... ...
pacotes/kmlmapserver/classes/symbolserver.class.php 0 → 100644
... ... @@ -0,0 +1,210 @@
  1 +<?php
  2 +/**
  3 +* Mapserver wrapper to symbol icons
  4 +*
  5 +* Returns an image for the symbol
  6 +*
  7 +* <pre>
  8 +* accepted parameters (case insensitive):
  9 +* - map = string - path to mapfile
  10 +* - typename = string - layer name
  11 +* - classname = string - class name
  12 +* </pre>
  13 +*
  14 +* @author Alessandro Pasotti
  15 +* @copyright 2007 ItOpen.it - All rights reserved
  16 +* @package KMLSERVER
  17 +
  18 +This file is part of KMLMAPSERVER.
  19 +
  20 + KMLMAPSERVER is free software; you can redistribute it and/or modify
  21 + it under the terms of the GNU Lesser General Public License as published by
  22 + the Free Software Foundation; either version 3 of the License, or
  23 + (at your option) any later version.
  24 +
  25 + KMLMAPSERVER is distributed in the hope that it will be useful,
  26 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  27 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28 + GNU Lesser General Public License for more details.
  29 +
  30 + You should have received a copy of the GNU Lesser General Public License
  31 + along with KMLMAPSERVER; if not, write to the Free Software
  32 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  33 +
  34 +*/
  35 +
  36 +class SymbolServer {
  37 +
  38 + /** map file path */
  39 + var $map;
  40 +
  41 + /** map instance */
  42 + var $map_object;
  43 +
  44 + /** layer name */
  45 + var $typename;
  46 +
  47 + /** class */
  48 + var $classname;
  49 +
  50 + /** class index */
  51 + var $classindex;
  52 +
  53 + /** icon_layer */
  54 + var $icon_layer;
  55 +
  56 + /** icon point object */
  57 + var $iconpoint;
  58 +
  59 +
  60 + function SymbolServer(){
  61 + $this->errors = array();
  62 + // Load request parameters
  63 + $this->get_request();
  64 + // Load map
  65 + if(!$this->has_error()) {
  66 + $this->load_map();
  67 + }
  68 + }
  69 +
  70 + /**
  71 + * Run the server and sends data
  72 + * @return string or void
  73 + */
  74 + function run(){
  75 + // Process request
  76 + if(!$this->has_error()) {
  77 + $this->process_request();
  78 + }
  79 + if($this->has_error()){
  80 + $this->send_errors();
  81 + } else {
  82 + $this->send_icon();
  83 + }
  84 + }
  85 +
  86 +
  87 + /**
  88 + * Process request
  89 + */
  90 + function process_request(){
  91 + $layer = @$this->map_object->getLayerByName($this->typename);
  92 + if(!$layer){
  93 + $this->set_error('Layer not found ' . $layer_name, $layer_name);
  94 + return false;
  95 + }
  96 + // Get class
  97 + $class = null;
  98 + for($i = 0; $i < $layer->numclasses; $i++){
  99 + $_class = @$layer->getClass($i);
  100 + if($this->classname == $_class->name){
  101 + $class =& $_class;
  102 + $this->classindex = $i;
  103 + break;
  104 + }
  105 + }
  106 + if(!$class){
  107 + $this->set_error('Class name not found ' . $layer_name, $this->classname);
  108 + return false;
  109 + }
  110 + // Get symbol size
  111 + for($i = 0; $i < $class->numstyles; $i++){
  112 + $_style = @$class->getStyle($i);
  113 + if($_style->symbolname){
  114 + // 64 pixel is standard Google Earth pushpin
  115 + //$_style->set('size', 64);
  116 + $symbolsize = $_style->size;
  117 + break;
  118 + }
  119 + }
  120 + // Provide a default here
  121 + if(!$symbolsize) {
  122 + $symbolsize = 10;
  123 + }
  124 + $ext = $this->map_object->extent;
  125 + $centerx = ($ext->maxx - $ext->minx)/2;
  126 + $centery = ($ext->maxy - $ext->miny)/2;
  127 +
  128 + // Create a new layer
  129 + $this->icon_layer = ms_newLayerObj($this->map_object, $layer);
  130 + $this->map_object->setSize($symbolsize, $symbolsize);
  131 + $this->map_object->setExtent($centerx - $symbolsize, $centery - $symbolsize, $centerx + $symbolsize, $centery + $symbolsize);
  132 + $this->icon_layer->set( 'status', MS_ON );
  133 + $this->iconpoint = ms_newPointObj();
  134 + $this->iconpoint->setXY($centerx, $centery);
  135 + }
  136 +
  137 + /**
  138 + * Test if has errors
  139 + * @return boolean
  140 + */
  141 + function has_error(){
  142 + return count($this->errors) > 0;
  143 + }
  144 +
  145 + /**
  146 + * Get all request parameters
  147 + */
  148 + function get_request(){
  149 + $this->map = $this->load_parm('map');
  150 + $this->typename = $this->load_parm('typename');
  151 + $this->classname= $this->load_parm('classname');
  152 + if(!$this->map){
  153 + $this->set_error('No mapfile specified');
  154 + }
  155 + if(!$this->typename){
  156 + $this->set_error('No typename (layer) specified');
  157 + }
  158 + }
  159 +
  160 + /**
  161 + * Get a request parameter
  162 + * @param string $name
  163 + * @return string the parameter value or empty string if null
  164 + */
  165 + function load_parm($name){
  166 + if(!isset($_REQUEST[$name])) return '';
  167 + $value = $_REQUEST[$name];
  168 + if(get_magic_quotes_gpc() != 1) $value = addslashes($value);
  169 + //$value = escapeshellcmd($value);
  170 + return $value;
  171 + }
  172 +
  173 + /**
  174 + * Set error message
  175 + * @param string $message
  176 + * @param string $layer name
  177 + */
  178 + function set_error($message, $layer = 'Error'){
  179 + $this->errors[$layer][] = $message;
  180 + }
  181 +
  182 + /**
  183 + * Load the map and create the map instance
  184 + */
  185 + function load_map(){
  186 + if(!file_exists($this->map) && is_readable($this->map)){
  187 + $this->set_error('Cannot read mapfile '. $this->map);
  188 + } else {
  189 + $this->map_object = ms_newMapObj($this->map);
  190 + if(!$this->map_object){
  191 + $this->set_error('Cannot load mapfile '. $this->map);
  192 + }
  193 + }
  194 + }
  195 +
  196 + function send_errors(){
  197 + print_r($this->errors);
  198 + }
  199 +
  200 + function send_icon(){
  201 + header('Content-type:image/png');
  202 + // Set transparency (needs imageformat RBGA in the mapfile too)
  203 + $this->map_object->set('transparent', 'on');
  204 + $img = $this->map_object->draw();
  205 + $this->iconpoint->draw($this->map_object, $this->icon_layer, $img, $this->classindex, '');
  206 + $img->saveImage('');
  207 + }
  208 +
  209 +}
  210 +?>
0 211 \ No newline at end of file
... ...
pacotes/kmlmapserver/classes/zip.class.php 0 → 100644
... ... @@ -0,0 +1,230 @@
  1 +<?php
  2 +/**
  3 +* Zip file creation class.
  4 +* Makes zip files.
  5 +*
  6 +* Last Modification and Extension By :
  7 +*
  8 +* Hasin Hayder
  9 +* HomePage : www.hasinme.info
  10 +* Email : countdraculla@gmail.com
  11 +* IDE : PHP Designer 2005
  12 +*
  13 +*
  14 +* Originally Based on :
  15 +*
  16 +* http://www.zend.com/codex.php?id=535&single=1
  17 +* By Eric Mueller <eric@themepark.com>
  18 +*
  19 +* http://www.zend.com/codex.php?id=470&single=1
  20 +* by Denis125 <webmaster@atlant.ru>
  21 +*
  22 +* a patch from Peter Listiak <mlady@users.sourceforge.net> for last modified
  23 +* date and time of the compressed file
  24 +*
  25 +* Official ZIP file format: http://www.pkware.com/appnote.txt
  26 +*
  27 +* @access public
  28 +*/
  29 +class zipfile
  30 +{
  31 + /**
  32 + * Array to store compressed data
  33 + *
  34 + * @var array $datasec
  35 + */
  36 + var $datasec = array();
  37 +
  38 + /**
  39 + * Central directory
  40 + *
  41 + * @var array $ctrl_dir
  42 + */
  43 + var $ctrl_dir = array();
  44 +
  45 + /**
  46 + * End of central directory record
  47 + *
  48 + * @var string $eof_ctrl_dir
  49 + */
  50 + var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
  51 +
  52 + /**
  53 + * Last offset position
  54 + *
  55 + * @var integer $old_offset
  56 + */
  57 + var $old_offset = 0;
  58 +
  59 +
  60 + /**
  61 + * Converts an Unix timestamp to a four byte DOS date and time format (date
  62 + * in high two bytes, time in low two bytes allowing magnitude comparison).
  63 + *
  64 + * @param integer the current Unix timestamp
  65 + *
  66 + * @return integer the current date in a four byte DOS format
  67 + *
  68 + * @access private
  69 + */
  70 + function unix2DosTime($unixtime = 0) {
  71 + $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
  72 +
  73 + if ($timearray['year'] < 1980) {
  74 + $timearray['year'] = 1980;
  75 + $timearray['mon'] = 1;
  76 + $timearray['mday'] = 1;
  77 + $timearray['hours'] = 0;
  78 + $timearray['minutes'] = 0;
  79 + $timearray['seconds'] = 0;
  80 + } // end if
  81 +
  82 + return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
  83 + ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
  84 + } // end of the 'unix2DosTime()' method
  85 +
  86 +
  87 + /**
  88 + * Adds "file" to archive
  89 + *
  90 + * @param string file contents
  91 + * @param string name of the file in the archive (may contains the path)
  92 + * @param integer the current timestamp
  93 + *
  94 + * @access public
  95 + */
  96 + function addFile($data, $name, $time = 0)
  97 + {
  98 + $name = str_replace('\\', '/', $name);
  99 +
  100 + $dtime = dechex($this->unix2DosTime($time));
  101 + $hexdtime = '\x' . $dtime[6] . $dtime[7]
  102 + . '\x' . $dtime[4] . $dtime[5]
  103 + . '\x' . $dtime[2] . $dtime[3]
  104 + . '\x' . $dtime[0] . $dtime[1];
  105 + eval('$hexdtime = "' . $hexdtime . '";');
  106 +
  107 + $fr = "\x50\x4b\x03\x04";
  108 + $fr .= "\x14\x00"; // ver needed to extract
  109 + $fr .= "\x00\x00"; // gen purpose bit flag
  110 + $fr .= "\x08\x00"; // compression method
  111 + $fr .= $hexdtime; // last mod time and date
  112 +
  113 + // "local file header" segment
  114 + $unc_len = strlen($data);
  115 + $crc = crc32($data);
  116 + $zdata = gzcompress($data);
  117 + $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
  118 + $c_len = strlen($zdata);
  119 + $fr .= pack('V', $crc); // crc32
  120 + $fr .= pack('V', $c_len); // compressed filesize
  121 + $fr .= pack('V', $unc_len); // uncompressed filesize
  122 + $fr .= pack('v', strlen($name)); // length of filename
  123 + $fr .= pack('v', 0); // extra field length
  124 + $fr .= $name;
  125 +
  126 + // "file data" segment
  127 + $fr .= $zdata;
  128 +
  129 + // "data descriptor" segment (optional but necessary if archive is not
  130 + // served as file)
  131 + $fr .= pack('V', $crc); // crc32
  132 + $fr .= pack('V', $c_len); // compressed filesize
  133 + $fr .= pack('V', $unc_len); // uncompressed filesize
  134 +
  135 + // add this entry to array
  136 + $this -> datasec[] = $fr;
  137 +
  138 + // now add to central directory record
  139 + $cdrec = "\x50\x4b\x01\x02";
  140 + $cdrec .= "\x00\x00"; // version made by
  141 + $cdrec .= "\x14\x00"; // version needed to extract
  142 + $cdrec .= "\x00\x00"; // gen purpose bit flag
  143 + $cdrec .= "\x08\x00"; // compression method
  144 + $cdrec .= $hexdtime; // last mod time & date
  145 + $cdrec .= pack('V', $crc); // crc32
  146 + $cdrec .= pack('V', $c_len); // compressed filesize
  147 + $cdrec .= pack('V', $unc_len); // uncompressed filesize
  148 + $cdrec .= pack('v', strlen($name) ); // length of filename
  149 + $cdrec .= pack('v', 0 ); // extra field length
  150 + $cdrec .= pack('v', 0 ); // file comment length
  151 + $cdrec .= pack('v', 0 ); // disk number start
  152 + $cdrec .= pack('v', 0 ); // internal file attributes
  153 + $cdrec .= pack('V', 32 ); // external file attributes - 'archive' bit set
  154 +
  155 + $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header
  156 + $this -> old_offset += strlen($fr);
  157 +
  158 + $cdrec .= $name;
  159 +
  160 + // optional extra field, file comment goes here
  161 + // save to central directory
  162 + $this -> ctrl_dir[] = $cdrec;
  163 + } // end of the 'addFile()' method
  164 +
  165 +
  166 + /**
  167 + * Dumps out file
  168 + *
  169 + * @return string the zipped file
  170 + *
  171 + * @access public
  172 + */
  173 + function file()
  174 + {
  175 + $data = implode('', $this -> datasec);
  176 + $ctrldir = implode('', $this -> ctrl_dir);
  177 +
  178 + return
  179 + $data .
  180 + $ctrldir .
  181 + $this -> eof_ctrl_dir .
  182 + pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk"
  183 + pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall
  184 + pack('V', strlen($ctrldir)) . // size of central dir
  185 + pack('V', strlen($data)) . // offset to start of central dir
  186 + "\x00\x00"; // .zip file comment length
  187 + } // end of the 'file()' method
  188 +
  189 +
  190 + /**
  191 + * A Wrapper of original addFile Function
  192 + *
  193 + * Created By Hasin Hayder at 29th Jan, 1:29 AM
  194 + *
  195 + * @param array An Array of files with relative/absolute path to be added in Zip File
  196 + *
  197 + * @access public
  198 + */
  199 + function addFiles($files /*Only Pass Array*/)
  200 + {
  201 + foreach($files as $file)
  202 + {
  203 + if (is_file($file)) //directory check
  204 + {
  205 + $data = implode("",file($file));
  206 + $this->addFile($data,$file);
  207 + }
  208 + }
  209 + }
  210 +
  211 + /**
  212 + * A Wrapper of original file Function
  213 + *
  214 + * Created By Hasin Hayder at 29th Jan, 1:29 AM
  215 + *
  216 + * @param string Output file name
  217 + *
  218 + * @access public
  219 + */
  220 + function output($file)
  221 + {
  222 + $fp=fopen($file,"w");
  223 + fwrite($fp,$this->file());
  224 + fclose($fp);
  225 + }
  226 +
  227 +
  228 +
  229 +} // end of the 'zipfile' class
  230 +?>
0 231 \ No newline at end of file
... ...
pacotes/kmlmapserver/doc/index.html 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +<p>See online docs here:<br />
  2 +
  3 +<a href="http://www.itopen.it/soluzioni/webmapping/kml-map-server/">http://www.itopen.it/soluzioni/webmapping/kml-map-server/</a>
  4 +</p>
0 5 \ No newline at end of file
... ...
pacotes/kmlmapserver/kmlservice.php 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +<?php
  2 +/**
  3 +* KML server
  4 +*
  5 +* @author Alessandro Pasotti
  6 +* @copyright 2007 ItOpen.it - All rights reserved
  7 +* @package KMLSERVER
  8 +
  9 +This file is part of KMLMAPSERVER.
  10 +
  11 + KMLMAPSERVER is free software; you can redistribute it and/or modify
  12 + it under the terms of the GNU Lesser General Public License as published by
  13 + the Free Software Foundation; either version 3 of the License, or
  14 + (at your option) any later version.
  15 +
  16 + KMLMAPSERVER is distributed in the hope that it will be useful,
  17 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19 + GNU Lesser General Public License for more details.
  20 +
  21 + You should have received a copy of the GNU Lesser General Public License
  22 + along with KMLMAPSERVER; if not, write to the Free Software
  23 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24 +
  25 +*/
  26 +
  27 +set_time_limit(0);
  28 +include 'classes/kmlserver.class.php';
  29 +$server = new KmlServer();
  30 +?>
0 31 \ No newline at end of file
... ...