xref: /plugin/spatialhelper/helper/sitemap.php (revision 94b6d38787dc96430c59edf5ece7c12508f3699f) !
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, '&amp;', 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