Completed
Push — master ( 8f3dec...787392 )
by Mark
18s queued 12s
created

action_plugin_spatialhelper::removeFromIndex()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 9.1768
c 0
b 0
f 0
cc 5
nc 6
nop 2
1
<?php
2
/*
3
 * Copyright (c) 2011-2020 Mark C. Prins <[email protected]>
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
use dokuwiki\Sitemap\Item;
19
20
/**
21
 * DokuWiki Plugin dokuwikispatial (Action Component).
22
 *
23
 * @license BSD license
24
 * @author Mark C. Prins <[email protected]>
25
 */
26
class action_plugin_spatialhelper extends DokuWiki_Action_Plugin {
27
28
    /**
29
     * Register for events.
30
     *
31
     * @param Doku_Event_Handler $controller
32
     *          DokuWiki's event controller object. Also available as global $EVENT_HANDLER
33
     */
34
    public function register(Doku_Event_Handler $controller) {
35
        // listen for page add / delete events
36
        // http://www.dokuwiki.org/devel:event:indexer_page_add
37
        $controller->register_hook('INDEXER_PAGE_ADD', 'BEFORE', $this, 'handleIndexerPageAdd');
38
        $controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'removeFromIndex');
39
40
        // http://www.dokuwiki.org/devel:event:sitemap_generate
41
        $controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handleSitemapGenerateBefore');
42
        // using after will only trigger us if a sitemap was actually created
43
        $controller->register_hook('SITEMAP_GENERATE', 'AFTER', $this, 'handleSitemapGenerateAfter');
44
45
        // handle actions we know of
46
        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleActionActPreprocess', array());
47
        // handle HTML eg. /dokuwiki/doku.php?id=start&do=findnearby&geohash=u15vk4
48
        $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
49
                'format' => 'HTML'
50
        ));
51
        // handles AJAX/json eg: jQuery.post("/dokuwiki/lib/exe/ajax.php?id=start&call=findnearby&geohash=u15vk4");
52
        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
53
                'format' => 'JSON'
54
        ));
55
56
        // listen for media uploads and deletes
57
        $controller->register_hook('MEDIA_UPLOAD_FINISH', 'BEFORE', $this, 'handleMediaUploaded', array());
58
        $controller->register_hook('MEDIA_DELETE_FILE', 'BEFORE', $this, 'handleMediaDeleted', array());
59
60
        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleMetaheaderOutput');
61
    }
62
63
    /**
64
     * Update the spatial index for the page.
65
     *
66
     * @param Doku_Event $event
67
     *          event object by reference
68
     * @param object $param
69
     *          the parameters passed to register_hook when this handler was registered
70
     */
71
    public function handleIndexerPageAdd(Doku_Event $event, $param) {
72
        // $event→data['page'] – the page id
73
        // $event→data['body'] – empty, can be filled by additional content to index by your plugin
74
        // $event→data['metadata'] – the metadata that shall be indexed. This is an array where the keys are the
75
        //    metadata indexes and the value a string or an array of strings with the values.
76
        //    title and relation_references will already be set.
77
        $id = $event->data ['page'];
78
        $indexer = & plugin_load('helper', 'spatialhelper_index');
79
        $entries = $indexer->updateSpatialIndex($id);
0 ignored issues
show
Unused Code introduced by
$entries is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
80
    }
81
82
    /**
83
     * Update the spatial index, removing the page.
84
     *
85
     * @param Doku_Event $event
86
     *          event object by reference
87
     * @param object $param
88
     *          the parameters passed to register_hook when this handler was registered
89
     */
90
    public function removeFromIndex(Doku_Event & $event, $param) {
91
        // event data:
92
        // $data[0] – The raw arguments for io_saveFile as an array. Do not change file path.
93
        // $data[0][0] – the file path.
94
        // $data[0][1] – the content to be saved, and may be modified.
95
        // $data[1] – ns: The colon separated namespace path minus the trailing page name. (false if root ns)
96
        // $data[2] – page_name: The wiki page name.
97
        // $data[3] – rev: The page revision, false for current wiki pages.
98
99
        dbglog($event->data, "Event data in removeFromIndex.");
100
        if (@file_exists($event->data [0] [0])) {
101
            // file not new
102
            if (!$event->data [0] [1]) {
103
                // file is empty, page is being deleted
104
                if (empty ($event->data [1])) {
105
                    // root namespace
106
                    $id = $event->data [2];
107
                } else {
108
                    $id = $event->data [1] . ":" . $event->data [2];
109
                }
110
                $indexer = & plugin_load('helper', 'spatialhelper_index');
111
                if ($indexer) {
112
                    $indexer->deleteFromIndex($id);
113
                }
114
            }
115
        }
116
    }
117
118
    /**
119
     * Add a new SitemapItem object that points to the KML of public geocoded pages.
120
     *
121
     * @param Doku_Event $event
122
     * @param unknown $param
123
     */
124
    public function handleSitemapGenerateBefore(Doku_Event $event, $param) {
125
        $path = mediaFN($this->getConf('media_kml'));
126
        $lastmod = @filemtime($path);
127
        $event->data ['items'] [] = new Item(ml($this->getConf('media_kml'), '', true, '&amp;', true), $lastmod);
128
        //dbglog($event->data ['items'],
129
        //  "Added a new SitemapItem object that points to the KML of public geocoded pages.");
130
    }
131
132
    /**
133
     * Create a spatial sitemap or attach the geo/kml map to the sitemap.
134
     *
135
     * @param Doku_Event $event
136
     *          event object by reference, not used
137
     * @param mixed $param
138
     *          parameter array, not used
139
     */
140
    public function handleSitemapGenerateAfter(Doku_Event $event, $param) {
141
        // $event→data['items']: Array of SitemapItem instances, the array of sitemap items that already
142
        //      contains all public pages of the wiki
143
        // $event→data['sitemap']: The path of the file the sitemap will be saved to.
144
        if ($helper = & plugin_load('helper', 'spatialhelper_sitemap')) {
145
            // dbglog($helper, "createSpatialSitemap loaded helper.");
146
147
            $kml = $helper->createKMLSitemap($this->getConf('media_kml'));
148
            $rss = $helper->createGeoRSSSitemap($this->getConf('media_georss'));
149
            
150
            if (!empty ($this->getConf('sitemap_namespaces'))) {
151
                $namespaces = array_map('trim', explode("\n", $this->getConf('sitemap_namespaces')));
152
                foreach ($namespaces as $namespace) {
153
                    $kmlN = $helper->createKMLSitemap($namespace . $this->getConf('media_kml'));
154
                    $rssN = $helper->createGeoRSSSitemap($namespace . $this->getConf('media_georss'));
155
                    dbglog(
156
                        $kmlN && $rssN,
157
                        "handleSitemapGenerateAfter, created KML / GeoRSS sitemap in $namespace, succes: "
158
                    );
159
                }  
160
            }
161
            return $kml && $rss;
162
        } else {
163
            dbglog($helper, "createSpatialSitemap NOT loaded helper.");
164
        }
165
    }
166
167
    /**
168
     * trap findnearby action.
169
     * This addional handler is required as described at: https://www.dokuwiki.org/devel:event:tpl_act_unknown
170
     *
171
     * @param Doku_Event $event
172
     *          event object by reference
173
     * @param mixed $param
174
     *          not used
175
     */
176
    public function handleActionActPreprocess(Doku_Event $event, $param) {
177
        if ($event->data != 'findnearby') {
178
            return;
179
        }
180
        $event->preventDefault();
181
    }
182
183
    /**
184
     * handle findnearby action.
185
     *
186
     * @param Doku_Event $event
187
     *          event object by reference
188
     * @param mixed $param
189
     *          associative array with keys
190
     *          'format'=> HTML | JSON
191
     */
192
    public function findnearby(Doku_Event & $event, $param) {
193
        if ($event->data != 'findnearby') {
194
            return;
195
        }
196
        $event->preventDefault();
197
198
        global $INPUT;
199
        if ($helper = & plugin_load('helper', 'spatialhelper_search')) {
200
            if ($INPUT->has('lat') && $INPUT->has('lon')) {
201
                $results = $helper->findNearbyLatLon($INPUT->param('lat'), $INPUT->param('lon'));
202
            } elseif ($INPUT->has('geohash')) {
203
                $results = $helper->findNearby($INPUT->str('geohash'));
204
            } else {
205
                $results = array(
206
                        'error' => hsc($this->getLang('invalidinput'))
207
                );
208
            }
209
        }
210
211
        $showMedia = $INPUT->bool('showMedia', true);
212
213
        switch ($param['format']) {
214
            case 'JSON' :
215
                $this->printJSON($results);
0 ignored issues
show
Bug introduced by
The variable $results does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
216
                break;
217
            case 'HTML' :
218
            // fall through to default
219
            default :
220
                $this->printHTML($results, $showMedia);
221
                break;
222
        }
223
    }
224
225
    /**
226
     * Print seachresults as HTML lists.
227
     *
228
     * @param array $searchresults
229
     */
230
    private function printJSON($searchresults) {
231
        require_once DOKU_INC . 'inc/JSON.php';
232
        $json = new JSON();
233
        header('Content-Type: application/json');
234
        print $json->encode($searchresults);
235
    }
236
237
    /**
238
     * Print seachresults as HTML lists.
239
     *
240
     * @param array $searchresults
241
     * @param boolean $showMedia
242
     */
243
    private function printHTML($searchresults, $showMedia = true) {
244
        $pages = (array) ($searchresults ['pages']);
245
        $media = (array) $searchresults ['media'];
246
        $lat = (float) $searchresults ['lat'];
247
        $lon = (float) $searchresults ['lon'];
248
        $geohash = (string) $searchresults ['geohash'];
249
250
        if (isset ($searchresults ['error'])) {
251
            print '<div class="level1"><p>' . hsc($results ['error']) . '</p></div>';
0 ignored issues
show
Bug introduced by
The variable $results does not exist. Did you mean $searchresults?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
252
            return;
253
        }
254
255
        // print a HTML list
256
        print '<h1>' . $this->getLang('results_header') . '</h1>' . DOKU_LF;
257
        print '<div class="level1">' . DOKU_LF;
258
        if (!empty ($pages)) {
259
            $pagelist = '<ol>' . DOKU_LF;
260
            foreach ($pages as $page) {
261
                $pagelist .= '<li>' . html_wikilink(':' . $page ['id'], useHeading('navigation') ? null :
262
                    noNS($page ['id'])) . ' (' . $this->getLang('results_distance_prefix')
263
                        . $page ['distance'] . '&nbsp;m) ' . $page ['description'] . '</li>' . DOKU_LF;
264
            }
265
            $pagelist .= '</ol>' . DOKU_LF;
266
267
            print '<h2>' . $this->getLang('results_pages') . hsc(' lat;lon: ' . $lat . ';' . $lon
268
                . ' (geohash: ' . $geohash . ')') . '</h2>';
269
            print '<div class="level2">' . DOKU_LF;
270
            print $pagelist;
271
            print '</div>' . DOKU_LF;
272
        } else {
273
            print '<p>' . hsc($this->getLang('nothingfound')) . '</p>';
274
        }
275
276
        if (!empty ($media) && $showMedia) {
277
            $pagelist = '<ol>' . DOKU_LF;
278
            foreach ($media as $m) {
279
                $opts = array();
280
                $link = ml($m ['id'], $opts, false, '&amp;', false);
281
                $opts ['w'] = '100';
282
                $src = ml($m ['id'], $opts);
283
                $pagelist .= '<li><a href="' . $link . '"><img src="' . $src . '"></a> ('
284
                    . $this->getLang('results_distance_prefix') . $page ['distance'] . '&nbsp;m) ' . hsc($desc)
0 ignored issues
show
Bug introduced by
The variable $desc does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $page seems to be defined by a foreach iteration on line 260. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
285
                    . '</li>' . DOKU_LF;
286
            }
287
            $pagelist .= '</ol>' . DOKU_LF;
288
289
            print '<h2>' . $this->getLang('results_media') . hsc(' lat;lon: ' . $lat . ';' . $lon
290
                . ' (geohash: ' . $geohash . ')') . '</h2>' . DOKU_LF;
291
            print '<div class="level2">' . DOKU_LF;
292
            print $pagelist;
293
            print '</div>' . DOKU_LF;
294
        }
295
        print '<p>' . $this->getLang('results_precision') . $searchresults ['precision'] . ' m. ';
296
        if (strlen($geohash) > 1) {
297
            $url = wl(getID(), array(
298
                    'do' => 'findnearby',
299
                    'geohash' => substr($geohash, 0, - 1)
300
            ));
301
            print '<a href="' . $url . '" class="findnearby">' . $this->getLang('search_largerarea') . '</a>.</p>'
302
                . DOKU_LF;
303
        }
304
        print '</div>' . DOKU_LF;
305
    }
306
307
    /**
308
     * add media to spatial index.
309
     *
310
     * @param Doku_Event $event
311
     *          event object by reference
312
     * @param unknown $param
313
     */
314
    public function handleMediaUploaded(Doku_Event & $event, $param) {
315
        // data[0] temporary file name (read from $_FILES)
316
        // data[1] file name of the file being uploaded
317
        // data[2] future directory id of the file being uploaded
318
        // data[3] the mime type of the file being uploaded
319
        // data[4] true if the uploaded file exists already
320
        // data[5] (since 2011-02-06) the PHP function used to move the file to the correct location
321
322
        dbglog($event->data, "handleMediaUploaded::event data");
323
324
        // check the list of mimetypes
325
        // if it's a supported type call appropriate index function
326
        if (substr_compare($event->data [3], 'image/jpeg', 0)) {
327
            $indexer = plugin_load('helper', 'spatialhelper_index');
328
            if ($indexer) {
329
                $indexer->indexImage($event->data [2], $event->data [1]);
330
            }
331
        }
332
        // TODO add image/tiff
333
        // TODO kml, gpx, geojson...
334
    }
335
336
    /**
337
     * removes the media from the index.
338
     */
339
    public function handleMediaDeleted(Doku_Event & $event, $param) {
340
        // data['id'] ID data['unl'] unlink return code
341
        // data['del'] Namespace directory unlink return code
342
        // data['name'] file name data['path'] full path to the file
343
        // data['size'] file size
344
345
        dbglog($event->data, "handleMediaDeleted::event data");
346
347
        // remove the media id from the index
348
        $indexer = & plugin_load('helper', 'spatialhelper_index');
349
        if ($indexer) {
350
            $indexer->deleteFromIndex('media__' . $event->data ['id']);
351
        }
352
    }
353
354
    /**
355
     * add a link to the spatial sitemap files in the header.
356
     *
357
     * @param Doku_Event $event
358
     *          the DokuWiki event. $event->data is a two-dimensional
359
     *          array of all meta headers. The keys are meta, link and script.
360
     * @param unknown_type $param
361
     *
362
     * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output
363
     */
364
    public function handleMetaheaderOutput(Doku_Event $event, $param) {
365
        // TODO maybe test for exist
366
        $event->data ["link"] [] = array(
367
                "type" => "application/atom+xml",
368
                "rel" => "alternate",
369
                "href" => ml($this->getConf('media_georss')),
370
                "title" => "Spatial ATOM Feed"
371
        );
372
        $event->data ["link"] [] = array(
373
                "type" => "application/vnd.google-earth.kml+xml",
374
                "rel" => "alternate",
375
                "href" => ml($this->getConf('media_kml')),
376
                "title" => "KML Sitemap"
377
        );
378
    }
379
380
    /**
381
     * Calculate a new coordinate based on start, distance and bearing
382
     *
383
     * @param $start array
384
     *          - start coordinate as decimal lat/lon pair
385
     * @param $dist float
386
     *          - distance in kilometers
387
     * @param $brng float
388
     *          - bearing in degrees (compass direction)
389
     */
390
    private function geoDestination($start, $dist, $brng) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
391
        $lat1 = toRad($start [0]);
392
        $lon1 = toRad($start [1]);
393
        // http://en.wikipedia.org/wiki/Earth_radius
394
        // average earth radius in km
395
        $dist = $dist / 6371.01;
396
        $brng = toRad($brng);
397
398
        $lon2 = $lon1 + atan2(sin($brng) * sin($dist) * cos($lat1), cos($dist) - sin($lat1) * sin($lat2));
0 ignored issues
show
Bug introduced by
The variable $lat2 does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
399
        $lon2 = fmod(($lon2 + 3 * pi()), (2 * pi())) - pi();
400
401
        return array(
402
                toDeg($lat2),
403
                toDeg($lon2)
404
        );
405
    }
406
    private function toRad($deg) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
407
        return $deg * pi() / 180;
408
    }
409
    private function toDeg($rad) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
410
        return $rad * 180 / pi();
411
    }
412
}
413