Completed
Push — master ( 00fa07...61a47e )
by Mark
21s queued 13s
created

action.php (9 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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(
49
            'TPL_ACT_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
50
            'format' => 'HTML'
51
        )
52
        );
53
        // handles AJAX/json eg: jQuery.post("/dokuwiki/lib/exe/ajax.php?id=start&call=findnearby&geohash=u15vk4");
54
        $controller->register_hook(
55
            'AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
56
            'format' => 'JSON'
57
        )
58
        );
59
60
        // listen for media uploads and deletes
61
        $controller->register_hook('MEDIA_UPLOAD_FINISH', 'BEFORE', $this, 'handleMediaUploaded', array());
62
        $controller->register_hook('MEDIA_DELETE_FILE', 'BEFORE', $this, 'handleMediaDeleted', array());
63
64
        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleMetaheaderOutput');
65
    }
66
67
    /**
68
     * Update the spatial index for the page.
69
     *
70
     * @param Doku_Event $event
71
     *          event object by reference
72
     * @param object     $param
73
     *          the parameters passed to register_hook when this handler was registered
74
     */
75
    public function handleIndexerPageAdd(Doku_Event $event, $param) {
76
        // $event→data['page'] – the page id
77
        // $event→data['body'] – empty, can be filled by additional content to index by your plugin
78
        // $event→data['metadata'] – the metadata that shall be indexed. This is an array where the keys are the
79
        //    metadata indexes and the value a string or an array of strings with the values.
80
        //    title and relation_references will already be set.
81
        $id      = $event->data ['page'];
82
        $indexer = &plugin_load('helper', 'spatialhelper_index');
83
        $entries = $indexer->updateSpatialIndex($id);
0 ignored issues
show
$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...
84
    }
85
86
    /**
87
     * Update the spatial index, removing the page.
88
     *
89
     * @param Doku_Event $event
90
     *          event object by reference
91
     * @param object     $param
92
     *          the parameters passed to register_hook when this handler was registered
93
     */
94
    public function removeFromIndex(Doku_Event &$event, $param) {
95
        // event data:
96
        // $data[0] – The raw arguments for io_saveFile as an array. Do not change file path.
97
        // $data[0][0] – the file path.
98
        // $data[0][1] – the content to be saved, and may be modified.
99
        // $data[1] – ns: The colon separated namespace path minus the trailing page name. (false if root ns)
100
        // $data[2] – page_name: The wiki page name.
101
        // $data[3] – rev: The page revision, false for current wiki pages.
102
103
        dbglog($event->data, "Event data in removeFromIndex.");
104
        if(@file_exists($event->data [0] [0])) {
105
            // file not new
106
            if(!$event->data [0] [1]) {
107
                // file is empty, page is being deleted
108
                if(empty ($event->data [1])) {
109
                    // root namespace
110
                    $id = $event->data [2];
111
                } else {
112
                    $id = $event->data [1] . ":" . $event->data [2];
113
                }
114
                $indexer = &plugin_load('helper', 'spatialhelper_index');
115
                if($indexer) {
116
                    $indexer->deleteFromIndex($id);
117
                }
118
            }
119
        }
120
    }
121
122
    /**
123
     * Add a new SitemapItem object that points to the KML of public geocoded pages.
124
     *
125
     * @param Doku_Event $event
126
     * @param unknown    $param
127
     */
128
    public function handleSitemapGenerateBefore(Doku_Event $event, $param) {
129
        $path                     = mediaFN($this->getConf('media_kml'));
130
        $lastmod                  = @filemtime($path);
131
        $event->data ['items'] [] = new Item(ml($this->getConf('media_kml'), '', true, '&amp;', true), $lastmod);
132
        //dbglog($event->data ['items'],
133
        //  "Added a new SitemapItem object that points to the KML of public geocoded pages.");
134
    }
135
136
    /**
137
     * Create a spatial sitemap or attach the geo/kml map to the sitemap.
138
     *
139
     * @param Doku_Event $event
140
     *          event object by reference, not used
141
     * @param mixed      $param
142
     *          parameter array, not used
143
     */
144
    public function handleSitemapGenerateAfter(Doku_Event $event, $param) {
145
        // $event→data['items']: Array of SitemapItem instances, the array of sitemap items that already
146
        //      contains all public pages of the wiki
147
        // $event→data['sitemap']: The path of the file the sitemap will be saved to.
148
        if($helper = &plugin_load('helper', 'spatialhelper_sitemap')) {
149
            // dbglog($helper, "createSpatialSitemap loaded helper.");
150
151
            $kml = $helper->createKMLSitemap($this->getConf('media_kml'));
152
            $rss = $helper->createGeoRSSSitemap($this->getConf('media_georss'));
153
154
            if(!empty ($this->getConf('sitemap_namespaces'))) {
155
                $namespaces = array_map('trim', explode("\n", $this->getConf('sitemap_namespaces')));
156
                foreach($namespaces as $namespace) {
157
                    $kmlN = $helper->createKMLSitemap($namespace . $this->getConf('media_kml'));
158
                    $rssN = $helper->createGeoRSSSitemap($namespace . $this->getConf('media_georss'));
159
                    dbglog(
160
                        $kmlN && $rssN,
161
                        "handleSitemapGenerateAfter, created KML / GeoRSS sitemap in $namespace, succes: "
162
                    );
163
                }
164
            }
165
            return $kml && $rss;
166
        } else {
167
            dbglog($helper, "createSpatialSitemap NOT loaded helper.");
168
        }
169
    }
170
171
    /**
172
     * trap findnearby action.
173
     * This addional handler is required as described at: https://www.dokuwiki.org/devel:event:tpl_act_unknown
174
     *
175
     * @param Doku_Event $event
176
     *          event object by reference
177
     * @param mixed      $param
178
     *          not used
179
     */
180
    public function handleActionActPreprocess(Doku_Event $event, $param) {
181
        if($event->data != 'findnearby') {
182
            return;
183
        }
184
        $event->preventDefault();
185
    }
186
187
    /**
188
     * handle findnearby action.
189
     *
190
     * @param Doku_Event $event
191
     *          event object by reference
192
     * @param mixed      $param
193
     *          associative array with keys
194
     *          'format'=> HTML | JSON
195
     */
196
    public function findnearby(Doku_Event &$event, $param) {
197
        if($event->data != 'findnearby') {
198
            return;
199
        }
200
        $event->preventDefault();
201
202
        global $INPUT;
203
        if($helper = &plugin_load('helper', 'spatialhelper_search')) {
204
            if($INPUT->has('lat') && $INPUT->has('lon')) {
205
                $results = $helper->findNearbyLatLon($INPUT->param('lat'), $INPUT->param('lon'));
206
            } elseif($INPUT->has('geohash')) {
207
                $results = $helper->findNearby($INPUT->str('geohash'));
208
            } else {
209
                $results = array(
210
                    'error' => hsc($this->getLang('invalidinput'))
211
                );
212
            }
213
        }
214
215
        $showMedia = $INPUT->bool('showMedia', true);
216
217
        switch($param['format']) {
218
            case 'JSON' :
219
                $this->printJSON($results);
0 ignored issues
show
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...
220
                break;
221
            case 'HTML' :
222
                // fall through to default
223
            default :
224
                $this->printHTML($results, $showMedia);
225
                break;
226
        }
227
    }
228
229
    /**
230
     * Print seachresults as HTML lists.
231
     *
232
     * @param array $searchresults
233
     */
234
    private function printJSON($searchresults) {
235
        require_once DOKU_INC . 'inc/JSON.php';
236
        $json = new JSON();
237
        header('Content-Type: application/json');
238
        print $json->encode($searchresults);
239
    }
240
241
    /**
242
     * Print seachresults as HTML lists.
243
     *
244
     * @param array   $searchresults
245
     * @param boolean $showMedia
246
     */
247
    private function printHTML($searchresults, $showMedia = true) {
248
        $pages   = (array) ($searchresults ['pages']);
249
        $media   = (array) $searchresults ['media'];
250
        $lat     = (float) $searchresults ['lat'];
251
        $lon     = (float) $searchresults ['lon'];
252
        $geohash = (string) $searchresults ['geohash'];
253
254
        if(isset ($searchresults ['error'])) {
255
            print '<div class="level1"><p>' . hsc($results ['error']) . '</p></div>';
0 ignored issues
show
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...
256
            return;
257
        }
258
259
        // print a HTML list
260
        print '<h1>' . $this->getLang('results_header') . '</h1>' . DOKU_LF;
261
        print '<div class="level1">' . DOKU_LF;
262
        if(!empty ($pages)) {
263
            $pagelist = '<ol>' . DOKU_LF;
264
            foreach($pages as $page) {
265
                $pagelist .= '<li>' . html_wikilink(
266
                        ':' . $page ['id'], useHeading('navigation') ? null :
267
                        noNS($page ['id'])
268
                    ) . ' (' . $this->getLang('results_distance_prefix')
269
                    . $page ['distance'] . '&nbsp;m) ' . $page ['description'] . '</li>' . DOKU_LF;
270
            }
271
            $pagelist .= '</ol>' . DOKU_LF;
272
273
            print '<h2>' . $this->getLang('results_pages') . hsc(
274
                    ' lat;lon: ' . $lat . ';' . $lon
275
                    . ' (geohash: ' . $geohash . ')'
276
                ) . '</h2>';
277
            print '<div class="level2">' . DOKU_LF;
278
            print $pagelist;
279
            print '</div>' . DOKU_LF;
280
        } else {
281
            print '<p>' . hsc($this->getLang('nothingfound')) . '</p>';
282
        }
283
284
        if(!empty ($media) && $showMedia) {
285
            $pagelist = '<ol>' . DOKU_LF;
286
            foreach($media as $m) {
287
                $opts       = array();
288
                $link       = ml($m ['id'], $opts, false, '&amp;', false);
289
                $opts ['w'] = '100';
290
                $src        = ml($m ['id'], $opts);
291
                $pagelist   .= '<li><a href="' . $link . '"><img src="' . $src . '"></a> ('
292
                    . $this->getLang('results_distance_prefix') . $page ['distance'] . '&nbsp;m) ' . hsc($desc)
0 ignored issues
show
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...
The variable $page seems to be defined by a foreach iteration on line 264. 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...
293
                    . '</li>' . DOKU_LF;
294
            }
295
            $pagelist .= '</ol>' . DOKU_LF;
296
297
            print '<h2>' . $this->getLang('results_media') . hsc(
298
                    ' lat;lon: ' . $lat . ';' . $lon
299
                    . ' (geohash: ' . $geohash . ')'
300
                ) . '</h2>' . DOKU_LF;
301
            print '<div class="level2">' . DOKU_LF;
302
            print $pagelist;
303
            print '</div>' . DOKU_LF;
304
        }
305
        print '<p>' . $this->getLang('results_precision') . $searchresults ['precision'] . ' m. ';
306
        if(strlen($geohash) > 1) {
307
            $url = wl(
308
                getID(), array(
309
                'do'      => 'findnearby',
310
                'geohash' => substr($geohash, 0, -1)
311
            )
312
            );
313
            print '<a href="' . $url . '" class="findnearby">' . $this->getLang('search_largerarea') . '</a>.</p>'
314
                . DOKU_LF;
315
        }
316
        print '</div>' . DOKU_LF;
317
    }
318
319
    /**
320
     * add media to spatial index.
321
     *
322
     * @param Doku_Event $event
323
     *          event object by reference
324
     * @param unknown    $param
325
     */
326
    public function handleMediaUploaded(Doku_Event &$event, $param) {
327
        // data[0] temporary file name (read from $_FILES)
328
        // data[1] file name of the file being uploaded
329
        // data[2] future directory id of the file being uploaded
330
        // data[3] the mime type of the file being uploaded
331
        // data[4] true if the uploaded file exists already
332
        // data[5] (since 2011-02-06) the PHP function used to move the file to the correct location
333
334
        dbglog($event->data, "handleMediaUploaded::event data");
335
336
        // check the list of mimetypes
337
        // if it's a supported type call appropriate index function
338
        if(substr_compare($event->data [3], 'image/jpeg', 0)) {
339
            $indexer = plugin_load('helper', 'spatialhelper_index');
340
            if($indexer) {
341
                $indexer->indexImage($event->data [2], $event->data [1]);
342
            }
343
        }
344
        // TODO add image/tiff
345
        // TODO kml, gpx, geojson...
346
    }
347
348
    /**
349
     * removes the media from the index.
350
     */
351
    public function handleMediaDeleted(Doku_Event &$event, $param) {
352
        // data['id'] ID data['unl'] unlink return code
353
        // data['del'] Namespace directory unlink return code
354
        // data['name'] file name data['path'] full path to the file
355
        // data['size'] file size
356
357
        dbglog($event->data, "handleMediaDeleted::event data");
358
359
        // remove the media id from the index
360
        $indexer = &plugin_load('helper', 'spatialhelper_index');
361
        if($indexer) {
362
            $indexer->deleteFromIndex('media__' . $event->data ['id']);
363
        }
364
    }
365
366
    /**
367
     * add a link to the spatial sitemap files in the header.
368
     *
369
     * @param Doku_Event   $event
370
     *          the DokuWiki event. $event->data is a two-dimensional
371
     *          array of all meta headers. The keys are meta, link and script.
372
     * @param unknown_type $param
373
     *
374
     * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output
375
     */
376
    public function handleMetaheaderOutput(Doku_Event $event, $param) {
377
        // TODO maybe test for exist
378
        $event->data ["link"] [] = array(
379
            "type"  => "application/atom+xml",
380
            "rel"   => "alternate",
381
            "href"  => ml($this->getConf('media_georss')),
382
            "title" => "Spatial ATOM Feed"
383
        );
384
        $event->data ["link"] [] = array(
385
            "type"  => "application/vnd.google-earth.kml+xml",
386
            "rel"   => "alternate",
387
            "href"  => ml($this->getConf('media_kml')),
388
            "title" => "KML Sitemap"
389
        );
390
    }
391
392
    /**
393
     * Calculate a new coordinate based on start, distance and bearing
394
     *
395
     * @param $start array
396
     *               - start coordinate as decimal lat/lon pair
397
     * @param $dist  float
398
     *               - distance in kilometers
399
     * @param $brng  float
400
     *               - bearing in degrees (compass direction)
401
     */
402
    private function geoDestination($start, $dist, $brng) {
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
403
        $lat1 = toRad($start [0]);
404
        $lon1 = toRad($start [1]);
405
        // http://en.wikipedia.org/wiki/Earth_radius
406
        // average earth radius in km
407
        $dist = $dist / 6371.01;
408
        $brng = toRad($brng);
409
410
        $lon2 = $lon1 + atan2(sin($brng) * sin($dist) * cos($lat1), cos($dist) - sin($lat1) * sin($lat2));
0 ignored issues
show
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...
411
        $lon2 = fmod(($lon2 + 3 * pi()), (2 * pi())) - pi();
412
413
        return array(
414
            toDeg($lat2),
415
            toDeg($lon2)
416
        );
417
    }
418
419
    private function toRad($deg) {
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
420
        return $deg * pi() / 180;
421
    }
422
423
    private function toDeg($rad) {
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
424
        return $rad * 180 / pi();
425
    }
426
}
427