Commit 035d3cd4c2b6f64e01797b100d598958231023bd
1 parent
0bd5f4eb
Exists in
master
and in
7 other branches
Adicionada a biblioteca kmlmapserver em pacotes
Showing
9 changed files
with
1741 additions
and
0 deletions
Show diff stats
@@ -0,0 +1,165 @@ | @@ -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. |
@@ -0,0 +1,92 @@ | @@ -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 | + |
@@ -0,0 +1,102 @@ | @@ -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 | \ No newline at end of file | 103 | \ No newline at end of file |
@@ -0,0 +1,908 @@ | @@ -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 . '&typename=' . urlencode($layer_name) . '&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('/&/', '&', $wms_link); | ||
315 | + $wms_link .= 'VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&STYLES=&BGCOLOR=0xFFFFFF&FORMAT=image/png&TRANSPARENT=TRUE&'; | ||
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 | \ No newline at end of file | 909 | \ No newline at end of file |
@@ -0,0 +1,210 @@ | @@ -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 | \ No newline at end of file | 211 | \ No newline at end of file |
@@ -0,0 +1,230 @@ | @@ -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 | \ No newline at end of file | 231 | \ No newline at end of file |
@@ -0,0 +1,30 @@ | @@ -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 | \ No newline at end of file | 31 | \ No newline at end of file |