Issues (843)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

require/class.METAR.php (1 issue)

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
 * This class is part of FlightAirmap. It's used to download and parse METAR
4
 *
5
 * Copyright (c) Ycarus (Yannick Chabanois) at Zugaina <[email protected]>
6
 * Licensed under AGPL license.
7
 * For more information see: https://www.flightairmap.com/
8
*/
9
require_once(dirname(__FILE__).'/settings.php');
10
require_once(dirname(__FILE__).'/class.Connection.php');
11
require_once(dirname(__FILE__).'/class.Common.php');
12
13
class METAR {
14
	public $db;
15
	
16
	protected $texts = Array(
17
	    'MI' => 'Shallow',
18
	    'PR' => 'Partial',
19
	    'BC' => 'Low drifting',
20
	    'BL' => 'Blowing',
21
	    'SH' => 'Showers',
22
	    'TS' => 'Thunderstorm',
23
	    'FZ' => 'Freezing',
24
	    'DZ' => 'Drizzle',
25
	    'RA' => 'Rain',
26
	    'SN' => 'Snow',
27
	    'SG' => 'Snow Grains',
28
	    'IC' => 'Ice crystals',
29
	    'PL' => 'Ice pellets',
30
	    'GR' => 'Hail',
31
	    'GS' => 'Small hail',
32
	    'UP' => 'Unknown',
33
	    'BR' => 'Mist',
34
	    'FG' => 'Fog',
35
	    'FU' => 'Smoke',
36
	    'VA' => 'Volcanic ash',
37
	    'DU' => 'Widespread dust',
38
	    'SA' => 'Sand',
39
	    'HZ' => 'Haze',
40
	    'PY' => 'Spray',
41
	    'PO' => 'Well developed dust / sand whirls',
42
	    'SQ' => 'Squalls',
43
	    'FC' => 'Funnel clouds inc tornadoes or waterspouts',
44
	    'SS' => 'Sandstorm',
45
	    'DS' => 'Duststorm'
46
	);
47
48
	/*
49
	 * Initialize db connection
50
	*/
51
	public function __construct($dbc = null) {
52
		$Connection = new Connection($dbc);
53
		$this->db = $Connection->db;
54
	}
55
56
	/*
57
	 * Check in config table in DB if METAR was updated more than 20 minutes ago
58
	 * @return Boolean Return true if METAR was updated more than 20 minutes ago
59
	*/
60
	public static function check_last_update() {
61
		global $globalDBdriver;
62
		if ($globalDBdriver == 'mysql') {
63
			$query = "SELECT COUNT(*) as nb FROM config WHERE name = 'last_update_metar' AND value > DATE_SUB(NOW(), INTERVAL 20 MINUTE)";
64
		} else {
65
			$query = "SELECT COUNT(*) as nb FROM config WHERE name = 'last_update_metar' AND value::timestamp > CURRENT_TIMESTAMP - INTERVAL '20 MINUTES'";
66
		}
67
		try {
68
			$Connection = new Connection();
69
			$sth = $Connection->db->prepare($query);
70
			$sth->execute();
71
		} catch(PDOException $e) {
72
			return "error : ".$e->getMessage();
73
		}
74
		$row = $sth->fetch(PDO::FETCH_ASSOC);
75
		$sth->closeCursor();
76
		if ($row['nb'] > 0) return false;
77
		else return true;
78
	}
79
80
	/*
81
	 * Insert METAR update date in config table in DB
82
	*/
83
	public static function insert_last_update() {
84
		$query = "DELETE FROM config WHERE name = 'last_update_metar';
85
		        INSERT INTO config (name,value) VALUES ('last_update_metar',NOW());";
86
		try {
87
			$Connection = new Connection();
88
			$sth = $Connection->db->prepare($query);
89
			$sth->execute();
90
		} catch(PDOException $e) {
91
			return "error : ".$e->getMessage();
92
		}
93
		return '';
94
	}
95
96
	/*
97
	 * Parse METAR
98
	 * @param String $data METAR text
99
	 * @return Array All data in METAR available in an array
100
	*/
101
	public function parse($data) {
102
		//$data = str_replace(array('\n','\r','\r','\n'),'',$data);
103
		$codes = implode('|', array_keys($this->texts));
104
		$regWeather = '#^(\+|\-|VC)?(' . $codes . ')(' . $codes . ')?$#';
105
		//$pieces = explode(' ',$data);
106
		$pieces = preg_split('/\s/',$data);
107
		$pos = 0;
108
		if ($pieces[0] == 'METAR') $pos++;
109
		elseif ($pieces[0] == 'SPECI') $pos++;
110
		if (strlen($pieces[$pos]) != 4) $pos++;
111
		$result = array();
112
		if (!isset($pieces[$pos])) return $result;
113
		$result['location'] = $pieces[$pos];
114
		$pos++;
115
		if (!isset($pieces[$pos])) return $result;
116
		$result['dayofmonth'] = substr($pieces[$pos],0,2);
117
		$result['time'] = substr($pieces[$pos],2,4);
118
		$c = count($pieces);
119
		for($pos++; $pos < $c; $pos++) {
120
			$piece = $pieces[$pos];
121
			if ($piece == 'RMK') break;
122
			if ($piece == 'AUTO') $result['auto'] = true;
123
			if ($piece == 'COR') $result['correction'] = true;
124
			// Wind Speed
125
			if (preg_match('#(VRB|\d\d\d)(\d\d)(?:G(\d\d))?(KT|MPS|KPH)(?: (\d{1,3})V(\d{1,3}))?$#', $piece, $matches)) {
126
				$result['wind']['direction'] = (float)$matches[1];
127
				$result['wind']['unit'] = $matches[4];
128
				if ($result['wind']['unit'] == 'KT') $result['wind']['speed'] = round(((float)$matches[2])*0.51444444444,2);
129
				elseif ($result['wind']['unit'] == 'KPH') $result['wind']['speed'] = round(((float)$matches[2])*1000,2);
130
				elseif ($result['wind']['unit'] == 'MPS') $result['wind']['speed'] = round(((float)$matches[2]),2);
131
				$result['wind']['gust'] = (float)$matches[3];
132
				$result['wind']['unit'] = $matches[4];
133
				$result['wind']['min_variation'] = array_key_exists(5,$matches) ? $matches[5] : 0;
134
				$result['wind']['max_variation'] = array_key_exists(6,$matches) ? $matches[6] : 0;
135
			}
136
137
/*    			if (preg_match('#^([0-9]{3})([0-9]{2})(G([0-9]{2}))?(KT|MPS)$#', $piece, $matches)) {
138
    				$result['wind_direction'] = (float)$matches[1];
139
    				if ($matches[5] == 'KT') {
140
    					$result['speed'] = round(((float)$matches[2])*0.51444444444,2);
141
    				} elseif ($matches[5] == 'KPH') {
142
    					$result['speed'] = round(((float)$matches[2])*1000,2);
143
    				} elseif ($matches[5] == 'MPS') {
144
    					$result['speed'] = round(((float)$matches[2]),2);
145
    				}
146
    				if ($matches[3]) {
147
    				    $result['gust'] = $matches[4];
148
    				    $result['gust_format'] = $matches[5];
149
    				}
150
    			}
151
    			*/
152
153
			// Temperature
154
			if (preg_match('#^(M?[0-9]{2,})/(M?[0-9]{2,})$#', $piece, $matches)) {
155
				$temp = (float)$matches[1];
156
				if ($matches[1]{0} == 'M') {
157
					$temp = ((float)substr($matches[1], 1)) * -1;
158
				}
159
				$result['temperature'] = $temp;
160
				$dew = (float)$matches[2];
161
				if ($matches[2]{0} == 'M') {
162
					$dew = ((float)substr($matches[2], 1)) * -1;
163
				}
164
				$result['dew'] = $dew;
165
				$result['rh'] = round(100*(exp((17.625*$dew)/(243.04+$dew))/exp((17.625*$temp)/(243.04+$temp))));
166
			}
167
			// QNH
168
			if (preg_match('#^(A|Q)([0-9]{4})$#', $piece, $matches)) {
169
			// #^(Q|A)(////|[0-9]{4})( )#
170
				if ($matches[1] == 'Q') {
171
					// hPa
172
					$result['QNH'] = $matches[2];
173
				} else {
174
					// inHg
175
					$result['QNH'] = round(($matches[2] / 100)*33.86389,2);
176
				}
177
				/*
178
    				$result['QNH'] = $matches[1] == 'Q' ? $matches[2] : ($matches[2] / 100);
179
    				$result['QNH_format'] = $matches[1] == 'Q' ? 'hPa' : 'inHg';
180
    				*/
181
			}
182
                     /*
183
    			// Wind Direction
184
    			if (preg_match('#^([0-9]{3})V([0-9]{3})$#', $piece, $matches)) {
185
    				$result['wind_direction'] = $matches[1];
186
    				$result['wind_direction_other'] = $matches[2];
187
    			}
188
    			// Wind Speed Variable
189
    			if (preg_match('#^VRB([0-9]{2})KT$#', $piece, $matches)) {
190
    				$result['speed_variable'] = $matches[1];
191
    			}
192
    			*/
193
    			// Visibility
194
			if (preg_match('#^([0-9]{4})|(([0-9]{1,4})SM)$#', $piece, $matches)) {
195
				if (isset($matches[3]) && strlen($matches[3]) > 0) {
196
					$result['visibility'] = (float)$matches[3] * 1609.34;
197
				} else {
198
					if ($matches[1] == '9999') {
199
						$result['visibility'] = '> 10000';
200
					} else {
201
						$result['visibility'] = (float)$matches[1];
202
					}
203
				}
204
			}
205
			if (preg_match('#^CAVOK$#', $piece, $matches)) {
206
				$result['visibility'] = '> 10000';
207
				$result['weather'] = "CAVOK";
208
			}
209
			
210
			// Cloud Coverage
211
			if (preg_match('#^(SKC|CLR|FEW|SCT|BKN|OVC|VV)([0-9]{3})(AC|CB|CBS|CC|CS|TCU|CU|CI|///)?$#', $piece, $matches)) {
212
				//$this->addCloudCover($matches[1], ((float)$matches[2]) * 100, isset($matches[3]) ? $matches[3] : '');
213
				$type = $matches[1];
214
				$cloud = array();
215
				if ($type == 'SKC') $cloud['type'] = 'No cloud/Sky clear';
216
				elseif ($type == 'CLR') $cloud['type'] = 'No cloud below 12,000ft (3700m)';
217
				elseif ($type == 'NSC') $cloud['type'] = 'No significant cloud';
218
				elseif ($type == 'FEW') $cloud['type'] = 'Few';
219
				elseif ($type == 'SCT') $cloud['type'] = 'Scattered';
220
				elseif ($type == 'BKN') $cloud['type'] = 'Broken';
221
				elseif ($type == 'OVC') $cloud['type'] = 'Overcast/Full cloud coverage';
222
				elseif ($type == 'VV') $cloud['type'] = 'Vertical visibility';
223
				$cloud['type_code'] = $type;
224
				$cloud['level'] = round(((float)$matches[2]) * 100 * 0.3048);
225
				if (isset($matches[3])) $significant = $matches[3];
226
				else $significant = '';
227
				if ($significant == 'CB') $cloud['significant'] = 'Cumulonimbus';
228
				elseif ($significant == 'AC') $cloud['significant'] = 'Altocumulus';
229
				elseif ($significant == 'CBS') $cloud['significant'] = 'Cumulonimbus';
230
				elseif ($significant == 'CC') $cloud['significant'] = 'Cirrocumulus';
231
				elseif ($significant == 'CU') $cloud['significant'] = 'Cumulus';
232
				elseif ($significant == 'CI') $cloud['significant'] = 'Cirrus';
233
				elseif ($significant == 'CS') $cloud['significant'] = 'Cirrostratus';
234
				elseif ($significant == 'TCU') $cloud['significant'] = 'Towering Cumulus';
235
				else $cloud['significant'] = $significant;
236
				//$cloud['significant'] = isset($matches[3]) ? $matches[3] : '';
237
				$result['cloud'][] = $cloud;
238
			}
239
			// RVR
240
			if (preg_match('#^(R.+)/([M|P])?(\d{4})(?:V(\d+)|[UDN])?(FT)?$#', $piece, $matches)) {
241
				$rvr = array();
242
				$rvr['runway'] = $matches[1];
243
				$rvr['assessment'] = $matches[2];
244
				$rvr['rvr'] = $matches[3];
245
				$rvr['rvr_max'] = array_key_exists(4,$matches) ? $matches[4] : 0;
246
				$rvr['unit'] = array_key_exists(5,$matches) ? $matches[5] : '';
247
				$result['RVR'] = $rvr;
248
			}
249
			//if (preg_match('#^(R[A-Z0-9]{2,3})/([0-9]{4})(V([0-9]{4}))?(FT)?$#', $piece, $matches)) {
250
			if (preg_match('#^R(\d{2}[LRC]?)/([\d/])([\d/])([\d/]{2})([\d/]{2})$#', $piece, $matches)) {
251
				// https://github.com/davidmegginson/metar-taf/blob/master/Metar.php
252
				$result['RVR']['runway'] = $matches[1];
253
				$result['RVR']['deposits'] = $matches[2];
254
				$result['RVR']['extent'] = $matches[3];
255
				$result['RVR']['depth'] = $matches[4];
256
				$result['RVR']['friction'] = $matches[5];
257
			}
258
			if (preg_match('#^(R[A-Z0-9]{2,3})/([0-9]{4})(V([0-9]{4}))?(FT)?$#', $piece, $matches)) {
259
				if (isset($matches[5])) $range = array('exact' => (float)$matches[2], 'unit' => $matches[5] ? 'FT' : 'M');
260
				else $range = array('exact' => (float)$matches[2], 'unit' => 'M');
261
				if (isset($matches[3])) {
262
					$range = Array(
263
					    'from' => (float)$matches[2],
264
					    'to'   => (float)$matches[4],
265
					    'unit' => $matches[5] ? 'FT' : 'M'
266
					);
267
				}
268
				$result['RVR'] = $matches[1];
269
				$result['RVR_range'] = $range;
270
			}
271
			// Weather
272
			if (preg_match($regWeather, $piece, $matches)) {
273
				$text = Array();
274
				switch ($matches[1]) {
275
					case '+':
276
						$text[] = 'Heavy';
277
						break;
278
					case '-':
279
						$text[] = 'Light';
280
						break;
281
					case 'VC':
282
						$text[] = 'Vicinity';
283
						break;
284
					default:
285
						break;
286
				}
287
				if (isset($matches[2])) {
288
					$text[] = $this->texts[$matches[2]];
289
				}
290
				if (isset($matches[3])) {
291
					$text[] = $this->texts[$matches[3]];
292
				}
293
				if (!isset($result['weather'])) $result['weather'] = implode(' ', $text);
294
				else $result['weather'] = $result['weather'].' / '.implode(' ', $text);
295
			}
296
		}
297
		return $result;
298
	}
299
300
	/*
301
	 * Get METAR from an airport ICAO
302
	 * @param String $icao Airport ICAO
303
	 * @return Array Return array with metar date, location and text
304
	*/
305
	public function getMETAR($icao) {
306
		global $globalMETARcycle, $globalDBdriver;
307
		if (isset($globalMETARcycle) && $globalMETARcycle) {
308
			$query = "SELECT * FROM metar WHERE metar_location = :icao";
309
		} else {
310
			if ($globalDBdriver == 'mysql') $query = "SELECT * FROM metar WHERE metar_location = :icao AND metar_date >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 10 HOUR) LIMIT 1";
311
			else $query = "SELECT * FROM metar WHERE metar_location = :icao AND metar_date >= now() AT TIMEZONE 'UTC' - '10 HOUR'->INTERVAL LIMIT 0,1";
312
		}
313
		$query_values = array(':icao' => $icao);
314
		try {
315
			$sth = $this->db->prepare($query);
316
			$sth->execute($query_values);
317
		} catch(PDOException $e) {
318
			return "error : ".$e->getMessage();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 'error : ' . $e->getMessage(); (string) is incompatible with the return type documented by METAR::getMETAR of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
319
		}
320
		$all = $sth->fetchAll(PDO::FETCH_ASSOC);
321
		if ((!isset($globalMETARcycle) || $globalMETARcycle === false) && count($all) == 0) {
322
			$all = $this->downloadMETAR($icao);
323
		}
324
		return $all;
325
	}
326
327
	/*
328
	 * Add METAR in DB
329
	 * @param String $location Airport ICAO
330
	 * @param String $metar METAR text
331
	 * @param String $date date of the METAR
332
	*/
333
	public function addMETAR($location,$metar,$date) {
334
		global $globalDBdriver;
335
		$date = date('Y-m-d H:i:s',strtotime($date));
336
		if ($globalDBdriver == 'mysql') {
337
			$query = "INSERT INTO metar (metar_location,metar_date,metar) VALUES (:location,:date,:metar) ON DUPLICATE KEY UPDATE metar_date = :date, metar = :metar";
338
		} else {
339
			$query = "UPDATE metar SET metar_date = :date, metar = :metar WHERE metar_location = :location;INSERT INTO metar (metar_location,metar_date,metar) SELECT :location,:date,:metar WHERE NOT EXISTS (SELECT 1 FROM metar WHERE metar_location = :location);";
340
		}
341
		$query_values = array(':location' => $location,':date' => $date,':metar' => utf8_encode($metar));
342
		try {
343
			$sth = $this->db->prepare($query);
344
			$sth->execute($query_values);
345
		} catch(PDOException $e) {
346
			return "error : ".$e->getMessage();
347
		}
348
		return '';
349
	}
350
351
	/*
352
	 * Delete a METAR based on id
353
	 * @param Integer $id METAR table id
354
	*/
355
	public function deleteMETAR($id) {
356
		$query = "DELETE FROM metar WHERE id = :id";
357
		$query_values = array(':id' => $id);
358
		try {
359
			$sth = $this->db->prepare($query);
360
			$sth->execute($query_values);
361
		} catch(PDOException $e) {
362
			return "error : ".$e->getMessage();
363
		}
364
		return '';
365
	}
366
367
	/*
368
	 * Delete all METAR in DB
369
	*/
370
	public function deleteAllMETARLocation() {
371
		$query = "DELETE FROM metar";
372
		try {
373
			$sth = $this->db->prepare($query);
374
			$sth->execute();
375
		} catch(PDOException $e) {
376
			return "error : ".$e->getMessage();
377
		}
378
		return '';
379
	}
380
381
	/*
382
	 * Download all METAR from IVAO or NOAA for current hour
383
	*/
384
	public function addMETARCycle() {
385
		global $globalDebug, $globalIVAO, $globalTransaction;
386
		if (isset($globalDebug) && $globalDebug) echo "Downloading METAR cycle...";
387
		date_default_timezone_set("UTC");
388
		$Common = new Common();
389
		if (isset($globalIVAO) && $globalIVAO) {
390
			$Common->download('http://wx.ivao.aero/metar.php',dirname(__FILE__).'/../install/tmp/ivaometar.txt');
391
			$handle = fopen(dirname(__FILE__).'/../install/tmp/ivaometar.txt',"r");
392
		} else {
393
			$Common->download('http://tgftp.nws.noaa.gov/data/observations/metar/cycles/'.date('H').'Z.TXT',dirname(__FILE__).'/../install/tmp/'.date('H').'Z.TXT');
394
			$handle = fopen(dirname(__FILE__).'/../install/tmp/'.date('H').'Z.TXT',"r");
395
		}
396
		if ($handle) {
397
			if (isset($globalDebug) && $globalDebug) echo "Done - Updating DB...";
398
			$date = '';
399
			if ($globalTransaction) $this->db->beginTransaction();
400
			while(($line = fgets($handle,4096)) !== false) {
401
				$line = str_replace(array("\r\n","\r", "\n"), '', $line);
402
				if (preg_match('#^([0-9]{4})/([0-9]{2})/([0-9]{2}) ([0-9]{2}):([0-9]{2})$#',$line)) {
403
					$date = $line;
404
				} elseif (trim($line) != '') {
405
					if ($date == '') $date = date('Y/m/d H:m');
406
					$pos = 0;
407
					$pieces = preg_split('/\s/',$line);
408
					if ($pieces[0] == 'METAR') $pos++;
409
					if (strlen($pieces[$pos]) != 4) $pos++;
410
					if (isset($pieces[$pos])) {
411
						$location = $pieces[$pos];
412
						//if ($location == 'LFLL') echo 'location: '.$location.' - date: '.$date.' - data: '.$line."\n";
413
						echo $this->addMETAR($location,$line,$date);
414
					}
415
				}
416
			}
417
			fclose($handle);
418
			if ($globalTransaction) $this->db->commit();
419
		}
420
		if (isset($globalDebug) && $globalDebug) echo "Done\n";
421
	}
422
423
	/*
424
	 * Download METAR from $globalMETARurl for an airport ICAO
425
	 * @param String $icao airport ICAO
426
	 * @return Array Return array with metar date, location and text
427
	*/
428
	public function downloadMETAR($icao) {
429
		global $globalMETARurl;
430
		if ($globalMETARurl == '') return array();
431
		date_default_timezone_set("UTC");
432
		$Common = new Common();
433
		$url = str_replace('{icao}',$icao,$globalMETARurl);
434
		$cycle = $Common->getData($url);
435
		$date = '';
436
		foreach(explode("\n",$cycle) as $line) {
437
			$line = str_replace(array("\r\n","\r", "\n"), '', $line);
438
			if (preg_match('#^([0-9]{4})/([0-9]{2})/([0-9]{2}) ([0-9]{2}):([0-9]{2})$#',$line)) {
439
				$date = $line;
440
			} 
441
			if (trim($line) != '') {
442
				if ($date == '') $date = date('Y/m/d H:m');
443
				$pos = 0;
444
				$pieces = preg_split('/\s/',$line);
445
				if ($pieces[0] == 'METAR') $pos++;
446
				if (strlen($pieces[$pos]) != 4) $pos++;
447
				$location = $pieces[$pos];
448
				if (strlen($location == 4)) {
449
					$this->addMETAR($location,$line,$date);
450
					return array('0' => array('metar_date' => $date, 'metar_location' => $location, 'metar' => $line));
451
				} else return array();
452
			}
453
		}
454
		return array();
455
	}
456
}
457
/*
458
$METAR = new METAR();
459
print_r($METAR->parse('LSGG 151850Z VRB05KT 9999 FEW060 10/01 Q1021 NOSIG'));
460
*/
461
/*
462
echo $METAR->parse('CYZR 070646Z AUTO VRB02KT 1SM R33/3500VP6000FT/ BR OVC001 M03/M03 A3020 RMK ICG PAST HR SLP233');
463
echo $METAR->parse('CYVQ 070647Z 00000KT 10SM -SN OVC030 M24/M26 A2981 RMK SC8 SLP105');
464
echo $METAR->parse('CYFC 070645Z AUTO 23003KT 5/8SM R09/3500VP6000FT BR FEW180 M01/M01 A3004 RMK SLP173');
465
echo $METAR->parse('ZMUB 070700Z VRB01MPS 6000NW SCT100 M11/M15 Q1013 NOSIG RMK QFE652.8 71 NW MO');
466
echo $METAR->parse('LFLY 070700Z AUTO 00000KT 2800 0500 R34/0600D BCFG NSC 04/03 Q1033');
467
echo $METAR->parse('LFLY 071100Z 0712/0812 15007KT CAVOK PROB30 0800/0806 4000 BR');
468
echo $METAR->parse('LFMU 070700Z AUTO 02005KT 5000 BR BKN012/// BKN018/// BKN030/// ///CB 11/11 Q1032');
469
echo $METAR->parse('METAR LFPO 231027Z AUTO 24004G09MPS 2500 1000NW R32/0400 R08C/0004D +FZRA VCSN //FEW015 17/10 Q1009 REFZRA WS R03');
470
*/
471
/*
472
$METAR = new METAR();
473
$METAR->addMETARCycle();
474
*/
475
/*
476
2015/12/07 12:21
477
TAF LFLY 071100Z 0712/0812 15007KT CAVOK PROB30 0800/0806 4000 BR 
478
      BECMG 0805/0807 0400 FG VV/// 
479
     FM081002 18010KT CAVOK
480
     */
481
482
?>