Common   F
last analyzed

Complexity

Total Complexity 203

Size/Duplication

Total Lines 915
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 915
rs 1.685
c 0
b 0
f 0
wmc 203
lcom 0
cbo 2

38 Methods

Rating   Name   Duplication   Size   Complexity  
F getData() 0 79 25
A curlResponseHeaderCallback() 0 7 2
B download() 0 27 11
B gunzip() 0 20 7
A bunzip2() 0 19 6
B table2array() 0 31 7
A text2array() 0 12 3
B distance() 0 15 8
A plunge() 0 11 1
A azimuth() 0 7 2
A withinThreshold() 0 8 5
A isAssoc() 0 4 1
A isInteger() 0 4 2
A convertDec() 0 10 2
B convertDecLatLong() 0 22 6
A convertDM() 0 14 4
A convertDMS() 0 15 4
A xcopy() 0 9 2
A urlexist() 0 4 2
A hex2str() 0 6 2
A hex2rgb() 0 4 1
A getHeading() 0 16 3
A checkLine() 0 9 3
A array_merge_noappend() 0 10 4
A arr_diff() 0 8 3
A multiKeyExists() 0 15 5
B listLocaleDir() 0 17 7
A nextcoord() 0 15 2
A getCoordfromDistanceBearing() 0 26 1
A gzCompressFile() 0 21 5
B remove_accents() 0 101 2
B str2int() 0 11 7
A create_socket() 0 13 5
A create_socket_udp() 0 12 4
A getUserIP() 0 5 3
A replace_mb_substr() 0 10 2
A is__writable() 0 19 5
F greatcircle() 0 123 39

How to fix   Complexity   

Complex Class

Complex classes like Common often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Common, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This class is part of FlightAirmap. It's used for all common functions
4
 *
5
 * Copyright (c) Ycarus (Yannick Chabanois) <[email protected]>
6
 * Licensed under AGPL license.
7
 * For more information see: https://www.flightairmap.com/
8
*/
9
require_once(dirname(__FILE__).'/libs/simple_html_dom.php');
10
require_once(dirname(__FILE__).'/libs/uagent/uagent.php');
11
require_once(dirname(__FILE__).'/settings.php');
12
13
class Common {
14
	//protected $cookies = array();
15
	
16
	/**
17
	* Get data from form result
18
	* @param String $url form URL
19
	* @param String $type type of submit form method (get or post)
20
	* @param String|array $data values form post method
21
	* @param array $headers header to submit with the form
22
	* @return String the result
23
	*/
24
	public function getData($url, $type = 'get', $data = '', $headers = '',$cookie = '',$referer = '',$timeout = '',$useragent = '', $sizelimit = false, $async = false, $getheaders = false) {
25
		global $globalProxy, $globalForceIPv4;
26
		$ch = curl_init();
27
		curl_setopt($ch, CURLOPT_URL, $url);
28
		if (isset($globalForceIPv4) && $globalForceIPv4) {
29
			if (defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')){
30
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
31
			}
32
		}
33
		if (isset($globalProxy) && $globalProxy != '') {
34
			curl_setopt($ch, CURLOPT_PROXY, $globalProxy);
35
		}
36
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
37
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
38
		curl_setopt($ch, CURLINFO_HEADER_OUT, true); 
39
		if ($getheaders) curl_setopt($ch, CURLOPT_HEADER, 1); 
40
		curl_setopt($ch,CURLOPT_ENCODING , "gzip");
41
		//curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB5');
42
//		curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0');
43
		if ($useragent == '') {
44
			curl_setopt($ch, CURLOPT_USERAGENT, UAgent::random());
45
		} else {
46
			curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
47
		}
48
		if ($timeout == '') curl_setopt($ch, CURLOPT_TIMEOUT, 10); 
49
		else curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); 
50
		//curl_setopt($ch, CURLOPT_HEADERFUNCTION, array('Common',"curlResponseHeaderCallback"));
51
		if ($type == 'post') {
52
			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
53
			if (is_array($data)) {
54
				curl_setopt($ch, CURLOPT_POST, count($data));
55
				$data_string = '';
56
				foreach($data as $key=>$value) { $data_string .= $key.'='.$value.'&'; }
57
				rtrim($data_string, '&');
58
				curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
59
			} else {
60
				curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
61
			}
62
		} elseif ($type != 'get' && $type != '') curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type);
63
		if ($headers != '') {
64
			curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
65
		}
66
		if ($cookie != '') {
67
			if (is_array($cookie)) {
68
				curl_setopt($ch, CURLOPT_COOKIE, implode($cookie,';'));
69
			} else {
70
				curl_setopt($ch, CURLOPT_COOKIE, $cookie);
71
			}
72
		}
73
		if ($referer != '') {
74
			curl_setopt($ch, CURLOPT_REFERER, $referer);
75
		}
76
		if ($sizelimit === true) {
77
			curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
78
			curl_setopt($ch, CURLOPT_NOPROGRESS, false);
79
			curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function($curlr,$downloadsize, $downloaded, $uploadsize, $uploaded){
0 ignored issues
show
Unused Code introduced by
The parameter $uploadsize is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $uploaded is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
80
				return ($downloaded > (3*1024)) ? 1 : 0;
81
			});
82
		}
83
		if ($async) {
84
			curl_setopt($ch, CURLOPT_NOSIGNAL, 1); //to timeout immediately if the value is < 1000 ms
85
			curl_setopt($ch, CURLOPT_TIMEOUT_MS, 50);
86
		}
87
		$result = curl_exec($ch);
88
		$info = curl_getinfo($ch);
89
		//var_dump($info);
90
		curl_close($ch);
91
		if ($info['http_code'] == '503' && strstr($result,'DDoS protection by CloudFlare')) {
92
			echo "Cloudflare Detected\n";
93
			require_once(dirname(__FILE__).'/libs/cloudflare-bypass/libraries/cloudflareClass.php');
94
			$useragent = UAgent::random();
95
			cloudflare::useUserAgent($useragent);
96
			if ($clearanceCookie = cloudflare::bypass($url)) {
97
				return $this->getData($url,'get',$data,$headers,$clearanceCookie,$referer,$timeout,$useragent);
98
			}
99
		} else {
100
			return $result;
101
		}
102
	}
103
	
104
	private function curlResponseHeaderCallback($ch, $headerLine) {
0 ignored issues
show
Unused Code introduced by
The parameter $ch is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
105
		global $curl_cookies;
106
		$curl_cookies = array();
107
		if (preg_match('/^Set-Cookie:\s*([^;]*)/mi', $headerLine, $cookie) == 1)
108
			$curl_cookies[] = $cookie;
109
		return strlen($headerLine); // Needed by curl
110
	}
111
112
113
	public static function download($url, $file, $referer = '', $headers = '') {
114
		global $globalDebug, $globalProxy, $globalForceIPv4;
115
		$fp = fopen($file, 'w');
116
		$ch = curl_init();
117
		curl_setopt($ch, CURLOPT_URL, $url);
118
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
119
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
120
		curl_setopt($ch, CURLOPT_COOKIEFILE, '');
121
		if ($referer != '') curl_setopt($ch, CURLOPT_REFERER, $referer);
122
		if (isset($globalForceIPv4) && $globalForceIPv4) {
123
			if (defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')){
124
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
125
			}
126
		}
127
		if ($headers != '') {
128
			curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
129
		}
130
		if (isset($globalProxy) && $globalProxy != '') {
131
			curl_setopt($ch, CURLOPT_PROXY, $globalProxy);
132
		}
133
		curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB5');
134
		curl_setopt($ch, CURLOPT_FILE, $fp);
135
		curl_exec($ch);
136
		if (curl_errno($ch) && $globalDebug) echo 'Download error: '.curl_error($ch);
137
		curl_close($ch);
138
		fclose($fp);
139
	}
140
141
	public static function gunzip($in_file,$out_file_name = '') {
142
		//echo $in_file.' -> '.$out_file_name."\n";
143
		$buffer_size = 4096; // read 4kb at a time
144
		if ($out_file_name == '') $out_file_name = str_replace('.gz', '', $in_file); 
145
		if ($in_file != '' && file_exists($in_file)) {
146
			// PHP version of Ubuntu use gzopen64 instead of gzopen
147
			if (function_exists('gzopen')) $file = gzopen($in_file,'rb');
148
			elseif (function_exists('gzopen64')) $file = gzopen64($in_file,'rb');
149
			else {
150
				echo 'gzopen not available';
151
				die;
152
			}
153
			$out_file = fopen($out_file_name, 'wb'); 
154
			while(!gzeof($file)) {
155
				fwrite($out_file, gzread($file, $buffer_size));
156
			}  
157
			fclose($out_file);
158
			gzclose($file);
159
		}
160
	}
161
162
	public static function bunzip2($in_file,$out_file_name = '') {
163
		//echo $in_file.' -> '.$out_file_name."\n";
164
		$buffer_size = 4096; // read 4kb at a time
165
		if ($out_file_name == '') $out_file_name = str_replace('.bz2', '', $in_file); 
166
		if ($in_file != '' && file_exists($in_file)) {
167
			// PHP version of Ubuntu use gzopen64 instead of gzopen
168
			if (function_exists('bzopen')) $file = bzopen($in_file,'rb');
169
			else {
170
				echo 'bzopen not available';
171
				die;
172
			}
173
			$out_file = fopen($out_file_name, 'wb'); 
174
			while(!feof($file)) {
175
				fwrite($out_file, bzread($file, $buffer_size));
176
			}  
177
			fclose($out_file);
178
			bzclose($file);
179
		}
180
	}
181
182
	/**
183
	* Convert a HTML table to an array
184
	* @param String $data HTML page
185
	* @return array array of the tables in HTML page
186
	*/
187
	public function table2array($data) {
188
		if (!is_string($data)) return array();
189
		if ($data == '') return array();
190
		$html = str_get_html($data);
191
		if ($html === false) return array();
192
		$tabledata=array();
193
		foreach($html->find('tr') as $element)
194
		{
195
			$td = array();
196
			foreach( $element->find('th') as $row)
197
			{
198
				$td [] = trim($row->plaintext);
199
			}
200
			$td=array_filter($td);
201
			$tabledata[] = $td;
202
203
			$td = array();
204
			$tdi = array();
205
			foreach( $element->find('td') as $row)
206
			{
207
				$td [] = trim($row->plaintext);
208
				$tdi [] = trim($row->innertext);
209
			}
210
			$td=array_filter($td);
211
			$tdi=array_filter($tdi);
212
			$tabledata[]=array_merge($td,$tdi);
213
		}
214
		$html->clear();
215
		unset($html);
216
		return(array_filter($tabledata));
217
	}
218
	
219
	/**
220
	* Convert <p> part of a HTML page to an array
221
	* @param String $data HTML page
222
	* @return array array of the <p> in HTML page
223
	*/
224
	public function text2array($data) {
225
		$html = str_get_html($data);
226
		if ($html === false) return array();
227
		$tabledata=array();
228
		foreach($html->find('p') as $element)
229
		{
230
			$tabledata [] = trim($element->plaintext);
231
		}
232
		$html->clear();
233
		unset($html);
234
		return(array_filter($tabledata));
235
	}
236
237
	/**
238
	* Give distance between 2 coordonnates
239
	* @param Float $lat latitude of first point
240
	* @param Float $lon longitude of first point
241
	* @param Float $latc latitude of second point
242
	* @param Float $lonc longitude of second point
243
	* @param String $unit km else no unit used
244
	* @return Float Distance in $unit
245
	*/
246
	public function distance($lat, $lon, $latc, $lonc, $unit = 'km') {
247
		if ($lat == $latc && $lon == $lonc) return 0;
248
		$dist = rad2deg(acos(sin(deg2rad(floatval($lat)))*sin(deg2rad(floatval($latc)))+ cos(deg2rad(floatval($lat)))*cos(deg2rad(floatval($latc)))*cos(deg2rad(floatval($lon)-floatval($lonc)))))*60*1.1515;
249
		if ($unit == "km") {
250
			return round($dist * 1.609344);
251
		} elseif ($unit == "m") {
252
			return round($dist * 1.609344 * 1000);
253
		} elseif ($unit == "mile" || $unit == "mi") {
254
			return round($dist);
255
		} elseif ($unit == "nm") {
256
			return round($dist*0.868976);
257
		} else {
258
			return round($dist);
259
		}
260
	}
261
262
	/**
263
	* Give plunge between 2 altitudes and distance
264
	* @param Float $initial_altitude altitude of first point in m
265
	* @param Float $final_altitude altitude of second point in m
266
	* @param String $distance distance between two points in m
267
	* @return Float plunge
268
	*/
269
	public function plunge($initial_altitude,$final_altitude,$distance) {
270
		$plunge = rad2deg(asin(($final_altitude-$initial_altitude)/$distance));
271
		/*
272
		$siter = 6378137.0 + $initial_altitude;
273
		$planer = 6378137.0 + $final_altitude;
274
		$airdist = sqrt($siter-$siter + $planer*$planer - 2*$siter*$planer*cos($distance/6378137.0));
275
		echo 'airdist:'.$airdist;
276
		$plunge = rad2deg(asin(($planer*$planer - $siter*$siter - $airdist*$airdist)/(2*$siter+$distance)));
277
		*/
278
		return $plunge;
279
	}
280
281
	/**
282
	* Give azimuth between 2 coordonnates
283
	* @param Float $lat latitude of first point
284
	* @param Float $lon longitude of first point
285
	* @param Float $latc latitude of second point
286
	* @param Float $lonc longitude of second point
287
	* @return Float Azimuth
288
	*/
289
	public function azimuth($lat, $lon, $latc, $lonc) {
290
		$dX = $latc - $lat;
291
		$dY = $lonc - $lon;
292
		$azimuth = rad2deg(atan2($dY,$dX));
293
		if ($azimuth < 0) return $azimuth+360;
294
		return $azimuth;
295
	}
296
	
297
	
298
	/**
299
	* Check is distance realistic
300
	* @param int $timeDifference the time between the reception of both messages
301
	* @param float $distance distance covered
302
	* @return bool whether distance is realistic
303
	*/
304
	public function withinThreshold ($timeDifference, $distance) {
305
		$x = abs($timeDifference);
306
		$d = abs($distance);
307
		if ($x == 0 || $d == 0) return true;
308
		// may be due to Internet jitter; distance is realistic
309
		if ($x < 0.7 && $d < 2000) return true;
310
		else return $d/$x < 1500*0.27778; // 1500 km/h max
311
	}
312
313
314
	// Check if an array is assoc
315
	public function isAssoc($array)
316
	{
317
		return ($array !== array_values($array));
318
	}
319
320
	public function isInteger($input){
321
		//return(ctype_digit(strval($input)));
322
		return preg_match('/^-?[0-9]+$/', (string)$input) ? true : false;
323
	}
324
325
326
	public function convertDec($dms,$latlong) {
327
		if ($latlong == 'latitude') {
328
			$deg = substr($dms, 0, 2);
329
			$min = substr($dms, 2, 4);
330
		} else {
331
			$deg = substr($dms, 0, 3);
332
			$min = substr($dms, 3, 5);
333
		}
334
		return $deg+(($min*60)/3600);
335
	}
336
	
337
	public function convertDecLatLong($coord) {
338
		//N43°36.763' W5°46.845'
339
		$coords = explode(' ',$coord);
340
		$latitude = '';
341
		$longitude = '';
342
		foreach ($coords as $latlong) {
343
			$type = substr($latlong,0,1);
344
			$degmin = explode('°',substr($latlong,1,-1));
345
			$deg = $degmin[0];
346
			$min = $degmin[1];
347
			if ($type == 'N') {
348
				$latitude = $deg+(($min*60)/3600);
349
			} elseif ($type == 'S') {
350
				$latitude = -($deg+(($min*60)/3600));
351
			} elseif ($type == 'E') {
352
				$longitude = ($deg+(($min*60)/3600));
353
			} elseif ($type == 'W') {
354
				$longitude = -($deg+(($min*60)/3600));
355
			}
356
		}
357
		return array('latitude' => round($latitude,5),'longitude' => round($longitude,5));
358
	}
359
	
360
	public function convertDM($coord,$latlong) {
361
		if ($latlong == 'latitude') {
362
			if ($coord < 0) $NSEW = 'S';
363
			else $NSEW = 'N';
364
		} else {
365
			if ($coord < 0) $NSEW = 'W';
366
			else $NSEW = 'E';
367
		}
368
		$coord = abs($coord);
369
		$deg = floor($coord);
370
		$coord = ($coord-$deg)*60;
371
		$min = $coord;
372
		return array('deg' => $deg,'min' => $min,'NSEW' => $NSEW);
373
	}
374
	public function convertDMS($coord,$latlong) {
375
		if ($latlong == 'latitude') {
376
			if ($coord < 0) $NSEW = 'S';
377
			else $NSEW = 'N';
378
		} else {
379
			if ($coord < 0) $NSEW = 'W';
380
			else $NSEW = 'E';
381
		}
382
		$coord = abs($coord);
383
		$deg = floor($coord);
384
		$coord = ($coord-$deg)*60;
385
		$min = floor($coord);
386
		$sec = round(($coord-$min)*60);
387
		return array('deg' => $deg,'min' => $min,'sec' => $sec,'NSEW' => $NSEW);
388
	}
389
	
390
	/**
391
	* Copy folder contents
392
	* @param       string   $source    Source path
393
	* @param       string   $dest      Destination path
394
	* @return      bool     Returns true on success, false on failure
395
	*/
396
	public function xcopy($source, $dest)
397
	{
398
		$files = glob($source.'*.*');
399
		foreach($files as $file){
400
			$file_to_go = str_replace($source,$dest,$file);
401
			copy($file, $file_to_go);
402
		}
403
		return true;
404
	}
405
	
406
	/**
407
	* Check if an url exist
408
	* @param	String $url url to check
409
	* @return	bool Return true on succes false on failure
410
	*/
411
	public function urlexist($url){
412
		$headers=get_headers($url);
413
		return stripos($headers[0],"200 OK")?true:false;
414
	}
415
	
416
	/**
417
	* Convert hexa to string
418
	* @param	String $hex data in hexa
419
	* @return	String Return result
420
	*/
421
	public function hex2str($hex) {
422
		$str = '';
423
		$hexln = strlen($hex);
424
		for($i=0;$i<$hexln;$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
425
		return $str;
426
	}
427
	
428
	/**
429
	* Convert hexa color to rgb
430
	* @param	String $hex data in hexa
431
	* @return	String Return result
432
	*/
433
	public function hex2rgb($hex) {
434
		$hex = str_replace('#','',$hex);
435
		return sscanf($hex, "%02x%02x%02x"); 
436
	}
437
	
438
	public function getHeading($lat1, $lon1, $lat2, $lon2) {
439
		//difference in longitudinal coordinates
440
		$dLon = deg2rad($lon2) - deg2rad($lon1);
441
		//difference in the phi of latitudinal coordinates
442
		$dPhi = log(tan(deg2rad($lat2) / 2 + M_PI / 4) / tan(deg2rad($lat1) / 2 + M_PI / 4));
443
		//we need to recalculate $dLon if it is greater than pi
444
		if(abs($dLon) > M_PI) {
445
			if($dLon > 0) {
446
				$dLon = (2 * M_PI - $dLon) * -1;
447
			} else {
448
				$dLon = 2 * M_PI + $dLon;
449
			}
450
		}
451
		//return the angle, normalized
452
		return (rad2deg(atan2($dLon, $dPhi)) + 360) % 360;
453
	}
454
455
	public function checkLine($lat1,$lon1,$lat2,$lon2,$lat3,$lon3,$approx = 0.15) {
456
		//$a = ($lon2-$lon1)*$lat3+($lat2-$lat1)*$lon3+($lat1*$lon2+$lat2*$lon1);
457
		$a = -($lon2-$lon1);
458
		$b = $lat2 - $lat1;
459
		$c = -($a*$lat1+$b*$lon1);
460
		$d = $a*$lat3+$b*$lon3+$c;
461
		if ($d > -$approx && $d < $approx) return true;
462
		else return false;
463
	}
464
	
465
	public function array_merge_noappend() {
466
		$output = array();
467
		foreach(func_get_args() as $array) {
468
			foreach($array as $key => $value) {
469
				$output[$key] = isset($output[$key]) ?
470
				array_merge($output[$key], $value) : $value;
471
			}
472
		}
473
		return $output;
474
	}
475
	
476
477
	public function arr_diff($arraya, $arrayb) {
478
		foreach ($arraya as $keya => $valuea) {
479
			if (in_array($valuea, $arrayb)) {
480
				unset($arraya[$keya]);
481
			}
482
		}
483
		return $arraya;
484
	}
485
486
	/*
487
	* Check if a key exist in an array
488
	* Come from http://stackoverflow.com/a/19420866
489
	* @param Array array to check
490
	* @param String key to check
491
	* @return Bool true if exist, else false
492
	*/
493
	public function multiKeyExists(array $arr, $key) {
494
		// is in base array?
495
		if (array_key_exists($key, $arr)) {
496
			return true;
497
		}
498
		// check arrays contained in this array
499
		foreach ($arr as $element) {
500
			if (is_array($element)) {
501
				if ($this->multiKeyExists($element, $key)) {
502
					return true;
503
				}
504
			}
505
		}
506
		return false;
507
	}
508
	
509
	/**
510
	* Returns list of available locales
511
	*
512
	* @return array
513
	 */
514
	public function listLocaleDir()
515
	{
516
		$result = array('en');
517
		if (!is_dir('./locale')) {
518
			return $result;
519
		}
520
		$handle = @opendir('./locale');
521
		if ($handle === false) return $result;
522
		while (false !== ($file = readdir($handle))) {
523
			$path = './locale'.'/'.$file.'/LC_MESSAGES/fam.mo';
524
			if ($file != "." && $file != ".." && @file_exists($path)) {
525
				$result[] = $file;
526
			}
527
		}
528
		closedir($handle);
529
		return $result;
530
	}
531
532
	public function nextcoord($latitude, $longitude, $speed, $heading, $archivespeed = 1, $seconds = ''){
533
		global $globalMapRefresh;
534
		if ($seconds == '') {
535
			$distance = ($speed*0.514444*$globalMapRefresh*$archivespeed)/1000;
536
		} else {
537
			$distance = ($speed*0.514444*$seconds*$archivespeed)/1000;
538
		}
539
		$r = 6378;
540
		$latitude = deg2rad($latitude);
541
		$longitude = deg2rad($longitude);
542
		$bearing = deg2rad($heading); 
543
		$latitude2 =  asin( (sin($latitude) * cos($distance/$r)) + (cos($latitude) * sin($distance/$r) * cos($bearing)) );
544
		$longitude2 = $longitude + atan2( sin($bearing)*sin($distance/$r)*cos($latitude), cos($distance/$r)-(sin($latitude)*sin($latitude2)) );
545
		return array('latitude' => number_format(rad2deg($latitude2),5,'.',''),'longitude' => number_format(rad2deg($longitude2),5,'.',''));
546
	}
547
	
548
	public function getCoordfromDistanceBearing($latitude,$longitude,$bearing,$distance) {
549
		// distance in meter
550
		$R = 6378.14;
551
		$latitude1 = $latitude * (M_PI/180);
552
		$longitude1 = $longitude * (M_PI/180);
553
		$brng = $bearing * (M_PI/180);
554
		$d = $distance;
555
556
		$latitude2 = asin(sin($latitude1)*cos($d/$R) + cos($latitude1)*sin($d/$R)*cos($brng));
557
		$longitude2 = $longitude1 + atan2(sin($brng)*sin($d/$R)*cos($latitude1),cos($d/$R)-sin($latitude1)*sin($latitude2));
558
559
		$latitude2 = $latitude2 * (180/M_PI);
560
		$longitude2 = $longitude2 * (180/M_PI);
561
562
		$flat = round ($latitude2,6);
563
		$flong = round ($longitude2,6);
564
/*
565
		$dx = $distance*cos($bearing);
566
		$dy = $distance*sin($bearing);
567
		$dlong = $dx/(111320*cos($latitude));
568
		$dlat = $dy/110540;
569
		$flong = $longitude + $dlong;
570
		$flat = $latitude + $dlat;
571
*/
572
		return array('latitude' => $flat,'longitude' => $flong);
573
	}
574
575
	/**
576
	 * GZIPs a file on disk (appending .gz to the name)
577
	 *
578
	 * From http://stackoverflow.com/questions/6073397/how-do-you-create-a-gz-file-using-php
579
	 * Based on function by Kioob at:
580
	 * http://www.php.net/manual/en/function.gzwrite.php#34955
581
	 * 
582
	 * @param string $source Path to file that should be compressed
583
	 * @param integer $level GZIP compression level (default: 9)
584
	 * @return string New filename (with .gz appended) if success, or false if operation fails
585
	 */
586
	public function gzCompressFile($source, $level = 9){ 
587
		$dest = $source . '.gz'; 
588
		$mode = 'wb' . $level; 
589
		$error = false; 
590
		if ($fp_out = gzopen($dest, $mode)) { 
591
			if ($fp_in = fopen($source,'rb')) { 
592
				while (!feof($fp_in)) 
593
					gzwrite($fp_out, fread($fp_in, 1024 * 512)); 
594
				fclose($fp_in); 
595
			} else {
596
				$error = true; 
597
			}
598
			gzclose($fp_out); 
599
		} else {
600
			$error = true; 
601
		}
602
		if ($error)
603
			return false; 
604
		else
605
			return $dest; 
606
	} 
607
	
608
	public function remove_accents($string) {
609
		if ( !preg_match('/[\x80-\xff]/', $string) ) return $string;
610
		$chars = array(
611
		    // Decompositions for Latin-1 Supplement
612
		    chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
613
		    chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
614
		    chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
615
		    chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
616
		    chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
617
		    chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
618
		    chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
619
		    chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
620
		    chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
621
		    chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
622
		    chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
623
		    chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
624
		    chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
625
		    chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
626
		    chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
627
		    chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
628
		    chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
629
		    chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
630
		    chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
631
		    chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
632
		    chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
633
		    chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
634
		    chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
635
		    chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
636
		    chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
637
		    chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
638
		    chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
639
		    chr(195).chr(191) => 'y',
640
		    // Decompositions for Latin Extended-A
641
		    chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
642
		    chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
643
		    chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
644
		    chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
645
		    chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
646
		    chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
647
		    chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
648
		    chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
649
		    chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
650
		    chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
651
		    chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
652
		    chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
653
		    chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
654
		    chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
655
		    chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
656
		    chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
657
		    chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
658
		    chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
659
		    chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
660
		    chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
661
		    chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
662
		    chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
663
		    chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
664
		    chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
665
		    chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
666
		    chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
667
		    chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
668
		    chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
669
		    chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
670
		    chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
671
		    chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
672
		    chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
673
		    chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
674
		    chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
675
		    chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
676
		    chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
677
		    chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
678
		    chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
679
		    chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
680
		    chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
681
		    chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
682
		    chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
683
		    chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
684
		    chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
685
		    chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
686
		    chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
687
		    chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
688
		    chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
689
		    chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
690
		    chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
691
		    chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
692
		    chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
693
		    chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
694
		    chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
695
		    chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
696
		    chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
697
		    chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
698
		    chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
699
		    chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
700
		    chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
701
		    chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
702
		    chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
703
		    chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
704
		    chr(197).chr(190) => 'z', chr(197).chr(191) => 's'
705
		);
706
		$string = strtr($string, $chars);
707
		return $string;
708
	}
709
	
710
	/*
711
	* Extract int from a string
712
	* Come from http://php.net/manual/fr/function.intval.php comment by michiel ed thalent nl
713
	*
714
	* @param String Input string
715
	* @return Integer integer from the string
716
	*/
717
	public function str2int($string, $concat = false) {
718
		$length = strlen($string);    
719
		for ($i = 0, $int = '', $concat_flag = true; $i < $length; $i++) {
720
			if (is_numeric($string[$i]) && $concat_flag) {
721
				$int .= $string[$i];
722
			} elseif(!$concat && $concat_flag && strlen($int) > 0) {
723
				$concat_flag = false;
724
			}
725
		}
726
		return (int) $int;
727
	}
728
	
729
	public function create_socket($host, $port, &$errno, &$errstr) {
730
		$ip = gethostbyname($host);
731
		$s = socket_create(AF_INET, SOCK_STREAM, 0);
732
		$r = @socket_connect($s, $ip, $port);
733
		if (!socket_set_nonblock($s)) echo "Unable to set nonblock on socket\n";
734
		if ($r || socket_last_error() == 114 || socket_last_error() == 115) {
735
			return $s;
736
		}
737
		$errno = socket_last_error($s);
738
		$errstr = socket_strerror($errno);
739
		socket_close($s);
740
		return false;
741
	}
742
743
	public function create_socket_udp($host, $port, &$errno, &$errstr) {
744
		$ip = gethostbyname($host);
745
		$s = socket_create(AF_INET, SOCK_DGRAM, 0);
746
		$r = @socket_bind($s, $ip, $port);
747
		if ($r || socket_last_error() == 114 || socket_last_error() == 115) {
748
			return $s;
749
		}
750
		$errno = socket_last_error($s);
751
		$errstr = socket_strerror($errno);
752
		socket_close($s);
753
		return false;
754
	}
755
756
	public function getUserIP() { 
757
		$client = @$_SERVER['HTTP_CLIENT_IP'];
758
		$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
759
		return filter_var($client, FILTER_VALIDATE_IP) ? $client : filter_var($forward, FILTER_VALIDATE_IP) ? $forward : $_SERVER['REMOTE_ADDR']; 
760
	}
761
	public function replace_mb_substr($string, $offset, $length)
762
	{
763
		if (!function_exists('mb_substr')) {
764
			$arr = preg_split("//u", $string);
765
			$slice = array_slice($arr, $offset + 1, $length);
766
			return implode("", $slice);
767
		} else {
768
			return mb_substr($string,$offset,$length,'UTF-8');
769
		}
770
	}
771
772
	// Come from comment : http://php.net/manual/fr/function.is-writable.php#73596
773
	public function is__writable($path) {
774
		//will work in despite of Windows ACLs bug
775
		//NOTE: use a trailing slash for folders!!!
776
		//see http://bugs.php.net/bug.php?id=27609
777
		//see http://bugs.php.net/bug.php?id=30931
778
		if ($path{strlen($path)-1}=='/') // recursively return a temporary file path
779
			return $this->is__writable($path.uniqid(mt_rand()).'.tmp');
780
		else if (is_dir($path))
781
			return $this->is__writable($path.'/'.uniqid(mt_rand()).'.tmp');
782
		// check tmp file for read/write capabilities
783
		$rm = file_exists($path);
784
		$f = @fopen($path, 'a');
785
		if ($f===false)
786
			return false;
787
		fclose($f);
788
		if (!$rm)
789
			unlink($path);
790
		return true;
791
	}
792
	
793
	/*
794
	 * Great circle route
795
	 * Translated to PHP from javascript version of https://github.com/springmeyer/arc.js
796
	 * @param Float $begin_lat Latitude of origin point
797
	 * @param Float $begin_lon Longitude of origin point
798
	 * @param Float $end_lat Latitude of final point
799
	 * @param Float $end_lon Longitude of final point
800
	 * @param Integer $nbpts Number of intermediate vertices desired
801
	 * @param Integer $offset Controls the likelyhood that lines will be split which cross the dateline
802
	 * @return Array Coordinate of the route
803
	*/
804
	public function greatcircle($begin_lat,$begin_lon,$end_lat,$end_lon,$nbpts = 20, $offset = 10) {
805
		if ($nbpts <= 2) return array(array($begin_lon,$begin_lat),array($end_lon,$end_lat));
806
		$sx = deg2rad($begin_lon);
807
		$sy = deg2rad($begin_lat);
808
		$ex = deg2rad($end_lon);
809
		$ey = deg2rad($end_lat);
810
		$w = $sx - $ex;
811
		$h = $sy - $ey;
812
		$z = pow(sin($h/2.0),2) + cos($sy)*cos($ey)*pow(sin($w/2.0),2);
813
		$g = 2.0*asin(sqrt($z));
814
		if ($g == M_PI || is_nan($g)) return array(array($begin_lon,$begin_lat),array($end_lon,$end_lat));
815
		$first_pass = array();
816
		$delta = 1.0/($nbpts-1);
817
		for ($i =0; $i < $nbpts; ++$i) {
818
			$step = $delta*$i;
819
			$A = sin((1 - $step) * $g) / sin($g);
820
			$B = sin($step * $g) / sin($g);
821
			$x = $A * cos($sy) * cos($sx) + $B * cos($ey) * cos($ex);
822
			$y = $A * cos($sy) * sin($sx) + $B * cos($ey) * sin($ex);
823
			$z = $A * sin($sy) + $B * sin($ey);
824
			$lat = rad2deg(atan2($z, sqrt(pow($x, 2) + pow($y, 2))));
825
			$lon = rad2deg(atan2($y, $x));
826
			$first_pass[] = array($lon,$lat);
827
		}
828
		$bHasBigDiff = false;
829
		$dfMaxSmallDiffLong = 0;
830
		// from http://www.gdal.org/ogr2ogr.html
831
		// -datelineoffset:
832
		// (starting with GDAL 1.10) offset from dateline in degrees (default long. = +/- 10deg, geometries within 170deg to -170deg will be splited)
833
		$dfDateLineOffset = $offset;
834
		$dfLeftBorderX = 180 - $dfDateLineOffset;
835
		$dfRightBorderX = -180 + $dfDateLineOffset;
836
		$dfDiffSpace = 360 - $dfDateLineOffset;
837
		
838
		// https://github.com/OSGeo/gdal/blob/7bfb9c452a59aac958bff0c8386b891edf8154ca/gdal/ogr/ogrgeometryfactory.cpp#L2342
839
		$first_pass_ln = count($first_pass);
840
		for ($j = 1; $j < $first_pass_ln; ++$j) {
841
			$dfPrevX = $first_pass[$j-1][0];
842
			$dfX = $first_pass[$j][0];
843
			$dfDiffLong = abs($dfX - $dfPrevX);
844
			if ($dfDiffLong > $dfDiffSpace &&
845
			    (($dfX > $dfLeftBorderX && $dfPrevX < $dfRightBorderX) || ($dfPrevX > $dfLeftBorderX && $dfX < $dfRightBorderX))) 
846
			{
847
				$bHasBigDiff = true;
848
			} else if ($dfDiffLong > $dfMaxSmallDiffLong) {
849
				$dfMaxSmallDiffLong = $dfDiffLong;
850
			}
851
		}
852
		$poMulti = array();
853
		$first_pass_ln = count($first_pass);
854
		if ($bHasBigDiff && $dfMaxSmallDiffLong < $dfDateLineOffset) {
855
			$poNewLS = array();
856
			//$poMulti[] = $poNewLS;
857
			for ($k = 0; $k < $first_pass_ln; ++$k) {
858
				$dfX0 = floatval($first_pass[$k][0]);
859
				if ($k > 0 &&  abs($dfX0 - $first_pass[$k-1][0]) > $dfDiffSpace) {
860
					$dfX1 = floatval($first_pass[$k-1][0]);
861
					$dfY1 = floatval($first_pass[$k-1][1]);
862
					$dfX2 = floatval($first_pass[$k][0]);
863
					$dfY2 = floatval($first_pass[$k][1]);
864
					if ($dfX1 > -180 && $dfX1 < $dfRightBorderX && $dfX2 == 180 &&
865
					    $k+1 < count($first_pass) &&
866
					    $first_pass[$k-1][0] > -180 && $first_pass[$k-1][0] < $dfRightBorderX)
867
					{
868
						$poNewLS[] = array(-180, $first_pass[$k][1]);
869
						$k++;
870
						//echo 'here';
871
						$poNewLS[] = array($first_pass[$k][0], $first_pass[$k][1]);
872
						continue;
873
					} else if ($dfX1 > $dfLeftBorderX && $dfX1 < 180 && $dfX2 == -180 &&
874
					    $k+1 < $first_pass_ln &&
875
					    $first_pass[$k-1][0] > $dfLeftBorderX && $first_pass[$k-1][0] < 180)
876
					{
877
						$poNewLS[] = array(180, $first_pass[$k][1]);
878
						$k++;
879
						$poNewLS[] = array($first_pass[$k][0], $first_pass[$k][1]);
880
						continue;
881
					}
882
					if ($dfX1 < $dfRightBorderX && $dfX2 > $dfLeftBorderX)
883
					{
884
						// swap dfX1, dfX2
885
						$tmpX = $dfX1;
886
						$dfX1 = $dfX2;
887
						$dfX2 = $tmpX;
888
						// swap dfY1, dfY2
889
						$tmpY = $dfY1;
890
						$dfY1 = $dfY2;
891
						$dfY2 = $tmpY;
892
					}
893
					if ($dfX1 > $dfLeftBorderX && $dfX2 < $dfRightBorderX) {
894
						$dfX2 += 360;
895
					}
896
					if ($dfX1 <= 180 && $dfX2 >= 180 && $dfX1 < $dfX2)
897
					{
898
						$dfRatio = (180 - $dfX1) / ($dfX2 - $dfX1);
899
						$dfY = $dfRatio * $dfY2 + (1 - $dfRatio) * $dfY1;
900
						$poNewLS[] = array($first_pass[$k-1][0] > $dfLeftBorderX ? 180 : -180, $dfY);
901
						$poMulti[] = $poNewLS;
902
						$poNewLS = array();
903
						$poNewLS[] = array($first_pass[$k-1][0] > $dfLeftBorderX ? -180 : 180, $dfY);
904
						//$poMulti[] = $poNewLS;
905
					} else {
906
						//$poNewLS[] = array();
907
						$poMulti[] = $poNewLS;
908
						$poNewLS = array();
909
					}
910
					$poNewLS[] = array($dfX0, $first_pass[$k][1]);
911
				} else {
912
					$poNewLS[] = array($first_pass[$k][0], $first_pass[$k][1]);
913
				}
914
			}
915
			$poMulti[] = $poNewLS;
916
		} else {
917
			// add normally
918
			$poNewLS0 = array();
919
			//$poMulti[] = $poNewLS0;
920
			for ($l = 0; $l < $first_pass_ln; ++$l) {
921
				$poNewLS0[] = array($first_pass[$l][0],$first_pass[$l][1]);
922
			}
923
			$poMulti[] = $poNewLS0;
924
		}
925
		return $poMulti;
926
	}
927
}
928
?>