1<?php 2/* 3 * Copyright (c) 2014-2016 Mark C. Prins <mprins@users.sf.net> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/** 19 * DokuWiki Plugin spatialhelper (sitemap Component). 20 * 21 * @license BSD license 22 * @author Mark Prins 23 */ 24class helper_plugin_spatialhelper_sitemap extends DokuWiki_Plugin { 25 /** 26 * spatial index. 27 */ 28 private $spatial_idx; 29 30 /** 31 * constructor, load spatial index. 32 */ 33 public function __construct() { 34 global $conf; 35 $idx_dir = $conf['indexdir']; 36 if(!@file_exists($idx_dir . '/spatial.idx')) { 37 $indexer = plugin_load('helper', 'spatialhelper_index'); 38 if($indexer !== null) { 39 $indexer->generateSpatialIndex(); 40 } 41 } 42 $this->spatial_idx = unserialize(io_readFile($fn = $idx_dir . '/spatial.idx', false), false); 43 } 44 45 final public function getMethods(): array { 46 $result[] = array( 47 'name' => 'createGeoRSSSitemap', 48 'desc' => 'create a spatial sitemap in GeoRSS format.', 49 'params' => array( 50 'path' => 'string' 51 ), 52 'return' => array( 53 'success' => 'boolean' 54 ) 55 ); 56 $result[] = array( 57 'name' => 'createKMLSitemap', 58 'desc' => 'create a spatial sitemap in KML format.', 59 'params' => array( 60 'path' => 'string' 61 ), 62 'return' => array( 63 'success' => 'boolean' 64 ) 65 ); 66 return $result; 67 } 68 69 /** 70 * Create a GeoRSS Simple sitemap (Atom). 71 * 72 * @param string $mediaID id 73 * for the GeoRSS file 74 */ 75 final public function createGeoRSSSitemap(string $mediaID): bool { 76 global $conf; 77 $namespace = getNS($mediaID); 78 79 $idTag = 'tag:' . parse_url(DOKU_URL, PHP_URL_HOST) . ','; 80 81 $RSSstart = '<?xml version="1.0" encoding="UTF-8"?>' . DOKU_LF; 82 $RSSstart .= '<feed xmlns="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss" '; 83 $RSSstart .= 'xmlns:dc="http://purl.org/dc/elements/1.1/">' . DOKU_LF; 84 $RSSstart .= '<title>' . $conf['title'] . ' spatial feed</title>' . DOKU_LF; 85 if(!empty($conf['tagline'])) { 86 $RSSstart .= '<subtitle>' . $conf['tagline'] . '</subtitle>' . DOKU_LF; 87 } 88 $RSSstart .= '<dc:publisher>' . $conf['title'] . '</dc:publisher>' . DOKU_LF; 89 $RSSstart .= '<link href="' . DOKU_URL . '" />' . DOKU_LF; 90 $RSSstart .= '<link href="' . ml($mediaID, '', true, '&', true) . '" rel="self" />' . DOKU_LF; 91 $RSSstart .= '<updated>' . date(DATE_ATOM) . '</updated>' . DOKU_LF; 92 $RSSstart .= '<id>' . $idTag . date("Y-m-d") . ':' . parse_url(ml($mediaID), PHP_URL_PATH) 93 . '</id>' . DOKU_LF; 94 $RSSstart .= '<rights>' . $conf['license'] . '</rights>' . DOKU_LF; 95 96 $RSSend = '</feed>' . DOKU_LF; 97 98 io_createNamespace($mediaID, 'media'); 99 @touch(mediaFN($mediaID)); 100 @chmod(mediaFN($mediaID), $conf['fmode']); 101 $fh = fopen(mediaFN($mediaID), 'wb'); 102 fwrite($fh, $RSSstart); 103 104 foreach($this->spatial_idx as $idxEntry) { 105 // get list of id's 106 foreach($idxEntry as $id) { 107 // for document item in the index 108 if(strpos($id, 'media__', 0) !== 0) { 109 if($this->skipPage($id, $namespace)) { 110 continue; 111 } 112 113 $meta = p_get_metadata($id); 114 115 // $desc = p_render('xhtmlsummary', p_get_instructions($meta['description']['abstract']), $info); 116 $desc = strip_tags($meta['description']['abstract']); 117 118 $entry = '<entry>' . DOKU_LF; 119 $entry .= ' <title>' . $meta['title'] . '</title>' . DOKU_LF; 120 $entry .= ' <summary>' . $desc . '</summary>' . DOKU_LF; 121 $entry .= ' <georss:point>' . $meta['geo']['lat'] . ' ' . $meta['geo']['lon'] 122 . '</georss:point>' . DOKU_LF; 123 if(isset($meta['geo']['alt'])) { 124 $entry .= ' <georss:elev>' . $meta['geo']['alt'] . '</georss:elev>' . DOKU_LF; 125 } 126 $entry .= ' <link href="' . wl($id) . '" rel="alternate" type="text/html" />' . DOKU_LF; 127 if(empty($meta['creator'])) { 128 $meta['creator'] = $conf['title']; 129 } 130 $entry .= ' <author><name>' . $meta['creator'] . '</name></author>' . DOKU_LF; 131 $entry .= ' <updated>' . date_iso8601($meta['date']['modified']) . '</updated>' . DOKU_LF; 132 $entry .= ' <published>' . date_iso8601($meta['date']['created']) . '</published>' . DOKU_LF; 133 $entry .= ' <id>' . $idTag . date("Y-m-d", $meta['date']['modified']) . ':' 134 . parse_url(wl($id), PHP_URL_PATH) . '</id>' . DOKU_LF; 135 $entry .= '</entry>' . DOKU_LF; 136 fwrite($fh, $entry); 137 } 138 } 139 } 140 141 fwrite($fh, $RSSend); 142 return fclose($fh); 143 } 144 145 /** 146 * will return true for non-public or hidden pages or pages that are not below or in the namespace. 147 */ 148 private function skipPage(string $id, string $namespace): bool { 149 dbglog("helper_plugin_spatialhelper_sitemap::skipPage, check for $id in $namespace"); 150 if(isHiddenPage($id)) { 151 return true; 152 } 153 if(auth_aclcheck($id, '', null) < AUTH_READ) { 154 return true; 155 } 156 157 if(!empty($namespace)) { 158 // only if id is in or below namespace 159 if(0 !== strpos(getNS($id), $namespace)) { 160 // dbglog("helper_plugin_spatialhelper_sitemap::skipPage, skipping $id, not in $namespace"); 161 return true; 162 } 163 } 164 return false; 165 } 166 167 /** 168 * Create a KML sitemap. 169 * 170 * @param string $mediaID id for the KML file 171 */ 172 final public function createKMLSitemap(string $mediaID): bool { 173 global $conf; 174 $namespace = getNS($mediaID); 175 176 $KMLstart = '<?xml version="1.0" encoding="UTF-8"?>' . DOKU_LF; 177 $KMLstart .= '<kml xmlns="http://www.opengis.net/kml/2.2" '; 178 $KMLstart .= 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '; 179 $KMLstart .= 'xmlns:atom="http://www.w3.org/2005/Atom"'; 180 $KMLstart .= ' xsi:schemaLocation="http://www.opengis.net/kml/2.2 '; 181 $KMLstart .= 'http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd">' . DOKU_LF; 182 $KMLstart .= '<Document id="root_doc">' . DOKU_LF; 183 $KMLstart .= '<name>' . $conf['title'] . ' spatial sitemap</name>' . DOKU_LF; 184 $KMLstart .= '<atom:link href="' . DOKU_URL . '" rel="related" type="text/html" />' . DOKU_LF; 185 $KMLstart .= '<!-- atom:updated>' . date(DATE_ATOM) . '</atom:updated -->' . DOKU_LF; 186 $KMLstart .= '<Style id="icon"><IconStyle><color>ffffffff</color><scale>1</scale>'; 187 $KMLstart .= '<Icon><href>' 188 . DOKU_BASE . 'lib/plugins/spatialhelper/wikiitem.png</href></Icon></IconStyle></Style>' . DOKU_LF; 189 190 $KMLend = '</Document>' . DOKU_LF . '</kml>'; 191 192 io_createNamespace($mediaID, 'media'); 193 @touch(mediaFN($mediaID)); 194 @chmod(mediaFN($mediaID), $conf['fmode']); 195 196 $fh = fopen(mediaFN($mediaID), 'wb'); 197 fwrite($fh, $KMLstart); 198 199 foreach($this->spatial_idx as $idxEntry) { 200 // get list of id's 201 foreach($idxEntry as $id) { 202 // for document item in the index 203 if(strpos($id, 'media__', 0) !== 0) { 204 if($this->skipPage($id, $namespace)) { 205 continue; 206 } 207 208 $meta = p_get_metadata($id); 209 210 // $desc = p_render('xhtmlsummary', p_get_instructions($meta['description']['abstract']), $info); 211 $desc = '<p>' . strip_tags($meta['description']['abstract']) . '</p>'; 212 $desc .= '<p><a href="' . wl($id, '', true) . '">' . $meta['title'] . '</a></p>'; 213 214 // create an entry and store it 215 $plcm = '<Placemark id="crc32-' . hash('crc32', $id) . '">' . DOKU_LF; 216 $plcm .= ' <name>' . $meta['title'] . '</name>' . DOKU_LF; 217 // TODO escape quotes in: title="' . $meta['title'] . '" 218 $plcm .= ' <atom:link href="' . wl($id, '' . true) . '" rel="alternate" type="text/html" />' 219 . DOKU_LF; 220 if(!empty($meta['creator'])) { 221 $plcm .= ' <atom:author><atom:name>' . $meta['creator'] . '</atom:name></atom:author>' 222 . DOKU_LF; 223 } 224 225 $plcm .= ' <description><![CDATA[' . $desc . ']]></description>' . DOKU_LF; 226 $plcm .= ' <styleUrl>#icon</styleUrl>' . DOKU_LF; 227 228 $plcm .= ' <Point><coordinates>' . $meta['geo']['lon'] . ',' . $meta['geo']['lat']; 229 if(isset($meta['geo']['alt'])) { 230 $plcm .= ',' . $meta['geo']['alt']; 231 } 232 $plcm .= '</coordinates></Point>' . DOKU_LF; 233 $plcm .= '</Placemark>' . DOKU_LF; 234 235 fwrite($fh, $plcm); 236 } 237 } 238 } 239 fwrite($fh, $KMLend); 240 return fclose($fh); 241 } 242} 243