View source
<?php
function weather_parse_metar($metar_raw_string) {
$metar = array();
$metar['#raw'] = $metar_raw_string;
$raw_items = preg_split('/\\s+/', strtoupper($metar_raw_string));
foreach ($raw_items as $metar_raw) {
if (_weather_parse_stop($metar_raw, $metar)) {
break;
}
_weather_parse_icao($metar_raw, $metar);
_weather_parse_timestamp($metar_raw, $metar);
_weather_parse_reporttype($metar_raw, $metar);
_weather_parse_wind($metar_raw, $metar);
_weather_parse_visibility($metar_raw, $metar);
_weather_parse_condition($metar_raw, $metar);
_weather_parse_phenomena($metar_raw, $metar);
_weather_parse_temperature($metar_raw, $metar);
_weather_parse_pressure($metar_raw, $metar);
}
return $metar;
}
function _weather_parse_stop($metar_raw, &$metar) {
if (preg_match('/^(BECMG|TEMPO|NOSIG|RMK)$/', $metar_raw)) {
return true;
}
else {
return false;
}
}
function _weather_parse_icao($metar_raw, &$metar) {
if (preg_match('/^([A-Z]{4}|K[A-Z0-9]{3})$/', $metar_raw) and !isset($metar['icao'])) {
$metar['icao'] = $metar_raw;
}
}
function _weather_parse_timestamp($metar_raw, &$metar) {
if (preg_match('/^([0-9]{2})([0-9]{2})([0-9]{2})Z$/', $metar_raw, $matches)) {
$timestamp['year'] = gmdate('Y');
$timestamp['month'] = gmdate('n');
$timestamp['day'] = $matches[1];
$timestamp['hour'] = $matches[2];
$timestamp['minute'] = $matches[3];
if (gmdate('d') < $timestamp['day']) {
$timestamp['month']--;
}
$metar['reported_on'] = gmmktime($timestamp['hour'], $timestamp['minute'], 0, $timestamp['month'], $timestamp['day'], $timestamp['year']);
}
}
function _weather_parse_reporttype($metar_raw, &$metar) {
if (preg_match('/^(AUTO|COR)$/', $metar_raw)) {
$metar['reporttype'] = $metar_raw;
}
}
function _weather_parse_wind($metar_raw, &$metar) {
if (preg_match('/^' . '([0-9]{3}|VRB)' . '([0-9]{2,3})' . '(G([0-9]{2,3}))?' . '(KT)' . '$/', $metar_raw, $matches)) {
$metar['wind']['direction'] = (int) $matches[1];
$wind_speed = (int) $matches[2];
$wind_gusts = (int) $matches[4];
$wind_unit = $matches[5];
switch ($wind_unit) {
case 'KT':
$metar['wind']['speed_kmh'] = round($wind_speed * 1.852, 1);
$metar['wind']['gusts_kmh'] = round($wind_gusts * 1.852, 1);
$metar['wind']['speed_mph'] = round($wind_speed * 1.151, 1);
$metar['wind']['gusts_mph'] = round($wind_gusts * 1.151, 1);
break;
}
}
else {
if (preg_match('/^' . '([0-9]{3})' . 'V' . '([0-9]{3})' . '$/', $metar_raw, $matches)) {
$metar['wind']['variable_start'] = (int) $matches[1];
$metar['wind']['variable_end'] = (int) $matches[2];
}
}
}
function _weather_parse_visibility($metar_raw, &$metar) {
if (preg_match('/^([0-9])$/', $metar_raw, $matches)) {
$metar['visibility']['#visibility_miles'] = $matches[1];
}
else {
if (preg_match('/^' . '(M?)([0-9])(\\/?)([0-9]*)' . 'SM' . '$/', $metar_raw, $matches)) {
if ($matches[3] == '/') {
$visibility = $metar['visibility']['#visibility_miles'] + $matches[2] / $matches[4];
}
else {
$visibility = $matches[2] . $matches[4];
}
$metar['visibility']['miles'] = $visibility;
$metar['visibility']['kilometers'] = round($visibility * 1.609344, 1);
}
else {
if (preg_match('/^([0-9]{4})$/', $metar_raw, $matches)) {
$metar['visibility']['kilometers'] = round($matches[1] / 1000, 1);
$metar['visibility']['miles'] = round($metar['visibility']['kilometers'] / 1.609344, 1);
}
}
}
}
function _weather_parse_phenomena($metar_raw, &$metar) {
if (preg_match('/^' . '(-|\\+|VC)?' . '(SH|TS|FZ)?' . 'RA' . '$/', $metar_raw, $matches)) {
$phen = array();
switch ($matches[1]) {
case '-':
$phen['#light'] = true;
break;
case '+':
$phen['#heavy'] = true;
break;
default:
$phen['#moderate'] = true;
}
switch ($matches[2]) {
case 'SH':
$phen['#showers'] = true;
break;
case 'FZ':
$phen['#freezing'] = true;
break;
}
$metar['phenomena']['rain'] = $phen;
}
else {
if (preg_match('/^' . '(-|\\+|VC)?' . '(FZ)?' . 'DZ' . '$/', $metar_raw, $matches)) {
$phen = array();
switch ($matches[1]) {
case '-':
$phen['#light'] = true;
break;
case '+':
$phen['#heavy'] = true;
break;
default:
$phen['#moderate'] = true;
}
switch ($matches[2]) {
case 'FZ':
$phen['#freezing'] = true;
break;
}
$metar['phenomena']['drizzle'] = $phen;
}
}
}
function _weather_parse_condition($metar_raw, &$metar) {
$ordering = array(
1 => array(
'CLR' => 'clear',
),
2 => array(
'FEW' => 'few',
),
3 => array(
'SCT' => 'scattered',
),
4 => array(
'BKN' => 'broken',
),
5 => array(
'OVC' => 'overcast',
),
);
if (preg_match('/^' . '(FEW|SCT|BKN|OVC)([0-9]{3})' . '(CB|TCU)?' . '$/', $metar_raw, $matches)) {
foreach ($ordering as $order => $data) {
if (key($data) == $matches[1]) {
$metar['#condition_text'][] = $data[key($data)];
$metar['#condition_order'][] = $order;
break;
}
}
}
else {
if (preg_match('/^' . '(CLR|SKC|CAVOK)' . '$/', $metar_raw, $matches)) {
$metar['#condition_text'][] = 'clear';
$metar['#condition_order'][] = 1;
if ($matches[1] == 'CAVOK') {
$metar['visibility']['kilometers'] = 10;
$metar['visibility']['miles'] = round($metar['visibility']['kilometers'] / 1.609344, 1);
}
}
else {
if (preg_match('/^' . '(NSC|NCD)' . '$/', $metar_raw, $matches)) {
$metar['#condition_text'][] = 'no-significant-clouds';
$metar['#condition_order'][] = 1;
}
else {
if (preg_match('/^' . 'VV[0-9]{3}' . '$/', $metar_raw, $matches)) {
$metar['#condition_text'][] = 'overcast';
$metar['#condition_order'][] = 5;
}
}
}
}
if (isset($metar['#condition_order'])) {
foreach ($metar['#condition_order'] as $index => $order) {
if ($order > $metar['condition_order']) {
$metar['condition_order'] = $order;
$metar['condition_text'] = $metar['#condition_text'][$index];
}
}
}
}
function _weather_parse_temperature($metar_raw, &$metar) {
if (preg_match('/^' . '(M?[0-9]{2})' . '\\/' . '(M?[0-9]{2})?' . '$/', $metar_raw, $matches)) {
$metar['temperature']['celsius'] = (int) strtr($matches[1], 'M', '-');
$metar['temperature']['fahrenheit'] = round($metar['temperature']['celsius'] * 9 / 5 + 32, 1);
if (isset($matches[2])) {
$metar['dewpoint']['celsius'] = (int) strtr($matches[2], 'M', '-');
$metar['dewpoint']['fahrenheit'] = round($metar['dewpoint']['celsius'] * 9 / 5 + 32, 1);
}
}
}
function _weather_parse_pressure($metar_raw, &$metar) {
if (preg_match('/^' . '(A|Q)([0-9]{4})' . '$/', $metar_raw, $matches)) {
if ($matches[1] == 'A') {
$metar['pressure']['inHg'] = $matches[2] / 100;
$metar['pressure']['hPa'] = round(33.8639 * $metar['pressure']['inHg'], 0);
}
else {
$metar['pressure']['hPa'] = (int) $matches[2];
$metar['pressure']['inHg'] = round($metar['pressure']['hPa'] * 0.02953, 2);
}
}
}