Jump to content

[SOLVED] Getting results twice?


ERuiz

Recommended Posts

Hello guys and gals,

 

I am having a small problem. I have a small script which gets a METAR feed, processes it and then displays the weather information. The problem is that it will accept 1 weather station as an input variable.

 

How can I run this script TWICE within the same execution, while getting 2 results, using 2 different weather stations?

 

The main file uses this to execute the functions which are on another separate file:

 

<?php
require_once ("functions_weather.php");
$station = "KJFK";
$wxInfo['STATION'] = $station;
$metar = get_metar($station,$wxInfo);
process_metar($metar,$wxInfo);

echo "METAR = $metar<BR><BR>\n";
print_wxInfo($wxInfo);
?>

 

The echo line prints out the raw METAR feed and then outputs 2 carriage returns. The print line outputs the processed METAR in a more detailed manner.

 

What I basically want is to be able to add a $station2 and output both stations.

 

Thanks in advance.

 

Regards,

 

ERuiz

Link to comment
Share on other sites

Have you tried putting the station data into an array? 

 

<?php
require_once ("functions_weather.php");

$location = array("KJFK","COLD");

foreach ($location  as $station) { 

$wxInfo['STATION'] = $station;
$metar = get_metar($station,$wxInfo);
process_metar($metar,$wxInfo);

echo "METAR = $metar<BR><BR>\n";
print_wxInfo($wxInfo);

}
?>

 

best,

 

richard

Link to comment
Share on other sites

Have you tried putting the station data into an array? 

 

<?php
require_once ("functions_weather.php");

$location = array("KJFK","COLD");

foreach ($location  as $station) { 

$wxInfo['STATION'] = $station;
$metar = get_metar($station,$wxInfo);
process_metar($metar,$wxInfo);

echo "METAR = $metar<BR><BR>\n";
print_wxInfo($wxInfo);

}
?>

 

best,

 

richard

 

Hello Richard,

 

I tried the above and I got the following error:

 

Fatal error: Cannot redeclare speed() (previously declared in /functions_weather.php:93)
in /functions_weather.php on line 93

Link to comment
Share on other sites

It's a pretty long code, so here it goes my friend:

 

<?php  // **** FUNCTIONS ****

function get_metar($station, &$wxInfo) {
// This function retrieves METAR information for a given station from the
// National Weather Service. It assumes that the station exists.
// A slower URL is "ftp://weather.noaa.gov/data/observations/metar/stations/$station.TXT"
$fileName = "http://weather.noaa.gov/pub/data/observations/metar/stations/$station.TXT";
$metar = '';
$fileData = @file($fileName);  // or die('Data not available');
if ($fileData != false) {
	list($i, $date) = each($fileData);
	$utc = strtotime(trim($date));
	set_time_data($utc,$wxInfo);
	while (list($i, $line) = each($fileData)) {
		$metar .= ' ' . trim($line);
		}
	$metar = trim(str_replace('  ', ' ', $metar));
	}
return $metar;
}


function set_time_data($utc, &$wxInfo) {
// This function formats observation time in the local time zone of server, the
// current local time on server, and time difference since observation. $utc is a
// UNIX timestamp for Universal Coordinated Time (Greenwich Mean Time or Zulu Time).
$timeZoneOffset = date('Z');
$local = $utc + $timeZoneOffset;
$wxInfo['OBSERVED'] = date('D M j, H:i T',$local);
$now = time();
$wxInfo['NOW'] = date('D M j, H:i T',$now);
$timeDiff = floor(($now - $local) / 60);
if ($timeDiff < 91) $wxInfo['AGE'] = "$timeDiff min ago";
else {
	$min = $timeDiff % 60;
	if ($min < 10) $min = '0' . $min;
	$wxInfo['AGE'] = floor($timeDiff / 60) . ":$min hr ago";
	}
}

function process_metar($metar, &$wxInfo) {
//   This function directs the examination of each group of the METAR. The problem
// with a METAR is that not all the groups have to be there. Some groups could be
// missing. Fortunately, the groups must be in a specific order. (This function
// also assumes that a METAR is well-formed, that is, no typographical mistakes.)
//   This function uses a function variable to organize the sequence in which to
// decode each group. Each function checks to see if it can decode the current
// METAR part. If not, then the group pointer is advanced for the next function
// to try. If yes, the function decodes that part of the METAR and advances the
// METAR pointer and group pointer. (If the function can be called again to
// decode similar information, then the group pointer does not get advanced.)
if ($metar != '') {
	$metarParts = explode(' ',$metar);
	$groupName = array('get_station','get_time','get_station_type','get_wind','get_var_wind','get_visibility','get_runway','get_conditions','get_cloud_cover','get_temperature','get_altimeter');
	$metarPtr = 1;  // get_station identity is ignored
	$group = 1;
	while ($group < count($groupName)) {
		$part = $metarParts[$metarPtr];
		$groupName[$group]($part,$metarPtr,$group,$wxInfo);  // $groupName is a function variable
		}
	}
else $wxInfo['ERROR'] = 'Data not available';
}

function get_station($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore station code. Script assumes this matches requesting $station.
// This function is never called. It is here for completeness of documentation.
if (strlen($part) == 4 and $group == 0) {
	$group++;
	$metarPtr++;
	}
}

function get_time($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore observation time. This information is found in the first line of the NWS file.
// Format is ddhhmmZ where dd = day, hh = hours, mm = minutes in UTC time.
if (substr($part,-1) == 'Z') $metarPtr++;
$group++;
}

function get_station_type($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore station type if present.
if ($part == 'AUTO' || $part == 'COR') $metarPtr++;
$group++;
}

function get_wind($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes wind direction and speed information.
// Format is dddssKT where ddd = degrees from North, ss = speed, KT for knots,
// or dddssGggKT where G stands for gust and gg = gust speed. (ss or gg can be a 3-digit number.)
// KT can be replaced with MPH for meters per second or KMH for kilometers per hour. 

function speed($part, $unit) {
	// Convert wind speed into miles per hour.
	// Some other common conversion factors (to 6 significant digits):
	//   1 mi/hr = 1.15080 knots  = 0.621371 km/hr = 2.23694 m/s
	//   1 ft/s  = 1.68781 knots  = 0.911344 km/hr = 3.28084 m/s
	//   1 knot  = 0.539957 km/hr = 1.94384 m/s
	//   1 km/hr = 1.852 knots    = 3.6 m/s
	//   1 m/s   = 0.514444 knots = 0.277778 km/s
	if ($unit == 'KT') $speed = round(1.1508 * $part);         // from knots
	elseif ($unit == 'MPS') $speed = round(2.23694 * $part);   // from meters per second
	else $speed = round(0.621371 * $part);                     // from km per hour
	$speed = "$speed mph";
	return $speed;
	}

if (ereg('^([0-9G]{5,10}|VRB[0-9]{2,3})(KT|MPS|KMH)$',$part,$pieces)) {
	$part = $pieces[1];
	$unit = $pieces[2];
	if ($part == '00000') {
		$wxInfo['WIND'] = 'calm';  // no wind
		}
	else {
		ereg('([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?',$part,$pieces);
		if ($pieces[1] == 'VRB') $direction = 'varies';
		else {
			$angle = (integer) $pieces[1];
			$compass = array('N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW');
			$direction = $compass[round($angle / 22.5) % 16];
			}
		if ($pieces[3] == 0) $gust = '';
		else $gust = ', gusting to ' . speed($pieces[3], $unit);
		$wxInfo['WIND'] = $direction . ' at ' . speed($pieces[2], $unit) . $gust;
		}
	$metarPtr++;
	}
$group++;
}

function get_var_wind($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore variable wind direction information if present.
// Format is fffVttt where V stands for varies from fff degrees to ttt degrees.
if (ereg('([0-9]{3})V([0-9]{3})',$part,$pieces)) $metarPtr++;
$group++;
}

function get_visibility($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes visibility information. This function will be called a second time
// if visibility is limited to an integer mile plus a fraction part.
// Format is mmSM for mm = statute miles, or m n/dSM for m = mile and n/d = fraction of a mile,
// or just a 4-digit number nnnn (with leading zeros) for nnnn = meters. 
static $integerMile = '';
if (strlen($part) == 1) {  // visibility is limited to a whole mile plus a fraction part
	$integerMile = $part . ' ';
	$metarPtr++;
	}
elseif (substr($part,-2) == 'SM') {  // visibility is in miles
	$part = substr($part,0,strlen($part)-2);
	if (substr($part,0,1) == 'M') {
		$prefix = 'less than ';
		$part = substr($part, 1);
		}
	else $prefix = '';
	if (($integerMile == '' && ereg('[/]',$part,$pieces)) || $part == '1') $unit = ' mile';
	else $unit = ' miles';
	$wxInfo['VISIBILITY'] = $prefix . $integerMile . $part . $unit;
	$metarPtr++;
	$group++;
	}
elseif (substr($part,-2) == 'KM') {  // unknown (Reported by NFFN in Fiji)
	$metarPtr++;
	$group++;
	}
elseif (ereg('^([0-9]{4})$',$part,$pieces)) {  // visibility is in meters
	$distance = round($part/ 621.4, 1);          // convert to miles
	if ($distance > 5) $distance = round($distance);
	if ($distance <= 1) $unit = ' mile';
	else $unit = ' miles';
	$wxInfo['VISIBILITY'] = $distance . $unit;
	$metarPtr++;
	$group++;
	}
elseif ($part == 'CAVOK') {  // good weather
	$wxInfo['VISIBILITY'] = 'greater than 7 miles';  // or 10 km
	$wxInfo['CONDITIONS'] = '';
	$wxInfo['CLOUDS'] = 'clear skies';
	$metarPtr++;
	$group += 4;  // can skip the next 3 groups
	}
else {
	$group++;
	}
}

function get_runway($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore runway information if present. Maybe called a second time.
// Format is Rrrr/vvvvFT where rrr = runway number and vvvv = visibility in feet.
if (substr($part,0,1) == 'R') $metarPtr++;
else $group++;
}

function get_conditions($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes current weather conditions. This function maybe called several times
// to decode all conditions. To learn more about weather condition codes, visit section
// 12.6.8 - Present Weather Group of the Federal Meteorological Handbook No. 1 at
// www.nws.noaa.gov/oso/oso1/oso12/fmh1/fmh1ch12.htm
static $conditions = '';
static $wxCode = array(
	'VC' => 'nearby',
	'MI' => 'shallow',
	'PR' => 'partial',
	'BC' => 'patches of',
	'DR' => 'low drifting',
	'BL' => 'blowing',
	'SH' => 'showers',
	'TS' => 'thunderstorm',
	'FZ' => 'freezing',
	'DZ' => 'drizzle',
	'RA' => 'rain',
	'SN' => 'snow',
	'SG' => 'snow grains',
	'IC' => 'ice crystals',
	'PE' => 'ice pellets',
	'GR' => 'hail',
	'GS' => 'small hail',  // and/or snow pellets
	'UP' => 'unknown',
	'BR' => 'mist',
	'FG' => 'fog',
	'FU' => 'smoke',
	'VA' => 'volcanic ash',
	'DU' => 'widespread dust',
	'SA' => 'sand',
	'HZ' => 'haze',
	'PY' => 'spray',
	'PO' => 'well-developed dust/sand whirls',
	'SQ' => 'squalls',
	'FC' => 'funnel cloud, tornado, or waterspout',
	'SS' => 'sandstorm/duststorm');
if (ereg('^(-|\+|VC)?(TS|SH|FZ|BL|DR|MI|BC|PR|RA|DZ|SN|SG|GR|GS|PE|IC|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$',$part,$pieces)) {
	if (strlen($conditions) == 0) $join = '';
	else $join = ' & ';
	if (substr($part,0,1) == '-') {
		$prefix = 'light ';
		$part = substr($part,1);
		}
	elseif (substr($part,0,1) == '+') {
		$prefix = 'heavy ';
		$part = substr($part,1);
		}
	else $prefix = '';  // moderate conditions have no descriptor
	$conditions .= $join . $prefix;
	// The 'showers' code 'SH' is moved behind the next 2-letter code to make the English translation read better.
	if (substr($part,0,2) == 'SH') $part = substr($part,2,2) . substr($part,0,2). substr($part, 4);
	while ($code = substr($part,0,2)) {
		$conditions .= $wxCode[$code] . ' ';
		$part = substr($part,2);
		}
	$wxInfo['CONDITIONS'] = $conditions;
	$metarPtr++;
	}
else {
	$wxInfo['CONDITIONS'] = $conditions;
	$group++;
	}
}

function get_cloud_cover($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes cloud cover information. This function maybe called several times
// to decode all cloud layer observations. Only the last layer is saved.
// Format is SKC or CLR for clear skies, or cccnnn where ccc = 3-letter code and
// nnn = altitude of cloud layer in hundreds of feet. 'VV' seems to be used for
// very low cloud layers. (Other conversion factor: 1 m = 3.28084 ft)
static $cloudCode = array(
	'SKC' => 'clear skies',
	'CLR' => 'clear skies',
	'FEW' => 'partly cloudy',
	'SCT' => 'scattered clouds',
	'BKN' => 'mostly cloudy',
	'OVC' => 'overcast',
	'VV'  => 'vertical visibility');
if ($part == 'SKC' || $part == 'CLR') {
	$wxInfo['CLOUDS'] = $cloudCode[$part];
	$metarPtr++;
	$group++;
	}
else {
	if (ereg('^([A-Z]{2,3})([0-9]{3})',$part,$pieces)) {  // codes for CB and TCU are ignored
		$wxInfo['CLOUDS'] = $cloudCode[$pieces[1]];
		if ($pieces[1] == 'VV') {
			$altitude = (integer) 100 * $pieces[2];  // units are feet
			$wxInfo['CLOUDS'] .= " to $altitude ft";
			}
		$metarPtr++;
		}
	else {
		$group++;
		}
	}
}

function get_temperature($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes temperature and dew point information. Relative humidity is calculated. Also,
// depending on the temperature, Heat Index or Wind Chill Temperature is calculated.
// Format is tt/dd where tt = temperature and dd = dew point temperature. All units are
// in Celsius. A 'M' preceeding the tt or dd indicates a negative temperature. Some
// stations do not report dew point, so the format is tt/ or tt/XX.

function get_heat_index($tempF, $rh, &$wxInfo) {
	// Calculate Heat Index based on temperature in F and relative humidity (65 = 65%)
	if ($tempF > 79 && $rh > 39) {
		$hiF = -42.379 + 2.04901523 * $tempF + 10.14333127 * $rh - 0.22475541 * $tempF * $rh;
		$hiF += -0.00683783 * pow($tempF, 2) - 0.05481717 * pow($rh, 2);
		$hiF += 0.00122874 * pow($tempF, 2) * $rh + 0.00085282 * $tempF * pow($rh, 2);
		$hiF += -0.00000199 * pow($tempF, 2) * pow($rh, 2);
		$hiF = round($hiF);
		$hiC = round(($hiF - 32) / 1.;
		$wxInfo['HEAT INDEX'] = "$hiF°F ($hiC°C)";
		}
	}

function get_wind_chill($tempF, &$wxInfo) {
	// Calculate Wind Chill Temperature based on temperature in F and
	// wind speed in miles per hour
	if ($tempF < 51 && $wxInfo['WIND'] != 'calm') {
		$pieces = explode(' ', $wxInfo['WIND']);
		$windspeed = (integer) $pieces[2];   // wind speed must be in miles per hour
		if ($windspeed > 3) {
			$chillF = 35.74 + 0.6215 * $tempF - 35.75 * pow($windspeed, 0.16) + 0.4275 * $tempF * pow($windspeed, 0.16);
			$chillF = round($chillF);
			$chillC = round(($chillF - 32) / 1.;
			$wxInfo['WIND CHILL'] = "$chillF°F ($chillC°C)";
			}
		}
	}

if (ereg('^(M?[0-9]{2})/(M?[0-9]{2}|[X]{2})?$',$part,$pieces)) {
	$tempC = (integer) strtr($pieces[1], 'M', '-');
	$tempF = round(1.8 * $tempC + 32);
	$wxInfo['TEMP'] = "$tempF°F ($tempC°C)";
	get_wind_chill($tempF, $wxInfo);
	if (strlen($pieces[2]) != 0 && $pieces[2] != 'XX') {
		$dewC = (integer) strtr($pieces[2], 'M', '-');
		$dewF = round(1.8 * $dewC + 32);
		$wxInfo['DEWPT'] = "$dewF°F ($dewC°C)";
		$rh = round(100 * pow((112 - (0.1 * $tempC) + $dewC) / (112 + (0.9 * $tempC)), );
		$wxInfo['HUMIDITY'] = $rh . '%';
		get_heat_index($tempF, $rh, $wxInfo);
		}
	$metarPtr++;
	$group++;
	}
else {
	$group++;
	}
}

function get_altimeter($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes altimeter or barometer information.
// Format is Annnn where nnnn represents a real number as nn.nn in inches of Hg, 
// or Qpppp where pppp = hectoPascals.
// Some other common conversion factors:
//   1 millibar = 1 hPa
//   1 in Hg = 0.02953 hPa
//   1 mm Hg = 25.4 in Hg = 0.750062 hPa
//   1 lb/sq in = 0.491154 in Hg = 0.014504 hPa
//   1 atm = 0.33421 in Hg = 0.0009869 hPa
if (ereg('^(A|Q)([0-9]{4})',$part,$pieces)) {
	if ($pieces[1] == 'A') {
		$pressureIN = substr($pieces[2],0,2) . '.' . substr($pieces[2],2);  // units are inches Hg
		$pressureHPA = round($pressureIN / 0.02953);                        // convert to hectoPascals
		}
	else {
		$pressureHPA = (integer) $pieces[2];              // units are hectoPascals
		$pressureIN = round(0.02953 * $pressureHPA,2);    // convert to inches Hg
		}
	$wxInfo['BAROMETER'] = "$pressureHPA hPa ($pressureIN in Hg)";
	$metarPtr++;
	$group++;
	}
else {
	$group++;
	}
}

function print_wxInfo($wxInfo) {
// Prints each piece of information stored in the array.
// If an error occurs in retrieving a METAR file, check for index called 'ERROR'.
// (Modify this function to fit your needs.)
$dots = '...............';
foreach($wxInfo As $wxIndex => $wx) {
	if (strlen($wx) != 0) echo $wxIndex . substr($dots,0,strlen($dots)-strlen($wxIndex)) . " $wx<BR>\n";
	}
}
?>

Link to comment
Share on other sites

can you provide another station. By accident I ran the code through a tester with "COLD" still in there, and most of the data was cached so If I can test it with another station that is real.

 

METAR = KJFK 272351Z 26012KT 10SM FEW050 SCT250 18/11 A3004 RMK AO2 SLP172 60010 T01780111 10200 20178 53028

 

STATION........ KJFK

OBSERVED....... Sat Oct 27, 16:51 PDT

NOW............ Sat Oct 27, 17:08 PDT

AGE............ 17 min ago

WIND........... W at 14 mph

VISIBILITY..... 10 miles

CLOUDS......... scattered clouds

TEMP........... 64°F (18°C)

DEWPT.......... 52°F (11°C)

HUMIDITY....... 64%

BAROMETER...... 1017 hPa (30.04 in Hg)

METAR =

 

STATION........ COLD

OBSERVED....... Sat Oct 27, 16:51 PDT

NOW............ Sat Oct 27, 17:08 PDT

AGE............ 17 min ago

WIND........... W at 14 mph

VISIBILITY..... 10 miles

CLOUDS......... scattered clouds

TEMP........... 64°F (18°C)

DEWPT.......... 52°F (11°C)

HUMIDITY....... 64%

BAROMETER...... 1017 hPa (30.04 in Hg)

ERROR.......... Data not available

 

Link to comment
Share on other sites

can you provide another station. By accident I ran the code through a tester with "COLD" still in there, and most of the data was cached so If I can test it with another station that is real.

 

METAR = KJFK 272351Z 26012KT 10SM FEW050 SCT250 18/11 A3004 RMK AO2 SLP172 60010 T01780111 10200 20178 53028

 

STATION........ KJFK

OBSERVED....... Sat Oct 27, 16:51 PDT

NOW............ Sat Oct 27, 17:08 PDT

AGE............ 17 min ago

WIND........... W at 14 mph

VISIBILITY..... 10 miles

CLOUDS......... scattered clouds

TEMP........... 64°F (18°C)

DEWPT.......... 52°F (11°C)

HUMIDITY....... 64%

BAROMETER...... 1017 hPa (30.04 in Hg)

METAR =

 

STATION........ COLD

OBSERVED....... Sat Oct 27, 16:51 PDT

NOW............ Sat Oct 27, 17:08 PDT

AGE............ 17 min ago

WIND........... W at 14 mph

VISIBILITY..... 10 miles

CLOUDS......... scattered clouds

TEMP........... 64°F (18°C)

DEWPT.......... 52°F (11°C)

HUMIDITY....... 64%

BAROMETER...... 1017 hPa (30.04 in Hg)

ERROR.......... Data not available

 

 

Sure, try KMIA

Link to comment
Share on other sites

I am now able to get the same error.

I have to log out now, but if you are continuing tonight, try this tester as you can edit and process code in real time (simulated) just go to the URL below and enter a name to start the session, it will open up a page with an textarea and a display browser below. It needs the php tags to process the code, hit the "Exceute Code" button. It will return your code in the text area and the results below. It is a quick way to test as you don't have to save each time.

 

 

http://www.mywebforyou.com/php4me/php_tester/php_start.php  Please don't forget to keep the php tags in the textarea

<?php  ?> 

 

I built this tester for a begining class, but it can handle this script as long as it thinks it's one page. Use the code in the block below as it has the correct array for both stations. It may be that the results need to written to a temporary file, and the script reset for the 2nd station and then combined into one page for output.

 

I had to comment out the include to test it as one page  (I hope this helps and I will check back tomorrow)  best and fly safely!

 

 

 


<?php  // **** FUNCTIONS ****

function get_metar($station, &$wxInfo) {
// This function retrieves METAR information for a given station from the
// National Weather Service. It assumes that the station exists.
// A slower URL is "ftp://weather.noaa.gov/data/observations/metar/stations/$station.TXT"
$fileName = "http://weather.noaa.gov/pub/data/observations/metar/stations/$station.TXT";
$metar = '';
$fileData = @file($fileName);  // or die('Data not available');
if ($fileData != false) {
	list($i, $date) = each($fileData);
	$utc = strtotime(trim($date));
	set_time_data($utc,$wxInfo);
	while (list($i, $line) = each($fileData)) {
		$metar .= ' ' . trim($line);
		}
	$metar = trim(str_replace('  ', ' ', $metar));
	}
return $metar;
}


function set_time_data($utc, &$wxInfo) {
// This function formats observation time in the local time zone of server, the
// current local time on server, and time difference since observation. $utc is a
// UNIX timestamp for Universal Coordinated Time (Greenwich Mean Time or Zulu Time).
$timeZoneOffset = date('Z');
$local = $utc + $timeZoneOffset;
$wxInfo['OBSERVED'] = date('D M j, H:i T',$local);
$now = time();
$wxInfo['NOW'] = date('D M j, H:i T',$now);
$timeDiff = floor(($now - $local) / 60);
if ($timeDiff < 91) $wxInfo['AGE'] = "$timeDiff min ago";
else {
	$min = $timeDiff % 60;
	if ($min < 10) $min = '0' . $min;
	$wxInfo['AGE'] = floor($timeDiff / 60) . ":$min hr ago";
	}
}

function process_metar($metar, &$wxInfo) {
//   This function directs the examination of each group of the METAR. The problem
// with a METAR is that not all the groups have to be there. Some groups could be
// missing. Fortunately, the groups must be in a specific order. (This function
// also assumes that a METAR is well-formed, that is, no typographical mistakes.)
//   This function uses a function variable to organize the sequence in which to
// decode each group. Each function checks to see if it can decode the current
// METAR part. If not, then the group pointer is advanced for the next function
// to try. If yes, the function decodes that part of the METAR and advances the
// METAR pointer and group pointer. (If the function can be called again to
// decode similar information, then the group pointer does not get advanced.)
if ($metar != '') {
	$metarParts = explode(' ',$metar);
	$groupName = array('get_station','get_time','get_station_type','get_wind','get_var_wind','get_visibility','get_runway','get_conditions','get_cloud_cover','get_temperature','get_altimeter');
	$metarPtr = 1;  // get_station identity is ignored
	$group = 1;
	while ($group < count($groupName)) {
		$part = $metarParts[$metarPtr];
		$groupName[$group]($part,$metarPtr,$group,$wxInfo);  // $groupName is a function variable
		}
	}
else $wxInfo['ERROR'] = 'Data not available';
}

function get_station($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore station code. Script assumes this matches requesting $station.
// This function is never called. It is here for completeness of documentation.
if (strlen($part) == 4 and $group == 0) {
	$group++;
	$metarPtr++;
	}
}

function get_time($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore observation time. This information is found in the first line of the NWS file.
// Format is ddhhmmZ where dd = day, hh = hours, mm = minutes in UTC time.
if (substr($part,-1) == 'Z') $metarPtr++;
$group++;
}

function get_station_type($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore station type if present.
if ($part == 'AUTO' || $part == 'COR') $metarPtr++;
$group++;
}

function get_wind($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes wind direction and speed information.
// Format is dddssKT where ddd = degrees from North, ss = speed, KT for knots,
// or dddssGggKT where G stands for gust and gg = gust speed. (ss or gg can be a 3-digit number.)
// KT can be replaced with MPH for meters per second or KMH for kilometers per hour. 

function speed($part, $unit) {
	// Convert wind speed into miles per hour.
	// Some other common conversion factors (to 6 significant digits):
	//   1 mi/hr = 1.15080 knots  = 0.621371 km/hr = 2.23694 m/s
	//   1 ft/s  = 1.68781 knots  = 0.911344 km/hr = 3.28084 m/s
	//   1 knot  = 0.539957 km/hr = 1.94384 m/s
	//   1 km/hr = 1.852 knots    = 3.6 m/s
	//   1 m/s   = 0.514444 knots = 0.277778 km/s
	if ($unit == 'KT') $speed = round(1.1508 * $part);         // from knots
	elseif ($unit == 'MPS') $speed = round(2.23694 * $part);   // from meters per second
	else $speed = round(0.621371 * $part);                     // from km per hour
	$speed = "$speed mph";
	return $speed;
	}

if (ereg('^([0-9G]{5,10}|VRB[0-9]{2,3})(KT|MPS|KMH)$',$part,$pieces)) {
	$part = $pieces[1];
	$unit = $pieces[2];
	if ($part == '00000') {
		$wxInfo['WIND'] = 'calm';  // no wind
		}
	else {
		ereg('([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?',$part,$pieces);
		if ($pieces[1] == 'VRB') $direction = 'varies';
		else {
			$angle = (integer) $pieces[1];
			$compass = array('N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW');
			$direction = $compass[round($angle / 22.5) % 16];
			}
		if ($pieces[3] == 0) $gust = '';
		else $gust = ', gusting to ' . speed($pieces[3], $unit);
		$wxInfo['WIND'] = $direction . ' at ' . speed($pieces[2], $unit) . $gust;
		}
	$metarPtr++;
	}
$group++;
}

function get_var_wind($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore variable wind direction information if present.
// Format is fffVttt where V stands for varies from fff degrees to ttt degrees.
if (ereg('([0-9]{3})V([0-9]{3})',$part,$pieces)) $metarPtr++;
$group++;
}

function get_visibility($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes visibility information. This function will be called a second time
// if visibility is limited to an integer mile plus a fraction part.
// Format is mmSM for mm = statute miles, or m n/dSM for m = mile and n/d = fraction of a mile,
// or just a 4-digit number nnnn (with leading zeros) for nnnn = meters. 
static $integerMile = '';
if (strlen($part) == 1) {  // visibility is limited to a whole mile plus a fraction part
	$integerMile = $part . ' ';
	$metarPtr++;
	}
elseif (substr($part,-2) == 'SM') {  // visibility is in miles
	$part = substr($part,0,strlen($part)-2);
	if (substr($part,0,1) == 'M') {
		$prefix = 'less than ';
		$part = substr($part, 1);
		}
	else $prefix = '';
	if (($integerMile == '' && ereg('[/]',$part,$pieces)) || $part == '1') $unit = ' mile';
	else $unit = ' miles';
	$wxInfo['VISIBILITY'] = $prefix . $integerMile . $part . $unit;
	$metarPtr++;
	$group++;
	}
elseif (substr($part,-2) == 'KM') {  // unknown (Reported by NFFN in Fiji)
	$metarPtr++;
	$group++;
	}
elseif (ereg('^([0-9]{4})$',$part,$pieces)) {  // visibility is in meters
	$distance = round($part/ 621.4, 1);          // convert to miles
	if ($distance > 5) $distance = round($distance);
	if ($distance <= 1) $unit = ' mile';
	else $unit = ' miles';
	$wxInfo['VISIBILITY'] = $distance . $unit;
	$metarPtr++;
	$group++;
	}
elseif ($part == 'CAVOK') {  // good weather
	$wxInfo['VISIBILITY'] = 'greater than 7 miles';  // or 10 km
	$wxInfo['CONDITIONS'] = '';
	$wxInfo['CLOUDS'] = 'clear skies';
	$metarPtr++;
	$group += 4;  // can skip the next 3 groups
	}
else {
	$group++;
	}
}

function get_runway($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore runway information if present. Maybe called a second time.
// Format is Rrrr/vvvvFT where rrr = runway number and vvvv = visibility in feet.
if (substr($part,0,1) == 'R') $metarPtr++;
else $group++;
}

function get_conditions($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes current weather conditions. This function maybe called several times
// to decode all conditions. To learn more about weather condition codes, visit section
// 12.6.8 - Present Weather Group of the Federal Meteorological Handbook No. 1 at
// www.nws.noaa.gov/oso/oso1/oso12/fmh1/fmh1ch12.htm
static $conditions = '';
static $wxCode = array(
	'VC' => 'nearby',
	'MI' => 'shallow',
	'PR' => 'partial',
	'BC' => 'patches of',
	'DR' => 'low drifting',
	'BL' => 'blowing',
	'SH' => 'showers',
	'TS' => 'thunderstorm',
	'FZ' => 'freezing',
	'DZ' => 'drizzle',
	'RA' => 'rain',
	'SN' => 'snow',
	'SG' => 'snow grains',
	'IC' => 'ice crystals',
	'PE' => 'ice pellets',
	'GR' => 'hail',
	'GS' => 'small hail',  // and/or snow pellets
	'UP' => 'unknown',
	'BR' => 'mist',
	'FG' => 'fog',
	'FU' => 'smoke',
	'VA' => 'volcanic ash',
	'DU' => 'widespread dust',
	'SA' => 'sand',
	'HZ' => 'haze',
	'PY' => 'spray',
	'PO' => 'well-developed dust/sand whirls',
	'SQ' => 'squalls',
	'FC' => 'funnel cloud, tornado, or waterspout',
	'SS' => 'sandstorm/duststorm');
if (ereg('^(-|\+|VC)?(TS|SH|FZ|BL|DR|MI|BC|PR|RA|DZ|SN|SG|GR|GS|PE|IC|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$',$part,$pieces)) {
	if (strlen($conditions) == 0) $join = '';
	else $join = ' & ';
	if (substr($part,0,1) == '-') {
		$prefix = 'light ';
		$part = substr($part,1);
		}
	elseif (substr($part,0,1) == '+') {
		$prefix = 'heavy ';
		$part = substr($part,1);
		}
	else $prefix = '';  // moderate conditions have no descriptor
	$conditions .= $join . $prefix;
	// The 'showers' code 'SH' is moved behind the next 2-letter code to make the English translation read better.
	if (substr($part,0,2) == 'SH') $part = substr($part,2,2) . substr($part,0,2). substr($part, 4);
	while ($code = substr($part,0,2)) {
		$conditions .= $wxCode[$code] . ' ';
		$part = substr($part,2);
		}
	$wxInfo['CONDITIONS'] = $conditions;
	$metarPtr++;
	}
else {
	$wxInfo['CONDITIONS'] = $conditions;
	$group++;
	}
}

function get_cloud_cover($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes cloud cover information. This function maybe called several times
// to decode all cloud layer observations. Only the last layer is saved.
// Format is SKC or CLR for clear skies, or cccnnn where ccc = 3-letter code and
// nnn = altitude of cloud layer in hundreds of feet. 'VV' seems to be used for
// very low cloud layers. (Other conversion factor: 1 m = 3.28084 ft)
static $cloudCode = array(
	'SKC' => 'clear skies',
	'CLR' => 'clear skies',
	'FEW' => 'partly cloudy',
	'SCT' => 'scattered clouds',
	'BKN' => 'mostly cloudy',
	'OVC' => 'overcast',
	'VV'  => 'vertical visibility');
if ($part == 'SKC' || $part == 'CLR') {
	$wxInfo['CLOUDS'] = $cloudCode[$part];
	$metarPtr++;
	$group++;
	}
else {
	if (ereg('^([A-Z]{2,3})([0-9]{3})',$part,$pieces)) {  // codes for CB and TCU are ignored
		$wxInfo['CLOUDS'] = $cloudCode[$pieces[1]];
		if ($pieces[1] == 'VV') {
			$altitude = (integer) 100 * $pieces[2];  // units are feet
			$wxInfo['CLOUDS'] .= " to $altitude ft";
			}
		$metarPtr++;
		}
	else {
		$group++;
		}
	}
}

function get_temperature($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes temperature and dew point information. Relative humidity is calculated. Also,
// depending on the temperature, Heat Index or Wind Chill Temperature is calculated.
// Format is tt/dd where tt = temperature and dd = dew point temperature. All units are
// in Celsius. A 'M' preceeding the tt or dd indicates a negative temperature. Some
// stations do not report dew point, so the format is tt/ or tt/XX.

function get_heat_index($tempF, $rh, &$wxInfo) {
	// Calculate Heat Index based on temperature in F and relative humidity (65 = 65%)
	if ($tempF > 79 && $rh > 39) {
		$hiF = -42.379 + 2.04901523 * $tempF + 10.14333127 * $rh - 0.22475541 * $tempF * $rh;
		$hiF += -0.00683783 * pow($tempF, 2) - 0.05481717 * pow($rh, 2);
		$hiF += 0.00122874 * pow($tempF, 2) * $rh + 0.00085282 * $tempF * pow($rh, 2);
		$hiF += -0.00000199 * pow($tempF, 2) * pow($rh, 2);
		$hiF = round($hiF);
		$hiC = round(($hiF - 32) / 1.;
		$wxInfo['HEAT INDEX'] = "$hiF°F ($hiC°C)";
		}
	}

function get_wind_chill($tempF, &$wxInfo) {
	// Calculate Wind Chill Temperature based on temperature in F and
	// wind speed in miles per hour
	if ($tempF < 51 && $wxInfo['WIND'] != 'calm') {
		$pieces = explode(' ', $wxInfo['WIND']);
		$windspeed = (integer) $pieces[2];   // wind speed must be in miles per hour
		if ($windspeed > 3) {
			$chillF = 35.74 + 0.6215 * $tempF - 35.75 * pow($windspeed, 0.16) + 0.4275 * $tempF * pow($windspeed, 0.16);
			$chillF = round($chillF);
			$chillC = round(($chillF - 32) / 1.;
			$wxInfo['WIND CHILL'] = "$chillF°F ($chillC°C)";
			}
		}
	}

if (ereg('^(M?[0-9]{2})/(M?[0-9]{2}|[X]{2})?$',$part,$pieces)) {
	$tempC = (integer) strtr($pieces[1], 'M', '-');
	$tempF = round(1.8 * $tempC + 32);
	$wxInfo['TEMP'] = "$tempF°F ($tempC°C)";
	get_wind_chill($tempF, $wxInfo);
	if (strlen($pieces[2]) != 0 && $pieces[2] != 'XX') {
		$dewC = (integer) strtr($pieces[2], 'M', '-');
		$dewF = round(1.8 * $dewC + 32);
		$wxInfo['DEWPT'] = "$dewF°F ($dewC°C)";
		$rh = round(100 * pow((112 - (0.1 * $tempC) + $dewC) / (112 + (0.9 * $tempC)), );
		$wxInfo['HUMIDITY'] = $rh . '%';
		get_heat_index($tempF, $rh, $wxInfo);
		}
	$metarPtr++;
	$group++;
	}
else {
	$group++;
	}
}

function get_altimeter($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes altimeter or barometer information.
// Format is Annnn where nnnn represents a real number as nn.nn in inches of Hg, 
// or Qpppp where pppp = hectoPascals.
// Some other common conversion factors:
//   1 millibar = 1 hPa
//   1 in Hg = 0.02953 hPa
//   1 mm Hg = 25.4 in Hg = 0.750062 hPa
//   1 lb/sq in = 0.491154 in Hg = 0.014504 hPa
//   1 atm = 0.33421 in Hg = 0.0009869 hPa
if (ereg('^(A|Q)([0-9]{4})',$part,$pieces)) {
	if ($pieces[1] == 'A') {
		$pressureIN = substr($pieces[2],0,2) . '.' . substr($pieces[2],2);  // units are inches Hg
		$pressureHPA = round($pressureIN / 0.02953);                        // convert to hectoPascals
		}
	else {
		$pressureHPA = (integer) $pieces[2];              // units are hectoPascals
		$pressureIN = round(0.02953 * $pressureHPA,2);    // convert to inches Hg
		}
	$wxInfo['BAROMETER'] = "$pressureHPA hPa ($pressureIN in Hg)";
	$metarPtr++;
	$group++;
	}
else {
	$group++;
	}
}

function print_wxInfo($wxInfo) {
// Prints each piece of information stored in the array.
// If an error occurs in retrieving a METAR file, check for index called 'ERROR'.
// (Modify this function to fit your needs.)
$dots = '...............';
foreach($wxInfo As $wxIndex => $wx) {
	if (strlen($wx) != 0) echo $wxIndex . substr($dots,0,strlen($dots)-strlen($wxIndex)) . " $wx<BR>\n";
	}
}
?>
<?php
// require_once ("functions_weather.php");

$location = array("KMIA","KJFK");

foreach ($location  as $station) { 

$wxInfo['STATION'] = $station;
$metar = get_metar($station,$wxInfo);
process_metar($metar,$wxInfo);

echo "METAR = $metar<BR><BR>\n";
print_wxInfo($wxInfo);


}
?>

Link to comment
Share on other sites

Code fixed:

<?php
require_once ("functions_weather.php");

$location = array("KMIA","KJFK"); // list your stations here

foreach ($location  as $station)
{
    $wxInfo['STATION'] = $station;
    $metar = get_metar($station,$wxInfo);
    process_metar($metar,$wxInfo);

    echo "<p>METAR = $metar</p>\n";
    print_wxInfo($wxInfo);

}
?>

functions_weather.php

<?php  // **** FUNCTIONS ****

function get_metar($station, &$wxInfo)
{
// This function retrieves METAR information for a given station from the
// National Weather Service. It assumes that the station exists.
// A slower URL is "ftp://weather.noaa.gov/data/observations/metar/stations/$station.TXT"
$fileName = "http://weather.noaa.gov/pub/data/observations/metar/stations/$station.TXT";
$metar = '';
$fileData = @file($fileName);  // or die('Data not available');
if ($fileData != false)
    {
	list($i, $date) = each($fileData);
	$utc = strtotime(trim($date));
	set_time_data($utc, $wxInfo);

	while (list($i, $line) = each($fileData))
        {
		$metar .= ' ' . trim($line);
	}

	$metar = trim(str_replace('  ', ' ', $metar));
}

return $metar;
}


function set_time_data($utc, &$wxInfo)
{
// This function formats observation time in the local time zone of server, the
// current local time on server, and time difference since observation. $utc is a
// UNIX timestamp for Universal Coordinated Time (Greenwich Mean Time or Zulu Time).
$timeZoneOffset = date('Z');
$local = $utc + $timeZoneOffset;

$wxInfo['OBSERVED'] = date('D M j, H:i T', $local);

$now = time();
$wxInfo['NOW'] = date('D M j, H:i T',$now);

$timeDiff = floor(($now - $local) / 60);

if ($timeDiff < 91)
        $wxInfo['AGE'] = "$timeDiff min ago";
else
    {
	$min = $timeDiff % 60;
	if ($min < 10)
            $min = '0' . $min;

	$wxInfo['AGE'] = floor($timeDiff / 60) . ":$min hr ago";
}
}

function process_metar($metar, &$wxInfo) {
//   This function directs the examination of each group of the METAR. The problem
// with a METAR is that not all the groups have to be there. Some groups could be
// missing. Fortunately, the groups must be in a specific order. (This function
// also assumes that a METAR is well-formed, that is, no typographical mistakes.)
//   This function uses a function variable to organize the sequence in which to
// decode each group. Each function checks to see if it can decode the current
// METAR part. If not, then the group pointer is advanced for the next function
// to try. If yes, the function decodes that part of the METAR and advances the
// METAR pointer and group pointer. (If the function can be called again to
// decode similar information, then the group pointer does not get advanced.)
if ($metar != '') {
	$metarParts = explode(' ',$metar);
	$groupName = array('get_station','get_time','get_station_type','get_wind','get_var_wind','get_visibility','get_runway','get_conditions','get_cloud_cover','get_temperature','get_altimeter');
	$metarPtr = 1;  // get_station identity is ignored
	$group = 1;
	while ($group < count($groupName)) {
		$part = $metarParts[$metarPtr];
		$groupName[$group]($part,$metarPtr,$group,$wxInfo);  // $groupName is a function variable
		}
	}
else $wxInfo['ERROR'] = 'Data not available';
}

function get_station($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore station code. Script assumes this matches requesting $station.
// This function is never called. It is here for completeness of documentation.
if (strlen($part) == 4 and $group == 0) {
	$group++;
	$metarPtr++;
	}
}

function get_time($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore observation time. This information is found in the first line of the NWS file.
// Format is ddhhmmZ where dd = day, hh = hours, mm = minutes in UTC time.
if (substr($part,-1) == 'Z') $metarPtr++;
$group++;
}

function get_station_type($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore station type if present.
if ($part == 'AUTO' || $part == 'COR') $metarPtr++;
$group++;
}

function get_wind($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes wind direction and speed information.
// Format is dddssKT where ddd = degrees from North, ss = speed, KT for knots,
// or dddssGggKT where G stands for gust and gg = gust speed. (ss or gg can be a 3-digit number.)
// KT can be replaced with MPH for meters per second or KMH for kilometers per hour.

if(!function_exists('speed'))
    {
        function speed($part, $unit) {
    		// Convert wind speed into miles per hour.
    		// Some other common conversion factors (to 6 significant digits):
    		//   1 mi/hr = 1.15080 knots  = 0.621371 km/hr = 2.23694 m/s
    		//   1 ft/s  = 1.68781 knots  = 0.911344 km/hr = 3.28084 m/s
    		//   1 knot  = 0.539957 km/hr = 1.94384 m/s
    		//   1 km/hr = 1.852 knots    = 3.6 m/s
    		//   1 m/s   = 0.514444 knots = 0.277778 km/s
    		if ($unit == 'KT') $speed = round(1.1508 * $part);         // from knots
    		elseif ($unit == 'MPS') $speed = round(2.23694 * $part);   // from meters per second
    		else $speed = round(0.621371 * $part);                     // from km per hour
    		$speed = "$speed mph";
    		return $speed;
    	}
    }

if (ereg('^([0-9G]{5,10}|VRB[0-9]{2,3})(KT|MPS|KMH)$',$part,$pieces)) {
	$part = $pieces[1];
	$unit = $pieces[2];
	if ($part == '00000') {
		$wxInfo['WIND'] = 'calm';  // no wind
		}
	else {
		ereg('([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?',$part,$pieces);
		if ($pieces[1] == 'VRB') $direction = 'varies';
		else {
			$angle = (integer) $pieces[1];
			$compass = array('N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW');
			$direction = $compass[round($angle / 22.5) % 16];
			}
		if ($pieces[3] == 0) $gust = '';
		else $gust = ', gusting to ' . speed($pieces[3], $unit);
		$wxInfo['WIND'] = $direction . ' at ' . speed($pieces[2], $unit) . $gust;
		}
	$metarPtr++;
	}
$group++;
}

function get_var_wind($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore variable wind direction information if present.
// Format is fffVttt where V stands for varies from fff degrees to ttt degrees.
if (ereg('([0-9]{3})V([0-9]{3})',$part,$pieces)) $metarPtr++;
$group++;
}

function get_visibility($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes visibility information. This function will be called a second time
// if visibility is limited to an integer mile plus a fraction part.
// Format is mmSM for mm = statute miles, or m n/dSM for m = mile and n/d = fraction of a mile,
// or just a 4-digit number nnnn (with leading zeros) for nnnn = meters.
static $integerMile = '';
if (strlen($part) == 1) {  // visibility is limited to a whole mile plus a fraction part
	$integerMile = $part . ' ';
	$metarPtr++;
	}
elseif (substr($part,-2) == 'SM') {  // visibility is in miles
	$part = substr($part,0,strlen($part)-2);
	if (substr($part,0,1) == 'M') {
		$prefix = 'less than ';
		$part = substr($part, 1);
		}
	else $prefix = '';
	if (($integerMile == '' && ereg('[/]',$part,$pieces)) || $part == '1') $unit = ' mile';
	else $unit = ' miles';
	$wxInfo['VISIBILITY'] = $prefix . $integerMile . $part . $unit;
	$metarPtr++;
	$group++;
	}
elseif (substr($part,-2) == 'KM') {  // unknown (Reported by NFFN in Fiji)
	$metarPtr++;
	$group++;
	}
elseif (ereg('^([0-9]{4})$',$part,$pieces)) {  // visibility is in meters
	$distance = round($part/ 621.4, 1);          // convert to miles
	if ($distance > 5) $distance = round($distance);
	if ($distance <= 1) $unit = ' mile';
	else $unit = ' miles';
	$wxInfo['VISIBILITY'] = $distance . $unit;
	$metarPtr++;
	$group++;
	}
elseif ($part == 'CAVOK') {  // good weather
	$wxInfo['VISIBILITY'] = 'greater than 7 miles';  // or 10 km
	$wxInfo['CONDITIONS'] = '';
	$wxInfo['CLOUDS'] = 'clear skies';
	$metarPtr++;
	$group += 4;  // can skip the next 3 groups
	}
else {
	$group++;
	}
}

function get_runway($part, &$metarPtr, &$group, &$wxInfo) {
// Ignore runway information if present. Maybe called a second time.
// Format is Rrrr/vvvvFT where rrr = runway number and vvvv = visibility in feet.
if (substr($part,0,1) == 'R') $metarPtr++;
else $group++;
}

function get_conditions($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes current weather conditions. This function maybe called several times
// to decode all conditions. To learn more about weather condition codes, visit section
// 12.6.8 - Present Weather Group of the Federal Meteorological Handbook No. 1 at
// www.nws.noaa.gov/oso/oso1/oso12/fmh1/fmh1ch12.htm
static $conditions = '';
static $wxCode = array(
	'VC' => 'nearby',
	'MI' => 'shallow',
	'PR' => 'partial',
	'BC' => 'patches of',
	'DR' => 'low drifting',
	'BL' => 'blowing',
	'SH' => 'showers',
	'TS' => 'thunderstorm',
	'FZ' => 'freezing',
	'DZ' => 'drizzle',
	'RA' => 'rain',
	'SN' => 'snow',
	'SG' => 'snow grains',
	'IC' => 'ice crystals',
	'PE' => 'ice pellets',
	'GR' => 'hail',
	'GS' => 'small hail',  // and/or snow pellets
	'UP' => 'unknown',
	'BR' => 'mist',
	'FG' => 'fog',
	'FU' => 'smoke',
	'VA' => 'volcanic ash',
	'DU' => 'widespread dust',
	'SA' => 'sand',
	'HZ' => 'haze',
	'PY' => 'spray',
	'PO' => 'well-developed dust/sand whirls',
	'SQ' => 'squalls',
	'FC' => 'funnel cloud, tornado, or waterspout',
	'SS' => 'sandstorm/duststorm');
if (ereg('^(-|\+|VC)?(TS|SH|FZ|BL|DR|MI|BC|PR|RA|DZ|SN|SG|GR|GS|PE|IC|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$',$part,$pieces)) {
	if (strlen($conditions) == 0) $join = '';
	else $join = ' & ';
	if (substr($part,0,1) == '-') {
		$prefix = 'light ';
		$part = substr($part,1);
		}
	elseif (substr($part,0,1) == '+') {
		$prefix = 'heavy ';
		$part = substr($part,1);
		}
	else $prefix = '';  // moderate conditions have no descriptor
	$conditions .= $join . $prefix;
	// The 'showers' code 'SH' is moved behind the next 2-letter code to make the English translation read better.
	if (substr($part,0,2) == 'SH') $part = substr($part,2,2) . substr($part,0,2). substr($part, 4);
	while ($code = substr($part,0,2)) {
		$conditions .= $wxCode[$code] . ' ';
		$part = substr($part,2);
		}
	$wxInfo['CONDITIONS'] = $conditions;
	$metarPtr++;
	}
else {
	$wxInfo['CONDITIONS'] = $conditions;
	$group++;
	}
}

function get_cloud_cover($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes cloud cover information. This function maybe called several times
// to decode all cloud layer observations. Only the last layer is saved.
// Format is SKC or CLR for clear skies, or cccnnn where ccc = 3-letter code and
// nnn = altitude of cloud layer in hundreds of feet. 'VV' seems to be used for
// very low cloud layers. (Other conversion factor: 1 m = 3.28084 ft)
static $cloudCode = array(
	'SKC' => 'clear skies',
	'CLR' => 'clear skies',
	'FEW' => 'partly cloudy',
	'SCT' => 'scattered clouds',
	'BKN' => 'mostly cloudy',
	'OVC' => 'overcast',
	'VV'  => 'vertical visibility');
if ($part == 'SKC' || $part == 'CLR') {
	$wxInfo['CLOUDS'] = $cloudCode[$part];
	$metarPtr++;
	$group++;
	}
else {
	if (ereg('^([A-Z]{2,3})([0-9]{3})',$part,$pieces)) {  // codes for CB and TCU are ignored
		$wxInfo['CLOUDS'] = $cloudCode[$pieces[1]];
		if ($pieces[1] == 'VV') {
			$altitude = (integer) 100 * $pieces[2];  // units are feet
			$wxInfo['CLOUDS'] .= " to $altitude ft";
			}
		$metarPtr++;
		}
	else {
		$group++;
		}
	}
}

function get_temperature($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes temperature and dew point information. Relative humidity is calculated. Also,
// depending on the temperature, Heat Index or Wind Chill Temperature is calculated.
// Format is tt/dd where tt = temperature and dd = dew point temperature. All units are
// in Celsius. A 'M' preceeding the tt or dd indicates a negative temperature. Some
// stations do not report dew point, so the format is tt/ or tt/XX.

if(!function_exists('get_heat_index'))
    {
        function get_heat_index($tempF, $rh, &$wxInfo)
        {
	    // Calculate Heat Index based on temperature in F and relative humidity (65 = 65%)
	    if ($tempF > 79 && $rh > 39) {
    			$hiF = -42.379 + 2.04901523 * $tempF + 10.14333127 * $rh - 0.22475541 * $tempF * $rh;
    			$hiF += -0.00683783 * pow($tempF, 2) - 0.05481717 * pow($rh, 2);
    			$hiF += 0.00122874 * pow($tempF, 2) * $rh + 0.00085282 * $tempF * pow($rh, 2);
    			$hiF += -0.00000199 * pow($tempF, 2) * pow($rh, 2);
    			$hiF = round($hiF);
    			$hiC = round(($hiF - 32) / 1.;
    			$wxInfo['HEAT INDEX'] = "{$hiF}°F ({$hiC}°C)";
		}
	}
    }

    if(!function_exists('get_wind_chill'))
    {
    	function get_wind_chill($tempF, &$wxInfo) {
    		// Calculate Wind Chill Temperature based on temperature in F and
    		// wind speed in miles per hour
    		if ($tempF < 51 && $wxInfo['WIND'] != 'calm') {
    			$pieces = explode(' ', $wxInfo['WIND']);
    			$windspeed = (integer) $pieces[2];   // wind speed must be in miles per hour
    			if ($windspeed > 3) {
    				$chillF = 35.74 + 0.6215 * $tempF - 35.75 * pow($windspeed, 0.16) + 0.4275 * $tempF * pow($windspeed, 0.16);
    				$chillF = round($chillF);
    				$chillC = round(($chillF - 32) / 1.;
    				$wxInfo['WIND CHILL'] = "$chillF°F ($chillC°C)";
			}
		}
	}
    }

if (ereg('^(M?[0-9]{2})/(M?[0-9]{2}|[X]{2})?$',$part,$pieces)) {
	$tempC = (integer) strtr($pieces[1], 'M', '-');
	$tempF = round(1.8 * $tempC + 32);
	$wxInfo['TEMP'] = "{$tempF}°F ({$tempC}°C)";
	get_wind_chill($tempF, $wxInfo);
	if (strlen($pieces[2]) != 0 && $pieces[2] != 'XX') {
		$dewC = (integer) strtr($pieces[2], 'M', '-');
		$dewF = round(1.8 * $dewC + 32);
		$wxInfo['DEWPT'] = "{$dewF}°F ({$dewC}°C)";
		$rh = round(100 * pow((112 - (0.1 * $tempC) + $dewC) / (112 + (0.9 * $tempC)), );
		$wxInfo['HUMIDITY'] = $rh . '%';
		get_heat_index($tempF, $rh, $wxInfo);
		}
	$metarPtr++;
	$group++;
	}
else {
	$group++;
	}
}

function get_altimeter($part, &$metarPtr, &$group, &$wxInfo) {
// Decodes altimeter or barometer information.
// Format is Annnn where nnnn represents a real number as nn.nn in inches of Hg,
// or Qpppp where pppp = hectoPascals.
// Some other common conversion factors:
//   1 millibar = 1 hPa
//   1 in Hg = 0.02953 hPa
//   1 mm Hg = 25.4 in Hg = 0.750062 hPa
//   1 lb/sq in = 0.491154 in Hg = 0.014504 hPa
//   1 atm = 0.33421 in Hg = 0.0009869 hPa
if (ereg('^(A|Q)([0-9]{4})',$part,$pieces)) {
	if ($pieces[1] == 'A') {
		$pressureIN = substr($pieces[2],0,2) . '.' . substr($pieces[2],2);  // units are inches Hg
		$pressureHPA = round($pressureIN / 0.02953);                        // convert to hectoPascals
		}
	else {
		$pressureHPA = (integer) $pieces[2];              // units are hectoPascals
		$pressureIN = round(0.02953 * $pressureHPA,2);    // convert to inches Hg
		}
	$wxInfo['BAROMETER'] = "$pressureHPA hPa ($pressureIN in Hg)";
	$metarPtr++;
	$group++;
	}
else {
	$group++;
	}
}

function print_wxInfo($wxInfo) {
// Prints each piece of information stored in the array.
// If an error occurs in retrieving a METAR file, check for index called 'ERROR'.
// (Modify this function to fit your needs.)
$dots = '...............';
foreach($wxInfo As $wxIndex => $wx) {
	if (strlen($wx) != 0) echo $wxIndex . substr($dots,0,strlen($dots)-strlen($wxIndex)) . " $wx<BR>\n";
	}
}
?>

 

I get the following output:

METAR = KMIA 281753Z 09019G22KT 10SM SCT032 OVC250 31/20 A2999 RMK AO2 SLP154 60005 T03060200 10306 20250 58017 $
STATION........ KMIA
OBSERVED....... Sun Oct 28, 17:53 GMT
NOW............ Sun Oct 28, 18:27 GMT
AGE............ 34 min ago
WIND........... E at 22 mph, gusting to 25 mph
VISIBILITY..... 10 miles
CLOUDS......... overcast
TEMP........... 88°F (31°C)
DEWPT.......... 68°F (20°C)
HUMIDITY....... 52%
HEAT INDEX..... 92°F (33°C)
BAROMETER...... 1016 hPa (29.99 in Hg)

METAR = KJFK 281751Z 34016G21KT 10SM FEW050 SCT250 14/M02 A3032 RMK AO2 PK WND 33026/1703 SLP266 T01391022 10139 20106 58004
STATION........ KJFK
OBSERVED....... Sun Oct 28, 17:51 GMT
NOW............ Sun Oct 28, 18:27 GMT
AGE............ 36 min ago
WIND........... NNW at 18 mph, gusting to 24 mph
VISIBILITY..... 10 miles
CLOUDS......... scattered clouds
TEMP........... 57°F (14°C)
DEWPT.......... 28°F (-2°C)
HUMIDITY....... 33%
HEAT INDEX..... 92°F (33°C)
BAROMETER...... 1027 hPa (30.32 in Hg)

 

The problem was to do with your functions within functions and few issue with your variables.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.