Completed
Push — master ( 4d5aa3...8f3dec )
by Mark
11s
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
if (!defined('DOKU_INC')) {
18
	die ();
19
}
20
if (!defined('DOKU_LF')) {
21
	define('DOKU_LF', "\n");
22
}
23
24
use dokuwiki\Sitemap\Item;
25
26
/**
27
 * DokuWiki Plugin dokuwikispatial (Action Component).
28
 *
29
 * @license BSD license
30
 * @author Mark C. Prins <[email protected]>
31
 */
32
class action_plugin_spatialhelper extends DokuWiki_Action_Plugin {
33
34
	/**
35
	 * Register for events.
36
	 *
37
	 * @param Doku_Event_Handler $controller
38
	 *        	DokuWiki's event controller object. Also available as global $EVENT_HANDLER
39
	 */
40
	public function register(Doku_Event_Handler $controller) {
41
		// listen for page add / delete events
42
		// http://www.dokuwiki.org/devel:event:indexer_page_add
43
		$controller->register_hook('INDEXER_PAGE_ADD', 'BEFORE', $this, 'handle_indexer_page_add');
44
		$controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, '_removeFromIndex');
45
46
		// http://www.dokuwiki.org/devel:event:sitemap_generate
47
		$controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handle_sitemap_generate_before');
48
		// using after will only trigger us if a sitemap was actually created
49
		$controller->register_hook('SITEMAP_GENERATE', 'AFTER', $this, 'handle_sitemap_generate_after');
50
51
		// handle actions we know of
52
		$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_action_act_preprocess', array());
53
		// handle HTML eg. /dokuwiki/doku.php?id=start&do=findnearby&geohash=u15vk4
54
		$controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, '_findnearby', array(
55
				'format' => 'HTML'
56
		));
57
		// handles AJAX/json eg: jQuery.post("/dokuwiki/lib/exe/ajax.php?id=start&call=findnearby&geohash=u15vk4");
58
		$controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, '_findnearby', array(
59
				'format' => 'JSON'
60
		));
61
62
		// listen for media uploads and deletes
63
		$controller->register_hook('MEDIA_UPLOAD_FINISH', 'BEFORE', $this, '_handle_media_uploaded', array());
64
		$controller->register_hook('MEDIA_DELETE_FILE', 'BEFORE', $this, '_handle_media_deleted', array());
65
66
		$controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handle_metaheader_output');
67
	}
68
69
	/**
70
	 * Update the spatial index for the page.
71
	 *
72
	 * @param Doku_Event $event
73
	 *        	event object by reference
74
	 * @param object $param
75
	 *        	the parameters passed to register_hook when this handler was registered
76
	 */
77
	public function handle_indexer_page_add(Doku_Event $event, $param) {
78
		// $event→data['page'] – the page id
79
		// $event→data['body'] – empty, can be filled by additional content to index by your plugin
80
		// $event→data['metadata'] – the metadata that shall be indexed. This is an array where the keys are the metadata indexes and the value a string or an array of strings with the values. 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 handle_sitemap_generate_before(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'], "Added a new SitemapItem object that points to the KML of public geocoded pages.");
133
	}
134
135
	/**
136
	 * Create a spatial sitemap or attach the geo/kml map to the sitemap.
137
	 *
138
	 * @param Doku_Event $event
139
	 *        	event object by reference, not used
140
	 * @param mixed $param
141
	 *        	parameter array, not used
142
	 */
143
	public function handle_sitemap_generate_after(Doku_Event $event, $param) {
144
		// $event→data['items']: Array of SitemapItem instances, the array of sitemap items that already contains all public pages of the wiki
145
		// $event→data['sitemap']: The path of the file the sitemap will be saved to.
146
		if ($helper = & plugin_load('helper', 'spatialhelper_sitemap')) {
147
			// dbglog($helper, "createSpatialSitemap loaded helper.");
148
149
			$kml = $helper->createKMLSitemap($this->getConf('media_kml'));
150
			$rss = $helper->createGeoRSSSitemap($this->getConf('media_georss'));
151
			
152
			if (!empty ($this->getConf('sitemap_namespaces'))) {
153
				$namespaces = array_map('trim', explode("\n", $this->getConf('sitemap_namespaces')));
154
				foreach ($namespaces as $namespace) {
155
					$kmlN = $helper->createKMLSitemap($namespace . $this->getConf('media_kml'));
156
					$rssN = $helper->createGeoRSSSitemap($namespace . $this->getConf('media_georss'));
157
					dbglog($kmlN && $rssN, "handle_sitemap_generate_after, created KML / GeoRSS sitemap in $namespace, succes: ");
158
				}  
159
			}
160
			return $kml && $rss;
161
		} else {
162
			dbglog($helper, "createSpatialSitemap NOT loaded helper.");
163
		}
164
	}
165
166
	/**
167
	 * trap findnearby action.
168
	 * This addional handler is required as described at: https://www.dokuwiki.org/devel:event:tpl_act_unknown
169
	 *
170
	 * @param Doku_Event $event
171
	 *        	event object by reference
172
	 * @param mixed $param
173
	 *        	not used
174
	 */
175
	public function handle_action_act_preprocess(Doku_Event $event, $param) {
176
		if ($event->data != 'findnearby') {
177
					return;
178
		}
179
		$event->preventDefault();
180
	}
181
182
	/**
183
	 * handle findnearby action.
184
	 *
185
	 * @param Doku_Event $event
186
	 *        	event object by reference
187
	 * @param mixed $param
188
	 *        	associative array with keys
189
	 *        	'format'=> HTML | JSON
190
	 */
191
	public function _findnearby(Doku_Event & $event, $param) {
192
		if ($event->data != 'findnearby') {
193
					return;
194
		}
195
		$event->preventDefault();
196
197
		global $INPUT;
198
		if ($helper = & plugin_load('helper', 'spatialhelper_search')) {
199
			if ($INPUT->has('lat') && $INPUT->has('lon')) {
200
				$results = $helper->findNearbyLatLon($INPUT->param('lat'), $INPUT->param('lon'));
201
			} elseif ($INPUT->has('geohash')) {
202
				$results = $helper->findNearby($INPUT->str('geohash'));
203
			} else {
204
				$results = array(
205
						'error' => hsc($this->getLang('invalidinput'))
206
				);
207
			}
208
		}
209
210
		$showMedia = $INPUT->bool('showMedia', true);
211
212
		switch ($param['format']) {
213
			case 'JSON' :
214
				$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...
215
				break;
216
			case 'HTML' :
217
			// fall through to default
218
			default :
219
				$this->printHTML($results, $showMedia);
220
				break;
221
		}
222
	}
223
224
	/**
225
	 * Print seachresults as HTML lists.
226
	 *
227
	 * @param array $searchresults
228
	 */
229
	private function printJSON($searchresults) {
230
		require_once DOKU_INC . 'inc/JSON.php';
231
		$json = new JSON();
232
		header('Content-Type: application/json');
233
		print $json->encode($searchresults);
234
	}
235
236
	/**
237
	 * Print seachresults as HTML lists.
238
	 *
239
	 * @param array $searchresults
240
	 * @param boolean $showMedia
241
	 */
242
	private function printHTML($searchresults, $showMedia = true) {
243
		$pages = ( array ) ($searchresults ['pages']);
244
		$media = ( array ) $searchresults ['media'];
245
		$lat = ( float ) $searchresults ['lat'];
246
		$lon = ( float ) $searchresults ['lon'];
247
		$geohash = ( string ) $searchresults ['geohash'];
248
249
		if (isset ($searchresults ['error'])) {
250
			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...
251
			return;
252
		}
253
254
		// print a HTML list
255
		print '<h1>' . $this->getLang('results_header') . '</h1>' . DOKU_LF;
256
		print '<div class="level1">' . DOKU_LF;
257
		if (!empty ($pages)) {
258
			$pagelist = '<ol>' . DOKU_LF;
259
			foreach ($pages as $page) {
260
				$pagelist .= '<li>' . html_wikilink(':' . $page ['id'], useHeading('navigation') ? null : noNS($page ['id'])) . ' (' . $this->getLang('results_distance_prefix') . $page ['distance'] . '&nbsp;m) ' . $page ['description'] . '</li>' . DOKU_LF;
261
			}
262
			$pagelist .= '</ol>' . DOKU_LF;
263
264
			print '<h2>' . $this->getLang('results_pages') . hsc(' lat;lon: ' . $lat . ';' . $lon . ' (geohash: ' . $geohash . ')') . '</h2>';
265
			print '<div class="level2">' . DOKU_LF;
266
			print $pagelist;
267
			print '</div>' . DOKU_LF;
268
		} else {
269
			print '<p>' . hsc($this->getLang('nothingfound')) . '</p>';
270
		}
271
272
		if (!empty ($media) && $showMedia) {
273
			$pagelist = '<ol>' . DOKU_LF;
274
			foreach ($media as $m) {
275
				$opts = array();
276
				$link = ml($m ['id'], $opts, false, '&amp;', false);
277
				$opts ['w'] = '100';
278
				$src = ml($m ['id'], $opts);
279
				$pagelist .= '<li><a href="' . $link . '"><img src="' . $src . '"></a> (' . $this->getLang('results_distance_prefix') . $page ['distance'] . '&nbsp;m) ' . hsc($desc) . '</li>' . DOKU_LF;
0 ignored issues
show
The variable $page seems to be defined by a foreach iteration on line 259. 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...
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...
280
			}
281
			$pagelist .= '</ol>' . DOKU_LF;
282
283
			print '<h2>' . $this->getLang('results_media') . hsc(' lat;lon: ' . $lat . ';' . $lon . ' (geohash: ' . $geohash . ')') . '</h2>' . DOKU_LF;
284
			print '<div class="level2">' . DOKU_LF;
285
			print $pagelist;
286
			print '</div>' . DOKU_LF;
287
		}
288
		print '<p>' . $this->getLang('results_precision') . $searchresults ['precision'] . ' m. ';
289
		if (strlen($geohash) > 1) {
290
			$url = wl(getID(), array(
291
					'do' => 'findnearby',
292
					'geohash' => substr($geohash, 0, - 1)
293
			));
294
			print '<a href="' . $url . '" class="findnearby">' . $this->getLang('search_largerarea') . '</a>.</p>' . DOKU_LF;
295
		}
296
		print '</div>' . DOKU_LF;
297
	}
298
299
	/**
300
	 * add media to spatial index.
301
	 *
302
	 * @param Doku_Event $event
303
	 *        	event object by reference
304
	 * @param unknown $param
305
	 */
306
	public function _handle_media_uploaded(Doku_Event & $event, $param) {
307
		// data[0] temporary file name (read from $_FILES)
308
		// data[1] file name of the file being uploaded
309
		// data[2] future directory id of the file being uploaded
310
		// data[3] the mime type of the file being uploaded
311
		// data[4] true if the uploaded file exists already
312
		// data[5] (since 2011-02-06) the PHP function used to move the file to the correct location
313
314
		dbglog($event->data, "_handle_media_uploaded::event data");
315
316
		// check the list of mimetypes
317
		// if it's a supported type call appropriate index function
318
		if (substr_compare($event->data [3], 'image/jpeg', 0)) {
319
			$indexer = plugin_load('helper', 'spatialhelper_index');
320
			if ($indexer) {
321
				$indexer->indexImage($event->data [2], $event->data [1]);
322
			}
323
		}
324
		// TODO add image/tiff
325
		// TODO kml, gpx, geojson...
326
	}
327
328
	/**
329
	 * removes the media from the index.
330
	 */
331
	public function _handle_media_deleted(Doku_Event & $event, $param) {
332
		// data['id'] ID data['unl'] unlink return code
333
		// data['del'] Namespace directory unlink return code
334
		// data['name'] file name data['path'] full path to the file
335
		// data['size'] file size
336
337
		dbglog($event->data, "_handle_media_deleted::event data");
338
339
		// remove the media id from the index
340
		$indexer = & plugin_load('helper', 'spatialhelper_index');
341
		if ($indexer) {
342
			$indexer->deleteFromIndex('media__' . $event->data ['id']);
343
		}
344
	}
345
346
	/**
347
	 * add a link to the spatial sitemap files in the header.
348
	 *
349
	 * @param Doku_Event $event
350
	 *        	the DokuWiki event. $event->data is a two-dimensional
351
	 *        	array of all meta headers. The keys are meta, link and script.
352
	 * @param unknown_type $param
353
	 *
354
	 * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output
355
	 */
356
	public function handle_metaheader_output(Doku_Event $event, $param) {
357
		// TODO maybe test for exist
358
		$event->data ["link"] [] = array(
359
				"type" => "application/atom+xml",
360
				"rel" => "alternate",
361
				"href" => ml($this->getConf('media_georss')),
362
				"title" => "Spatial ATOM Feed"
363
		);
364
		$event->data ["link"] [] = array(
365
				"type" => "application/vnd.google-earth.kml+xml",
366
				"rel" => "alternate",
367
				"href" => ml($this->getConf('media_kml')),
368
				"title" => "KML Sitemap"
369
		);
370
	}
371
372
	/**
373
	 * Calculate a new coordinate based on start, distance and bearing
374
	 *
375
	 * @param $start array
376
	 *        	- start coordinate as decimal lat/lon pair
377
	 * @param $dist float
378
	 *        	- distance in kilometers
379
	 * @param $brng float
380
	 *        	- bearing in degrees (compass direction)
381
	 */
382
	private function _geo_destination($start, $dist, $brng) {
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
383
		$lat1 = _toRad($start [0]);
384
		$lon1 = _toRad($start [1]);
385
		// http://en.wikipedia.org/wiki/Earth_radius
386
		// average earth radius in km
387
		$dist = $dist / 6371.01;
388
		$brng = _toRad($brng);
389
390
		$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...
391
		$lon2 = fmod(($lon2 + 3 * pi()), (2 * pi())) - pi();
392
393
		return array(
394
				_toDeg($lat2),
395
				_toDeg($lon2)
396
		);
397
	}
398
	private function _toRad($deg) {
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
399
		return $deg * pi() / 180;
400
	}
401
	private function _toDeg($rad) {
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
402
		return $rad * 180 / pi();
403
	}
404
}
405