Completed
Push — master ( 589edc...c24ce2 )
by Yannick
35:38
created

Common::withinThreshold()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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