Completed
Push — master ( 310e09...3a0f7f )
by Mark
03:14 queued 01:35
created

action.php (2 issues)

Severity

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