This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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
|
|||
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 | ?> |
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.