cvs: pear /Services_Weather Weather.php /Services_Weather/Weather Common.php Metar.php
| From: | Alexander Wirtz | Date: | Fri, 11 Nov 2005 14:33:15 +0000 |
| Subject: | cvs: pear /Services_Weather Weather.php /Services_Weather/Weather Common.php Metar.php | ||
| Groups: | php.pear.cvs | ||
| Request: | Send a blank email to pear-cvs+get-36209@lists.php.net to get a copy of this message | ||
eru Fri Nov 11 09:33:15 2005 EDT
Modified files:
/pear/Services_Weather/Weather Metar.php Common.php
/pear/Services_Weather Weather.php
Log:
o Added using HTTP_Request or Net_FTP for retrieving the data
http://cvs.php.net/diff.php/pear/Services_Weather/Weather/Metar.php?r1=1.77&r2=1.78&ty=u Index: pear/Services_Weather/Weather/Metar.php diff -u pear/Services_Weather/Weather/Metar.php:1.77 pear/Services_Weather/Weather/Metar.php:1.78 --- pear/Services_Weather/Weather/Metar.php:1.77 Wed Nov 9 17:52:44 2005 +++ pear/Services_Weather/Weather/Metar.php Fri Nov 11 09:33:14 2005 @@ -40,7 +40,7 @@ * @author Alexander Wirtz <alex@pc4p.net> * @copyright 2005 Alexander Wirtz * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: Metar.php,v 1.77 2005/11/09 22:52:44 eru Exp $ + * @version CVS: $Id: Metar.php,v 1.78 2005/11/11 14:33:14 eru Exp $ * @link http://pear.php.net/package/Services_Weather * @link http://weather.noaa.gov/weather/metar.shtml * @link http://weather.noaa.gov/weather/taf.shtml @@ -236,46 +236,64 @@ * @param string $sourcePathMetar * @param string $sourceTaf * @param string $sourcePathTaf + * @return PEAR_ERROR|bool + * @throws PEAR_Error::SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID * @access public */ function setMetarSource($sourceMetar, $sourcePathMetar = "", $sourceTaf = "", $sourcePathTaf = "") { if (in_array($sourceMetar, array("http", "ftp", "file"))) { $this->_sourceMetar = $sourceMetar; + } else { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); } + clearstatcache(); if (strlen($sourcePathMetar)) { - $this->_sourcePathMetar = $sourcePathMetar; + if (($this->_sourceMetar == "file" && is_dir($sourcePathMetar)) || ($this->_sourceMetar != "file" && parse_url($sourcePathMetar))) { + $this->_sourcePathMetar = $sourcePathMetar; + } else { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); + } } else { switch ($sourceMetar) { case "http": - $this->_sourcePathMetar = "http://weather.noaa.gov/pub/data/observations/metar/stations/"; + $this->_sourcePathMetar = "http://weather.noaa.gov/pub/data/observations/metar/stations"; break; case "ftp": - $this->_sourcePathMetar = "ftp://weather.noaa.gov/data/observations/metar/stations/"; + $this->_sourcePathMetar = "ftp://weather.noaa.gov/data/observations/metar/stations"; break; case "file": - $this->_sourcePathMetar = "./"; + $this->_sourcePathMetar = "."; break; } } if (in_array($sourceTaf, array("http", "ftp", "file"))) { $this->_sourceTaf = $sourceTaf; + } elseif ($sourceTaf != "") { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); } + clearstatcache(); if (strlen($sourcePathTaf)) { - $this->_sourcePathTaf = $sourcePathTaf; + if (($this->_sourceTaf == "file" && is_dir($sourcePathTaf)) || ($this->_sourceTaf != "file" && parse_url($sourcePathTaf))) { + $this->_sourcePathTaf = $sourcePathTaf; + } else { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); + } } else { switch ($sourceTaf) { case "http": - $this->_sourcePathTaf = "http://weather.noaa.gov/pub/data/forecasts/taf/stations/"; + $this->_sourcePathTaf = "http://weather.noaa.gov/pub/data/forecasts/taf/stations"; break; case "ftp": - $this->_sourcePathTaf = "ftp://weather.noaa.gov/data/forecasts/taf/stations/"; + $this->_sourcePathTaf = "ftp://weather.noaa.gov/data/forecasts/taf/stations"; break; case "file": - $this->_sourcePathTaf = "./"; + $this->_sourcePathTaf = "."; break; } } + + return true; } // }}} @@ -302,20 +320,91 @@ } // }}} + /** + * Downloads the weather- or forecast-data for an id from the server dependant on the datatype and returns it + * + * @param string $id + * @param string $dataType + * @return PEAR_Error|array + * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA + * @access private + */ + // {{{ _retrieveServerData() + function _retrieveServerData($id, $dataType) { + switch($this->{"_source".ucfirst($dataType)}) { + case "file": + $source = realpath($this->{"_sourcePath".ucfirst($dataType)}."/".$id.".TXT"); + $data = @file_get_contents($source); + if ($data === false) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + break; + case "http": + include_once "HTTP/Request.php"; + + $request = &new HTTP_Request($this->{"_sourcePath".ucfirst($dataType)}."/".$id.".TXT", $this->_httpOptions); + $status = $request->sendRequest(); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $data = $request->getResponseBody(); + break; + case "ftp": + include_once "Net/FTP.php"; + + $server = parse_url($this->{"_sourcePath".ucfirst($dataType)}."/".$id.".TXT"); + + if (!isset($server["port"]) || $server["port"] == "" || $server["port"] == 0) { + $server["port"] = 21; + } + if (!isset($server["user"]) || $server["user"] == "") { + $server["user"] = "ftp"; + } + if (!isset($server["pass"]) || $server["pass"] == "") { + $server["pass"] = "ftp@"; + } + + $ftp = &new Net_FTP($server["host"], $server["port"], $this->_httpOptions["timeout"]); + $status = $ftp->connect(); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $status = $ftp->login($server["user"], $server["pass"]); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $tempfile = tempnam(); + $status = $ftp->get($server["path"], $tempfile, true, FTP_ASCII); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $ftp->disconnect(); + $data = @file_get_contents($tempfile); + break; + } + + return preg_split("/\n|\r\n|\n\r/", $data); + } + // }}} + // {{{ _parseWeatherData() /** - * Parses the data returned by the provided source and caches it + * Parses the data and caches it * * METAR KPIT 091955Z COR 22015G25KT 3/4SM R28L/2600FT TSRA OVC010CB * 18/16 A2992 RMK SLP045 T01820159 * - * @param string $source + * @param array $data * @return PEAR_Error|array * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION * @access private */ - function _parseWeatherData($source) + function _parseWeatherData($data) { static $compass; static $clouds; @@ -416,386 +505,380 @@ "maintain" => "[\$]" ); - $data = @file($source); + if (SERVICES_WEATHER_DEBUG) { + for ($i = 0; $i < sizeof($data); $i++) { + echo $data[$i]; + } + } + // Start with parsing the first line for the last update + $weatherData = array(); + $weatherData["station"] = ""; + $weatherData["dataRaw"] = implode(" ", $data); + $weatherData["update"] = strtotime(trim($data[0])." GMT"); + $weatherData["updateRaw"] = trim($data[0]); + // and prepare the rest for stepping through + array_shift($data); + $metar = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); + + // Add a few local variables for data processing + $trendCount = 0; // If we have trends, we need this + $pointer =& $weatherData; // Pointer to the array we add the data to + for ($i = 0; $i < sizeof($metar); $i++) { + // Check for whitespace and step loop, if nothing's there + $metar[$i] = trim($metar[$i]); + if (!strlen($metar[$i])) { + continue; + } - // Check for correct data, 2 lines in size - if (!$data || !is_array($data) || sizeof($data) < 2) { - return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); - } else { if (SERVICES_WEATHER_DEBUG) { - for ($i = 0; $i < sizeof($data); $i++) { - echo $data[$i]; - } + $tab = str_repeat("\t", 2 - floor((strlen($metar[$i]) + 2) / 8)); + echo "\"".$metar[$i]."\"".$tab."-> "; } - // Ok, we have correct data, start with parsing the first line for the last update - $weatherData = array(); - $weatherData["station"] = ""; - $weatherData["dataRaw"] = implode(" ", $data); - $weatherData["update"] = strtotime(trim($data[0])." GMT"); - $weatherData["updateRaw"] = trim($data[0]); - // and prepare the rest for stepping through - array_shift($data); - $metar = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); - - // Add a few local variables for data processing - $trendCount = 0; // If we have trends, we need this - $pointer =& $weatherData; // Pointer to the array we add the data to - for ($i = 0; $i < sizeof($metar); $i++) { - // Check for whitespace and step loop, if nothing's there - $metar[$i] = trim($metar[$i]); - if (!strlen($metar[$i])) { - continue; - } - - if (SERVICES_WEATHER_DEBUG) { - $tab = str_repeat("\t", 2 - floor((strlen($metar[$i]) + 2) / 8)); - echo "\"".$metar[$i]."\"".$tab."-> "; - } - - // Initialize some arrays - $result = array(); - $resultVF = array(); - $lresult = array(); - - $found = false; - foreach ($metarCode as $key => $regexp) { - // Check if current code matches current metar snippet - if (($found = preg_match("/^".$regexp."$/i", $metar[$i], $result)) == true) { - switch ($key) { - case "station": - $pointer["station"] = $result[0]; - unset($metarCode["station"]); + + // Initialize some arrays + $result = array(); + $resultVF = array(); + $lresult = array(); + + $found = false; + foreach ($metarCode as $key => $regexp) { + // Check if current code matches current metar snippet + if (($found = preg_match("/^".$regexp."$/i", $metar[$i], $result)) == true) { + switch ($key) { + case "station": + $pointer["station"] = $result[0]; + unset($metarCode["station"]); + break; + case "wind": + // Parse wind data, first the speed, convert from kt to chosen unit + $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); + if ($result[1] == "VAR" || $result[1] == "VRB") { + // Variable winds + $pointer["windDegrees"] = "Variable"; + $pointer["windDirection"] = "Variable"; + } else { + // Save wind degree and calc direction + $pointer["windDegrees"] = intval($result[1]); + $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; + } + if (is_numeric($result[4])) { + // Wind with gusts... + $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); + } + break; + case "windVar": + // Once more wind, now variability around the current wind-direction + $pointer["windVariability"] = array("from" => intval($result[1]), "to" => intval($result[2])); + break; + case "visFrac": + // Possible fractional visibility here. Check if it matches with the next METAR piece for visibility + if (!isset($metar[$i + 1]) || !preg_match("/^".$metarCode["visibility"]."$/i", $result[1]." ".$metar[$i + 1], $resultVF)) { + // No next METAR piece available or not matching. Match against next METAR code + $found = false; break; - case "wind": - // Parse wind data, first the speed, convert from kt to chosen unit - $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); - if ($result[1] == "VAR" || $result[1] == "VRB") { - // Variable winds - $pointer["windDegrees"] = "Variable"; - $pointer["windDirection"] = "Variable"; - } else { - // Save wind degree and calc direction - $pointer["windDegrees"] = intval($result[1]); - $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; - } - if (is_numeric($result[4])) { - // Wind with gusts... - $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); + } else { + // Match. Hand over result and advance METAR + if (SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + echo "\"".$result[1]." ".$metar[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$metar[$i + 1]) + 2) / 8))."-> "; + } + $key = "visibility"; + $result = $resultVF; + $i++; + } + case "visibility": + $pointer["visQualifier"] = "AT"; + if (is_numeric($result[1]) && ($result[1] == 9999)) { + // Upper limit of visibility range + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["visQualifier"] = "BEYOND"; + } elseif (is_numeric($result[1])) { + // 4-digit visibility in m + $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); + } elseif (!isset($result[11]) || $result[11] != "CAVOK") { + if ($result[3] == "M") { + $pointer["visQualifier"] = "BELOW"; + } elseif ($result[3] == "P") { + $pointer["visQualifier"] = "BEYOND"; } - break; - case "windVar": - // Once more wind, now variability around the current wind-direction - $pointer["windVariability"] = array("from" => intval($result[1]), "to" => intval($result[2])); - break; - case "visFrac": - // Possible fractional visibility here. Check if it matches with the next METAR piece for visibility - if (!isset($metar[$i + 1]) || !preg_match("/^".$metarCode["visibility"]."$/i", $result[1]." ".$metar[$i + 1], $resultVF)) { - // No next METAR piece available or not matching. Match against next METAR code - $found = false; - break; + if (is_numeric($result[5])) { + // visibility as one/two-digit number + $visibility = $this->convertDistance($result[5], $result[10], "sm"); } else { - // Match. Hand over result and advance METAR - if (SERVICES_WEATHER_DEBUG) { - echo $key."\n"; - echo "\"".$result[1]." ".$metar[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$metar[$i + 1]) + 2) / 8))."-> "; - } - $key = "visibility"; - $result = $resultVF; - $i++; - } - case "visibility": - $pointer["visQualifier"] = "AT"; - if (is_numeric($result[1]) && ($result[1] == 9999)) { - // Upper limit of visibility range - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["visQualifier"] = "BEYOND"; - } elseif (is_numeric($result[1])) { - // 4-digit visibility in m - $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); - } elseif (!isset($result[11]) || $result[11] != "CAVOK") { - if ($result[3] == "M") { - $pointer["visQualifier"] = "BELOW"; - } elseif ($result[3] == "P") { - $pointer["visQualifier"] = "BEYOND"; - } - if (is_numeric($result[5])) { - // visibility as one/two-digit number - $visibility = $this->convertDistance($result[5], $result[10], "sm"); + // the y/z part, add if we had a x part (see visibility1) + if (is_numeric($result[7])) { + $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); } else { - // the y/z part, add if we had a x part (see visibility1) - if (is_numeric($result[7])) { - $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); - } else { - $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); - } + $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); } - } else { - $pointer["visQualifier"] = "BEYOND"; - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); - $pointer["condition"] = "no significant weather"; - } - $pointer["visibility"] = $visibility; - break; - case "condition": - // First some basic setups - if (!isset($pointer["condition"])) { - $pointer["condition"] = ""; - } elseif (strlen($pointer["condition"]) > 0) { - $pointer["condition"] .= ","; } + } else { + $pointer["visQualifier"] = "BEYOND"; + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); + $pointer["condition"] = "no significant weather"; + } + $pointer["visibility"] = $visibility; + break; + case "condition": + // First some basic setups + if (!isset($pointer["condition"])) { + $pointer["condition"] = ""; + } elseif (strlen($pointer["condition"]) > 0) { + $pointer["condition"] .= ","; + } - if (in_array(strtolower($result[0]), $conditions)) { - // First try matching the complete string - $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; - } else { - // No luck, match part by part - array_shift($result); - $result = array_unique($result); - foreach ($result as $condition) { - if (strlen($condition) > 0) { - $pointer["condition"] .= " ".$conditions[strtolower($condition)]; - } + if (in_array(strtolower($result[0]), $conditions)) { + // First try matching the complete string + $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; + } else { + // No luck, match part by part + array_shift($result); + $result = array_unique($result); + foreach ($result as $condition) { + if (strlen($condition) > 0) { + $pointer["condition"] .= " ".$conditions[strtolower($condition)]; } } - $pointer["condition"] = trim($pointer["condition"]); - break; - case "clouds": - if (!isset($pointer["clouds"])) { - $pointer["clouds"] = array(); - } + } + $pointer["condition"] = trim($pointer["condition"]); + break; + case "clouds": + if (!isset($pointer["clouds"])) { + $pointer["clouds"] = array(); + } - if (sizeof($result) == 5) { - // Only amount and height - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100)); - } - elseif (sizeof($result) == 6) { - // Amount, height and type - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100), "type" => $clouds[strtolower($result[5])]); - } - else { - // SKC or CLR or NSC - $cloud = array("amount" => $clouds[strtolower($result[0])]); - } - $pointer["clouds"][] = $cloud; - break; - case "temperature": - // normal temperature in first part - // negative value - if ($result[1] == "M") { - $result[2] *= -1; - } - $pointer["temperature"] = $this->convertTemperature($result[2], "c", "f"); - if (sizeof($result) > 4) { - // same for dewpoint - if ($result[4] == "M") { - $result[5] *= -1; - } - $pointer["dewPoint"] = $this->convertTemperature($result[5], "c", "f"); - $pointer["humidity"] = $this->calculateHumidity($result[2], $result[5]); - } - if (isset($pointer["wind"])) { - // Now calculate windchill from temperature and windspeed - $pointer["feltTemperature"] = $this->calculateWindChill($pointer["temperature"], $pointer["wind"]); - } - break; - case "pressure": - if ($result[1] == "A") { - // Pressure provided in inches - $pointer["pressure"] = $result[2] / 100; - } elseif ($result[3] == "Q") { - // ... in hectopascal - $pointer["pressure"] = $this->convertPressure($result[4], "hpa", "in"); - } - break; - case "trend": - // We may have a trend here... extract type and set pointer on - // created new array - if (!isset($weatherData["trend"])) { - $weatherData["trend"] = array(); - $weatherData["trend"][$trendCount] = array(); - } - $pointer =& $weatherData["trend"][$trendCount]; - $trendCount++; - $pointer["type"] = $result[0]; - while (isset($metar[$i + 1]) && preg_match("/^(FM|TL|AT)(\d{2})(\d{2})$/i", $metar[$i + 1], $lresult)) { - if ($lresult[1] == "FM") { - $pointer["from"] = $lresult[2].":".$lresult[3]; - } elseif ($lresult[1] == "TL") { - $pointer["to"] = $lresult[2].":".$lresult[3]; - } else { - $pointer["at"] = $lresult[2].":".$lresult[3]; - } - // As we have just extracted the time for this trend - // from our METAR, increase field-counter - $i++; + if (sizeof($result) == 5) { + // Only amount and height + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100)); + } + elseif (sizeof($result) == 6) { + // Amount, height and type + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100), "type" => $clouds[strtolower($result[5])]); + } + else { + // SKC or CLR or NSC + $cloud = array("amount" => $clouds[strtolower($result[0])]); + } + $pointer["clouds"][] = $cloud; + break; + case "temperature": + // normal temperature in first part + // negative value + if ($result[1] == "M") { + $result[2] *= -1; + } + $pointer["temperature"] = $this->convertTemperature($result[2], "c", "f"); + if (sizeof($result) > 4) { + // same for dewpoint + if ($result[4] == "M") { + $result[5] *= -1; } - break; - case "remark": - // Remark part begins - $metarCode = $remarks; - $weatherData["remark"] = array(); - break; - case "autostation": - // Which autostation do we have here? - if ($result[1] == 0) { - $weatherData["remark"]["autostation"] = "Automatic weatherstation w/o precipitation discriminator"; + $pointer["dewPoint"] = $this->convertTemperature($result[5], "c", "f"); + $pointer["humidity"] = $this->calculateHumidity($result[2], $result[5]); + } + if (isset($pointer["wind"])) { + // Now calculate windchill from temperature and windspeed + $pointer["feltTemperature"] = $this->calculateWindChill($pointer["temperature"], $pointer["wind"]); + } + break; + case "pressure": + if ($result[1] == "A") { + // Pressure provided in inches + $pointer["pressure"] = $result[2] / 100; + } elseif ($result[3] == "Q") { + // ... in hectopascal + $pointer["pressure"] = $this->convertPressure($result[4], "hpa", "in"); + } + break; + case "trend": + // We may have a trend here... extract type and set pointer on + // created new array + if (!isset($weatherData["trend"])) { + $weatherData["trend"] = array(); + $weatherData["trend"][$trendCount] = array(); + } + $pointer =& $weatherData["trend"][$trendCount]; + $trendCount++; + $pointer["type"] = $result[0]; + while (isset($metar[$i + 1]) && preg_match("/^(FM|TL|AT)(\d{2})(\d{2})$/i", $metar[$i + 1], $lresult)) { + if ($lresult[1] == "FM") { + $pointer["from"] = $lresult[2].":".$lresult[3]; + } elseif ($lresult[1] == "TL") { + $pointer["to"] = $lresult[2].":".$lresult[3]; } else { - $weatherData["remark"]["autostation"] = "Automatic weatherstation w/ precipitation discriminator"; + $pointer["at"] = $lresult[2].":".$lresult[3]; } - unset($metarCode["autostation"]); - break; - case "presschg": - // Decoding for rapid pressure changes - if (strtolower($result[1]) == "r") { - $weatherData["remark"]["presschg"] = "Pressure rising rapidly"; + // As we have just extracted the time for this trend + // from our METAR, increase field-counter + $i++; + } + break; + case "remark": + // Remark part begins + $metarCode = $remarks; + $weatherData["remark"] = array(); + break; + case "autostation": + // Which autostation do we have here? + if ($result[1] == 0) { + $weatherData["remark"]["autostation"] = "Automatic weatherstation w/o precipitation discriminator"; + } else { + $weatherData["remark"]["autostation"] = "Automatic weatherstation w/ precipitation discriminator"; + } + unset($metarCode["autostation"]); + break; + case "presschg": + // Decoding for rapid pressure changes + if (strtolower($result[1]) == "r") { + $weatherData["remark"]["presschg"] = "Pressure rising rapidly"; + } else { + $weatherData["remark"]["presschg"] = "Pressure falling rapidly"; + } + unset($metarCode["presschg"]); + break; + case "seapressure": + // Pressure at sea level (delivered in hpa) + // Decoding is a bit obscure as 982 gets 998.2 + // whereas 113 becomes 1113 -> no real rule here + if (strtolower($result[1]) != "no") { + if ($result[1] > 500) { + $press = 900 + round($result[1] / 100, 1); } else { - $weatherData["remark"]["presschg"] = "Pressure falling rapidly"; - } - unset($metarCode["presschg"]); - break; - case "seapressure": - // Pressure at sea level (delivered in hpa) - // Decoding is a bit obscure as 982 gets 998.2 - // whereas 113 becomes 1113 -> no real rule here - if (strtolower($result[1]) != "no") { - if ($result[1] > 500) { - $press = 900 + round($result[1] / 100, 1); - } else { - $press = 1000 + $result[1]; - } - $weatherData["remark"]["seapressure"] = $this->convertPressure($press, "hpa", "in"); - } - unset($metarCode["seapressure"]); - break; - case "precip": - // Precipitation in inches - static $hours; - if (!isset($weatherData["precipitation"])) { - $weatherData["precipitation"] = array(); - $hours = array("P" => "1", "6" => "3/6", "7" => "24"); - } - if (!is_numeric($result[2])) { - $precip = "indeterminable"; - } elseif ($result[2] == "0000") { - $precip = "traceable"; - }else { - $precip = $result[2] / 100; - } - $weatherData["precipitation"][] = array( - "amount" => $precip, - "hours" => $hours[$result[1]] - ); - break; - case "snowdepth": - // Snow depth in inches - $weatherData["remark"]["snowdepth"] = $result[1]; - unset($metarCode["snowdepth"]); - break; - case "snowequiv": - // Same for equivalent in Water... (inches) - $weatherData["remark"]["snowequiv"] = $result[1] / 10; - unset($metarCode["snowequiv"]); - break; - case "cloudtypes": - // Cloud types, haven't found a way for decent decoding (yet) - unset($metarCode["cloudtypes"]); - break; - case "sunduration": - // Duration of sunshine (in minutes) - $weatherData["remark"]["sunduration"] = "Total minutes of sunshine: ".$result[1]; - unset($metarCode["sunduration"]); - break; - case "1htempdew": - // Temperatures in the last hour in C - if ($result[1] == "1") { - $result[2] *= -1; + $press = 1000 + $result[1]; } - $weatherData["remark"]["1htemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + $weatherData["remark"]["seapressure"] = $this->convertPressure($press, "hpa", "in"); + } + unset($metarCode["seapressure"]); + break; + case "precip": + // Precipitation in inches + static $hours; + if (!isset($weatherData["precipitation"])) { + $weatherData["precipitation"] = array(); + $hours = array("P" => "1", "6" => "3/6", "7" => "24"); + } + if (!is_numeric($result[2])) { + $precip = "indeterminable"; + } elseif ($result[2] == "0000") { + $precip = "traceable"; + }else { + $precip = $result[2] / 100; + } + $weatherData["precipitation"][] = array( + "amount" => $precip, + "hours" => $hours[$result[1]] + ); + break; + case "snowdepth": + // Snow depth in inches + $weatherData["remark"]["snowdepth"] = $result[1]; + unset($metarCode["snowdepth"]); + break; + case "snowequiv": + // Same for equivalent in Water... (inches) + $weatherData["remark"]["snowequiv"] = $result[1] / 10; + unset($metarCode["snowequiv"]); + break; + case "cloudtypes": + // Cloud types, haven't found a way for decent decoding (yet) + unset($metarCode["cloudtypes"]); + break; + case "sunduration": + // Duration of sunshine (in minutes) + $weatherData["remark"]["sunduration"] = "Total minutes of sunshine: ".$result[1]; + unset($metarCode["sunduration"]); + break; + case "1htempdew": + // Temperatures in the last hour in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["1htemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - if (sizeof($result) > 3) { - // same for dewpoint - if ($result[4] == "1") { - $result[5] *= -1; - } - $weatherData["remark"]["1hdew"] = $this->convertTemperature($result[5] / 10, "c", "f"); - } - unset($metarCode["1htempdew"]); - break; - case "6hmaxtemp": - // Max temperature in the last 6 hours in C - if ($result[1] == "1") { - $result[2] *= -1; + if (sizeof($result) > 3) { + // same for dewpoint + if ($result[4] == "1") { + $result[5] *= -1; } - $weatherData["remark"]["6hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - unset($metarCode["6hmaxtemp"]); - break; - case "6hmintemp": - // Min temperature in the last 6 hours in C - if ($result[1] == "1") { - $result[2] *= -1; - } - $weatherData["remark"]["6hmintemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - unset($metarCode["6hmintemp"]); - break; - case "24htemp": - // Max/Min temperatures in the last 24 hours in C - if ($result[1] == "1") { - $result[2] *= -1; - } - $weatherData["remark"]["24hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + $weatherData["remark"]["1hdew"] = $this->convertTemperature($result[5] / 10, "c", "f"); + } + unset($metarCode["1htempdew"]); + break; + case "6hmaxtemp": + // Max temperature in the last 6 hours in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["6hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + unset($metarCode["6hmaxtemp"]); + break; + case "6hmintemp": + // Min temperature in the last 6 hours in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["6hmintemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + unset($metarCode["6hmintemp"]); + break; + case "24htemp": + // Max/Min temperatures in the last 24 hours in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["24hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - if ($result[3] == "1") { - $result[4] *= -1; - } - $weatherData["remark"]["24hmintemp"] = $this->convertTemperature($result[4] / 10, "c", "f"); - unset($metarCode["24htemp"]); - break; - case "3hpresstend": - // We don't save the pressure during the day, so no decoding - // possible, sorry - unset($metarCode["3hpresstend"]); - break; - case "nospeci": - // No change during the last hour - $weatherData["remark"]["nospeci"] = "No changes in weather conditions"; - unset($metarCode["nospeci"]); - break; - case "sensors": - // We may have multiple broken sensors, so do not unset - if (!isset($weatherData["remark"]["sensors"])) { - $weatherData["remark"]["sensors"] = array(); - } - $weatherData["remark"]["sensors"][strtolower($result[0])] = $sensors[strtolower($result[0])]; - break; - case "maintain": - $weatherData["remark"]["maintain"] = "Maintainance needed"; - unset($metarCode["maintain"]); - break; - default: - // Do nothing, just prevent further matching - unset($metarCode[$key]); - break; - } - if ($found && !SERVICES_WEATHER_DEBUG) { + if ($result[3] == "1") { + $result[4] *= -1; + } + $weatherData["remark"]["24hmintemp"] = $this->convertTemperature($result[4] / 10, "c", "f"); + unset($metarCode["24htemp"]); break; - } elseif ($found && SERVICES_WEATHER_DEBUG) { - echo $key."\n"; + case "3hpresstend": + // We don't save the pressure during the day, so no decoding + // possible, sorry + unset($metarCode["3hpresstend"]); + break; + case "nospeci": + // No change during the last hour + $weatherData["remark"]["nospeci"] = "No changes in weather conditions"; + unset($metarCode["nospeci"]); + break; + case "sensors": + // We may have multiple broken sensors, so do not unset + if (!isset($weatherData["remark"]["sensors"])) { + $weatherData["remark"]["sensors"] = array(); + } + $weatherData["remark"]["sensors"][strtolower($result[0])] = $sensors[strtolower($result[0])]; + break; + case "maintain": + $weatherData["remark"]["maintain"] = "Maintainance needed"; + unset($metarCode["maintain"]); + break; + default: + // Do nothing, just prevent further matching + unset($metarCode[$key]); break; - } - } - } - if (!$found) { - if (SERVICES_WEATHER_DEBUG) { - echo "n/a\n"; } - if (!isset($weatherData["noparse"])) { - $weatherData["noparse"] = array(); + if ($found && !SERVICES_WEATHER_DEBUG) { + break; + } elseif ($found && SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + break; } - $weatherData["noparse"][] = $metar[$i]; } } + if (!$found) { + if (SERVICES_WEATHER_DEBUG) { + echo "n/a\n"; + } + if (!isset($weatherData["noparse"])) { + $weatherData["noparse"] = array(); + } + $weatherData["noparse"][] = $metar[$i]; + } } + if (isset($weatherData["noparse"])) { $weatherData["noparse"] = implode(" ", $weatherData["noparse"]); } @@ -806,7 +889,7 @@ // {{{ _parseForecastData() /** - * Parses the data returned by the provided source and caches it + * Parses the data and caches it * * TAF KLGA 271734Z 271818 11007KT P6SM -RA SCT020 BKN200 * FM2300 14007KT P6SM SCT030 BKN150 @@ -815,13 +898,13 @@ * TEMPO 1215 5SM -RA BR SCT009 BKN015 * BECMG 1517 16007KT P6SM NSW SCT015 BKN070 * - * @param string $source + * @param array $data * @return PEAR_Error|array * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION * @access private */ - function _parseForecastData($source) + function _parseForecastData($data) { static $compass; static $clouds; @@ -894,315 +977,309 @@ "fmc" => "(PROB|BECMG|TEMPO)(\d{2})?" ); - $data = @file($source); + if (SERVICES_WEATHER_DEBUG) { + for ($i = 0; $i < sizeof($data); $i++) { + echo $data[$i]; + } + } + // Ok, we have correct data, start with parsing the first line for the last update + $forecastData = array(); + $forecastData["station"] = ""; + $forecastData["dataRaw"] = implode(" ", $data); + $forecastData["update"] = strtotime(trim($data[0])." GMT"); + $forecastData["updateRaw"] = trim($data[0]); + // and prepare the rest for stepping through + array_shift($data); + $taf = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); + + // Add a few local variables for data processing + $fromTime = ""; // The timeperiod the data gets added to + $fmcCount = 0; // If we have FMCs (Forecast Meteorological Conditions), we need this + $pointer =& $forecastData; // Pointer to the array we add the data to + for ($i = 0; $i < sizeof($taf); $i++) { + // Check for whitespace and step loop, if nothing's there + $taf[$i] = trim($taf[$i]); + if (!strlen($taf[$i])) { + continue; + } - // Check for correct data - if (!$data || !is_array($data) || sizeof($data) < 2) { - return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); - } else { if (SERVICES_WEATHER_DEBUG) { - for ($i = 0; $i < sizeof($data); $i++) { - echo $data[$i]; - } + $tab = str_repeat("\t", 2 - floor((strlen($taf[$i]) + 2) / 8)); + echo "\"".$taf[$i]."\"".$tab."-> "; } - // Ok, we have correct data, start with parsing the first line for the last update - $forecastData = array(); - $forecastData["station"] = ""; - $forecastData["dataRaw"] = implode(" ", $data); - $forecastData["update"] = strtotime(trim($data[0])." GMT"); - $forecastData["updateRaw"] = trim($data[0]); - // and prepare the rest for stepping through - array_shift($data); - $taf = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); - - // Add a few local variables for data processing - $fromTime = ""; // The timeperiod the data gets added to - $fmcCount = 0; // If we have FMCs (Forecast Meteorological Conditions), we need this - $pointer =& $forecastData; // Pointer to the array we add the data to - for ($i = 0; $i < sizeof($taf); $i++) { - // Check for whitespace and step loop, if nothing's there - $taf[$i] = trim($taf[$i]); - if (!strlen($taf[$i])) { - continue; - } - - if (SERVICES_WEATHER_DEBUG) { - $tab = str_repeat("\t", 2 - floor((strlen($taf[$i]) + 2) / 8)); - echo "\"".$taf[$i]."\"".$tab."-> "; - } - // Initialize some arrays - $result = array(); - $resultVF = array(); - $lresult = array(); - - $found = false; - foreach ($tafCode as $key => $regexp) { - // Check if current code matches current taf snippet - if (($found = preg_match("/^".$regexp."$/i", $taf[$i], $result)) == true) { - $insert = array(); - switch ($key) { - case "station": - $pointer["station"] = $result[0]; - unset($tafCode["station"]); - break; - case "valid": - $pointer["validRaw"] = $result[0]; - // Generates the timeperiod the report is valid for - list($year, $month, $day) = explode("-", date("Y-m-d", $forecastData["update"])); - // Date is in next month - if ($result[1] < $day) { - $month++; - } - $pointer["validFrom"] = gmmktime($result[2], 0, 0, $month, $result[1], $year); - // Valid time ends next day - if ($result[2] >= $result[3]) { - $result[1]++; - } - $pointer["validTo"] = gmmktime($result[3], 0, 0, $month, $result[1], $year); - unset($tafCode["valid"]); - // Now the groups will start, so initialize the time groups - $pointer["time"] = array(); - $fromTime = $result[2].":00"; - $pointer["time"][$fromTime] = array(); - // Set pointer to the first timeperiod - $pointer =& $pointer["time"][$fromTime]; + // Initialize some arrays + $result = array(); + $resultVF = array(); + $lresult = array(); + + $found = false; + foreach ($tafCode as $key => $regexp) { + // Check if current code matches current taf snippet + if (($found = preg_match("/^".$regexp."$/i", $taf[$i], $result)) == true) { + $insert = array(); + switch ($key) { + case "station": + $pointer["station"] = $result[0]; + unset($tafCode["station"]); + break; + case "valid": + $pointer["validRaw"] = $result[0]; + // Generates the timeperiod the report is valid for + list($year, $month, $day) = explode("-", date("Y-m-d", $forecastData["update"])); + // Date is in next month + if ($result[1] < $day) { + $month++; + } + $pointer["validFrom"] = gmmktime($result[2], 0, 0, $month, $result[1], $year); + // Valid time ends next day + if ($result[2] >= $result[3]) { + $result[1]++; + } + $pointer["validTo"] = gmmktime($result[3], 0, 0, $month, $result[1], $year); + unset($tafCode["valid"]); + // Now the groups will start, so initialize the time groups + $pointer["time"] = array(); + $fromTime = $result[2].":00"; + $pointer["time"][$fromTime] = array(); + // Set pointer to the first timeperiod + $pointer =& $pointer["time"][$fromTime]; + break; + case "wind": + // Parse wind data, first the speed, convert from kt to chosen unit + $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); + if ($result[1] == "VAR" || $result[1] == "VRB") { + // Variable winds + $pointer["windDegrees"] = "Variable"; + $pointer["windDirection"] = "Variable"; + } else { + // Save wind degree and calc direction + $pointer["windDegrees"] = $result[1]; + $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; + } + if (is_numeric($result[4])) { + // Wind with gusts... + $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); + } + if (isset($probability)) { + $pointer["windProb"] = $probability; + unset($probability); + } + break; + case "visFrac": + // Possible fractional visibility here. Check if it matches with the next TAF piece for visibility + if (!isset($taf[$i + 1]) || !preg_match("/^".$tafCode["visibility"]."$/i", $result[1]." ".$taf[$i + 1], $resultVF)) { + // No next TAF piece available or not matching. Match against next TAF code + $found = false; break; - case "wind": - // Parse wind data, first the speed, convert from kt to chosen unit - $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); - if ($result[1] == "VAR" || $result[1] == "VRB") { - // Variable winds - $pointer["windDegrees"] = "Variable"; - $pointer["windDirection"] = "Variable"; - } else { - // Save wind degree and calc direction - $pointer["windDegrees"] = $result[1]; - $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; - } - if (is_numeric($result[4])) { - // Wind with gusts... - $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); - } - if (isset($probability)) { - $pointer["windProb"] = $probability; - unset($probability); + } else { + // Match. Hand over result and advance TAF + if (SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + echo "\"".$result[1]." ".$taf[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$taf[$i + 1]) + 2) / 8))."-> "; + } + $key = "visibility"; + $result = $resultVF; + $i++; + } + case "visibility": + $pointer["visQualifier"] = "AT"; + if (is_numeric($result[1]) && ($result[1] == 9999)) { + // Upper limit of visibility range + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["visQualifier"] = "BEYOND"; + } elseif (is_numeric($result[1])) { + // 4-digit visibility in m + $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); + } elseif (!isset($result[11]) || $result[11] != "CAVOK") { + if ($result[3] == "M") { + $pointer["visQualifier"] = "BELOW"; + } elseif ($result[3] == "P") { + $pointer["visQualifier"] = "BEYOND"; } - break; - case "visFrac": - // Possible fractional visibility here. Check if it matches with the next TAF piece for visibility - if (!isset($taf[$i + 1]) || !preg_match("/^".$tafCode["visibility"]."$/i", $result[1]." ".$taf[$i + 1], $resultVF)) { - // No next TAF piece available or not matching. Match against next TAF code - $found = false; - break; + if (is_numeric($result[5])) { + // visibility as one/two-digit number + $visibility = $this->convertDistance($result[5], $result[10], "sm"); } else { - // Match. Hand over result and advance TAF - if (SERVICES_WEATHER_DEBUG) { - echo $key."\n"; - echo "\"".$result[1]." ".$taf[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$taf[$i + 1]) + 2) / 8))."-> "; - } - $key = "visibility"; - $result = $resultVF; - $i++; - } - case "visibility": - $pointer["visQualifier"] = "AT"; - if (is_numeric($result[1]) && ($result[1] == 9999)) { - // Upper limit of visibility range - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["visQualifier"] = "BEYOND"; - } elseif (is_numeric($result[1])) { - // 4-digit visibility in m - $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); - } elseif (!isset($result[11]) || $result[11] != "CAVOK") { - if ($result[3] == "M") { - $pointer["visQualifier"] = "BELOW"; - } elseif ($result[3] == "P") { - $pointer["visQualifier"] = "BEYOND"; - } - if (is_numeric($result[5])) { - // visibility as one/two-digit number - $visibility = $this->convertDistance($result[5], $result[10], "sm"); + // the y/z part, add if we had a x part (see visibility1) + if (is_numeric($result[7])) { + $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); } else { - // the y/z part, add if we had a x part (see visibility1) - if (is_numeric($result[7])) { - $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); - } else { - $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); - } + $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); } - } else { - $pointer["visQualifier"] = "BEYOND"; - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); - $pointer["condition"] = "no significant weather"; - } - if (isset($probability)) { - $pointer["visProb"] = $probability; - unset($probability); - } - $pointer["visibility"] = $visibility; - break; - case "condition": - // First some basic setups - if (!isset($pointer["condition"])) { - $pointer["condition"] = ""; - } elseif (strlen($pointer["condition"]) > 0) { - $pointer["condition"] .= ","; } + } else { + $pointer["visQualifier"] = "BEYOND"; + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); + $pointer["condition"] = "no significant weather"; + } + if (isset($probability)) { + $pointer["visProb"] = $probability; + unset($probability); + } + $pointer["visibility"] = $visibility; + break; + case "condition": + // First some basic setups + if (!isset($pointer["condition"])) { + $pointer["condition"] = ""; + } elseif (strlen($pointer["condition"]) > 0) { + $pointer["condition"] .= ","; + } - if (in_array(strtolower($result[0]), $conditions)) { - // First try matching the complete string - $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; - } else { - // No luck, match part by part - array_shift($result); - $result = array_unique($result); - foreach ($result as $condition) { - if (strlen($condition) > 0) { - $pointer["condition"] .= " ".$conditions[strtolower($condition)]; - } + if (in_array(strtolower($result[0]), $conditions)) { + // First try matching the complete string + $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; + } else { + // No luck, match part by part + array_shift($result); + $result = array_unique($result); + foreach ($result as $condition) { + if (strlen($condition) > 0) { + $pointer["condition"] .= " ".$conditions[strtolower($condition)]; } } - $pointer["condition"] = trim($pointer["condition"]); - if (isset($probability)) { - $pointer["condition"] .= " (".$probability."% prob.)"; - unset($probability); - } - break; - case "clouds": - if (!isset($pointer["clouds"])) { - $pointer["clouds"] = array(); - } + } + $pointer["condition"] = trim($pointer["condition"]); + if (isset($probability)) { + $pointer["condition"] .= " (".$probability."% prob.)"; + unset($probability); + } + break; + case "clouds": + if (!isset($pointer["clouds"])) { + $pointer["clouds"] = array(); + } - if (sizeof($result) == 5) { - // Only amount and height - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100)); - } - elseif (sizeof($result) == 6) { - // Amount, height and type - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100), "type" => $clouds[strtolower($result[5])]); - } - else { - // SKC or CLR or NSC - $cloud = array("amount" => $clouds[strtolower($result[0])]); - } - if(isset($probability)) { - $cloud["prob"] = $probability; - unset($probability); - } - $pointer["clouds"][] = $cloud; - break; - case "windshear": - // Parse windshear, if available - $pointer["windshear"] = $this->convertSpeed($result[3], strtolower($result[4]), "mph"); - $pointer["windshearHeight"] = $result[1] * 100; - $pointer["windshearDegrees"] = $result[2]; - $pointer["windshearDirection"] = $compass[round($result[2] / 22.5) % 16]; - break; - case "tempmax": - $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); - break; - case "tempmin": - // Parse max/min temperature - $forecastData["temperatureLow"] = $this->convertTemperature($result[1], "c", "f"); - break; - case "tempmaxmin": - $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); - $forecastData["temperatureLow"] = $this->convertTemperature($result[4], "c", "f"); - break; - case "from": - // Next timeperiod is coming up, prepare array and - // set pointer accordingly - if (sizeof($result) > 2) { - // The ICAO way - $fromTime = $result[1].":".$result[2]; - } else { - // The Australian way (Hey mates!) - $fromTime = $result[1].":00"; + if (sizeof($result) == 5) { + // Only amount and height + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100)); + } + elseif (sizeof($result) == 6) { + // Amount, height and type + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100), "type" => $clouds[strtolower($result[5])]); + } + else { + // SKC or CLR or NSC + $cloud = array("amount" => $clouds[strtolower($result[0])]); + } + if(isset($probability)) { + $cloud["prob"] = $probability; + unset($probability); + } + $pointer["clouds"][] = $cloud; + break; + case "windshear": + // Parse windshear, if available + $pointer["windshear"] = $this->convertSpeed($result[3], strtolower($result[4]), "mph"); + $pointer["windshearHeight"] = $result[1] * 100; + $pointer["windshearDegrees"] = $result[2]; + $pointer["windshearDirection"] = $compass[round($result[2] / 22.5) % 16]; + break; + case "tempmax": + $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); + break; + case "tempmin": + // Parse max/min temperature + $forecastData["temperatureLow"] = $this->convertTemperature($result[1], "c", "f"); + break; + case "tempmaxmin": + $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); + $forecastData["temperatureLow"] = $this->convertTemperature($result[4], "c", "f"); + break; + case "from": + // Next timeperiod is coming up, prepare array and + // set pointer accordingly + if (sizeof($result) > 2) { + // The ICAO way + $fromTime = $result[1].":".$result[2]; + } else { + // The Australian way (Hey mates!) + $fromTime = $result[1].":00"; + } + $forecastData["time"][$fromTime] = array(); + $fmcCount = 0; + $pointer =& $forecastData["time"][$fromTime]; + break; + case "fmc"; + // Test, if this is a probability for the next FMC + if (preg_match("/^BECMG|TEMPO$/i", $taf[$i + 1], $lresult)) { + // Set type to BECMG or TEMPO + $type = $lresult[0]; + // Set probability + $probability = $result[2]; + // Now extract time for this group + preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 2], $lresult); + $from = $lresult[1].":00"; + $to = $lresult[2].":00"; + $to = ($to == "24:00") ? "00:00" : $to; + // As we now have type, probability and time for this FMC + // from our TAF, increase field-counter + $i += 2; + } elseif (preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 1], $lresult)) { + // Normal group, set type and use extracted time + $type = $result[1]; + // Check for PROBdd + if (isset($result[2])) { + $probability = $result[2]; } - $forecastData["time"][$fromTime] = array(); - $fmcCount = 0; - $pointer =& $forecastData["time"][$fromTime]; - break; - case "fmc"; - // Test, if this is a probability for the next FMC - if (preg_match("/^BECMG|TEMPO$/i", $taf[$i + 1], $lresult)) { - // Set type to BECMG or TEMPO - $type = $lresult[0]; - // Set probability + $from = $lresult[1].":00"; + $to = $lresult[2].":00"; + $to = ($to == "24:00") ? "00:00" : $to; + // Same as above, we have a time for this FMC from our TAF, + // increase field-counter + $i += 1; + } else { + // This is either a PROBdd or a malformed TAF + if (isset($result[2])) { $probability = $result[2]; - // Now extract time for this group - preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 2], $lresult); - $from = $lresult[1].":00"; - $to = $lresult[2].":00"; - $to = ($to == "24:00") ? "00:00" : $to; - // As we now have type, probability and time for this FMC - // from our TAF, increase field-counter - $i += 2; - } elseif (preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 1], $lresult)) { - // Normal group, set type and use extracted time - $type = $result[1]; - // Check for PROBdd - if (isset($result[2])) { - $probability = $result[2]; - } - $from = $lresult[1].":00"; - $to = $lresult[2].":00"; - $to = ($to == "24:00") ? "00:00" : $to; - // Same as above, we have a time for this FMC from our TAF, - // increase field-counter - $i += 1; - } else { - // This is either a PROBdd or a malformed TAF - if (isset($result[2])) { - $probability = $result[2]; - } } + } - // Handle the FMC, generate neccessary array if it's the first... - if (isset($type)) { - if (!isset($forecastData["time"][$fromTime]["fmc"])) { - $forecastData["time"][$fromTime]["fmc"] = array(); - } - $forecastData["time"][$fromTime]["fmc"][$fmcCount] = array(); - // ...and set pointer. - $pointer =& $forecastData["time"][$fromTime]["fmc"][$fmcCount]; - $fmcCount++; - // Insert data - $pointer["type"] = $type; - $pointer["from"] = $from; - $pointer["to"] = $to; - unset($type, $from, $to); - if (isset($probability)) { - $pointer["probability"] = $probability; - unset($probability); - } + // Handle the FMC, generate neccessary array if it's the first... + if (isset($type)) { + if (!isset($forecastData["time"][$fromTime]["fmc"])) { + $forecastData["time"][$fromTime]["fmc"] = array(); + } + $forecastData["time"][$fromTime]["fmc"][$fmcCount] = array(); + // ...and set pointer. + $pointer =& $forecastData["time"][$fromTime]["fmc"][$fmcCount]; + $fmcCount++; + // Insert data + $pointer["type"] = $type; + $pointer["from"] = $from; + $pointer["to"] = $to; + unset($type, $from, $to); + if (isset($probability)) { + $pointer["probability"] = $probability; + unset($probability); } - break; - default: - // Do nothing - break; - } - if ($found && !SERVICES_WEATHER_DEBUG) { + } break; - } elseif ($found && SERVICES_WEATHER_DEBUG) { - echo $key."\n"; + default: + // Do nothing break; - } - } - } - if (!$found) { - if (SERVICES_WEATHER_DEBUG) { - echo "n/a\n"; } - if (!isset($forecastData["noparse"])) { - $forecastData["noparse"] = array(); + if ($found && !SERVICES_WEATHER_DEBUG) { + break; + } elseif ($found && SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + break; } - $forecastData["noparse"][] = $taf[$i]; } } + if (!$found) { + if (SERVICES_WEATHER_DEBUG) { + echo "n/a\n"; + } + if (!isset($forecastData["noparse"])) { + $forecastData["noparse"] = array(); + } + $forecastData["noparse"][] = $taf[$i]; + } } + if (isset($forecastData["noparse"])) { $forecastData["noparse"] = implode(" ", $forecastData["noparse"]); } @@ -1625,15 +1702,16 @@ $this->_weather = $weatherReturn; $weatherReturn["cache"] = "HIT"; } else { - // Set the source - if ($this->_sourceMetar == "file") { - $source = realpath($this->_sourcePathMetar."/".$id.".TXT"); - } else { - $source = $this->_sourcePathMetar."/".$id.".TXT"; - } - - // Download and parse weather - $weatherReturn = $this->_parseWeatherData($source); + // Download weather + $weatherData = $this->_retrieveServerData($id, "metar"); + if (Services_Weather::isError($weatherData)) { + return $weatherData; + } elseif (!is_array($weatherData) || sizeof($weatherData) < 2) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + // Parse weather + $weatherReturn = $this->_parseWeatherData($weatherData); if (Services_Weather::isError($weatherReturn)) { return $weatherReturn; @@ -1688,15 +1766,16 @@ $this->_forecast = $forecastReturn; $forecastReturn["cache"] = "HIT"; } else { - // Set the source - if ($this->_sourceTaf == "file") { - $source = realpath($this->_sourcePathTaf."/".$id.".TXT"); - } else { - $source = $this->_sourcePathTaf."/".$id.".TXT"; + // Download forecast + $forecastData = $this->_retrieveServerData($id, "taf"); + if (Services_Weather::isError($forecastData)) { + return $forecastData; + } elseif (!is_array($forecastData) || sizeof($forecastData) < 2) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); } - // Download and parse weather - $forecastReturn = $this->_parseForecastData($source); + // Parse forecast + $forecastReturn = $this->_parseForecastData($forecastData); if (Services_Weather::isError($forecastReturn)) { return $forecastReturn; http://cvs.php.net/diff.php/pear/Services_Weather/Weather/Common.php?r1=1.46&r2=1.47&ty=u Index: pear/Services_Weather/Weather/Common.php diff -u pear/Services_Weather/Weather/Common.php:1.46 pear/Services_Weather/Weather/Common.php:1.47 --- pear/Services_Weather/Weather/Common.php:1.46 Wed Nov 9 18:46:56 2005 +++ pear/Services_Weather/Weather/Common.php Fri Nov 11 09:33:14 2005 @@ -40,7 +40,7 @@ * @author Alexander Wirtz <alex@pc4p.net> * @copyright 2005 Alexander Wirtz * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: Common.php,v 1.46 2005/11/09 23:46:56 eru Exp $ + * @version CVS: $Id: Common.php,v 1.47 2005/11/11 14:33:14 eru Exp $ * @link http://pear.php.net/package/Services_Weather * @filesource */ @@ -327,20 +327,18 @@ */ function setHttpProxy($httpProxy) { - $proxy = array(); - - if (preg_match("#http://(?:([^:^@]+)?:?([^@]+)?@)?([^:]+)(?::(\d+))?#", $httpProxy, $proxy)) { - if (isset($proxy[1]) && $proxy[1] != "") { - $this->_httpOptions["proxy_user"] = $proxy[1]; + if (($proxy = parse_url($httpProxy)) !== false && $proxy["scheme"] == "http") { + if (isset($proxy["user"]) && $proxy["user"] != "") { + $this->_httpOptions["proxy_user"] = $proxy["user"]; } - if (isset($proxy[2]) && $proxy[2] != "") { - $this->_httpOptions["proxy_pass"] = $proxy[2]; + if (isset($proxy["pass"]) && $proxy["pass"] != "") { + $this->_httpOptions["proxy_pass"] = $proxy["pass"]; } - if (isset($proxy[3]) && $proxy[3] != "") { - $this->_httpOptions["proxy_host"] = $proxy[3]; + if (isset($proxy["host"]) && $proxy["host"] != "") { + $this->_httpOptions["proxy_host"] = $proxy["host"]; } - if (isset($proxy[4]) && $proxy[4] != "") { - $this->_httpOptions["proxy_port"] = $proxy[4]; + if (isset($proxy["port"]) && $proxy["port"] != "") { + $this->_httpOptions["proxy_port"] = $proxy["port"]; } return true; http://cvs.php.net/diff.php/pear/Services_Weather/Weather.php?r1=1.39&r2=1.40&ty=u Index: pear/Services_Weather/Weather.php diff -u pear/Services_Weather/Weather.php:1.39 pear/Services_Weather/Weather.php:1.40 --- pear/Services_Weather/Weather.php:1.39 Wed Nov 9 16:47:17 2005 +++ pear/Services_Weather/Weather.php Fri Nov 11 09:33:15 2005 @@ -46,7 +46,7 @@ * @author Alexander Wirtz <alex@pc4p.net> * @copyright 2005 Alexander Wirtz * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: Weather.php,v 1.39 2005/11/09 21:47:17 eru Exp $ + * @version CVS: $Id: Weather.php,v 1.40 2005/11/11 14:33:15 eru Exp $ * @link http://pear.php.net/package/Services_Weather * @filesource */ @@ -69,6 +69,7 @@ define("SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID", 15); define("SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID", 16); define("SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID", 17); +define("SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID", 18); // }}} // {{{ error codes defined by weather.com @@ -205,6 +206,7 @@ SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID => "The given proxy is not valid, please use the notation http://[user[:pass]@]host[:port].", SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID => "The date you've provided for calculation of sunrise/sunset is not a timestamp.", SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID => "The return format you've provided for calculation of sunrise/sunset is not valid.", + SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID => "The METAR/TAF source you've provided has an invalid type or path.", SERVICES_WEATHER_ERROR_UNKNOWN_ERROR => "An unknown error has occured.", SERVICES_WEATHER_ERROR_NO_LOCATION => "No location provided.", SERVICES_WEATHER_ERROR_INVALID_LOCATION => "Invalid location provided.",
http://cvs.php.net/diff.php/pear/Services_Weather/Weather/Metar.php?r1=1.77&r2=1.78&ty=u Index: pear/Services_Weather/Weather/Metar.php diff -u pear/Services_Weather/Weather/Metar.php:1.77 pear/Services_Weather/Weather/Metar.php:1.78 --- pear/Services_Weather/Weather/Metar.php:1.77 Wed Nov 9 17:52:44 2005 +++ pear/Services_Weather/Weather/Metar.php Fri Nov 11 09:33:14 2005 @@ -40,7 +40,7 @@ * @author Alexander Wirtz <alex@pc4p.net> * @copyright 2005 Alexander Wirtz * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: Metar.php,v 1.77 2005/11/09 22:52:44 eru Exp $ + * @version CVS: $Id: Metar.php,v 1.78 2005/11/11 14:33:14 eru Exp $ * @link http://pear.php.net/package/Services_Weather * @link http://weather.noaa.gov/weather/metar.shtml * @link http://weather.noaa.gov/weather/taf.shtml @@ -236,46 +236,64 @@ * @param string $sourcePathMetar * @param string $sourceTaf * @param string $sourcePathTaf + * @return PEAR_ERROR|bool + * @throws PEAR_Error::SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID * @access public */ function setMetarSource($sourceMetar, $sourcePathMetar = "", $sourceTaf = "", $sourcePathTaf = "") { if (in_array($sourceMetar, array("http", "ftp", "file"))) { $this->_sourceMetar = $sourceMetar; + } else { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); } + clearstatcache(); if (strlen($sourcePathMetar)) { - $this->_sourcePathMetar = $sourcePathMetar; + if (($this->_sourceMetar == "file" && is_dir($sourcePathMetar)) || ($this->_sourceMetar != "file" && parse_url($sourcePathMetar))) { + $this->_sourcePathMetar = $sourcePathMetar; + } else { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); + } } else { switch ($sourceMetar) { case "http": - $this->_sourcePathMetar = "http://weather.noaa.gov/pub/data/observations/metar/stations/"; + $this->_sourcePathMetar = "http://weather.noaa.gov/pub/data/observations/metar/stations"; break; case "ftp": - $this->_sourcePathMetar = "ftp://weather.noaa.gov/data/observations/metar/stations/"; + $this->_sourcePathMetar = "ftp://weather.noaa.gov/data/observations/metar/stations"; break; case "file": - $this->_sourcePathMetar = "./"; + $this->_sourcePathMetar = "."; break; } } if (in_array($sourceTaf, array("http", "ftp", "file"))) { $this->_sourceTaf = $sourceTaf; + } elseif ($sourceTaf != "") { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); } + clearstatcache(); if (strlen($sourcePathTaf)) { - $this->_sourcePathTaf = $sourcePathTaf; + if (($this->_sourceTaf == "file" && is_dir($sourcePathTaf)) || ($this->_sourceTaf != "file" && parse_url($sourcePathTaf))) { + $this->_sourcePathTaf = $sourcePathTaf; + } else { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID, __FILE__, __LINE__); + } } else { switch ($sourceTaf) { case "http": - $this->_sourcePathTaf = "http://weather.noaa.gov/pub/data/forecasts/taf/stations/"; + $this->_sourcePathTaf = "http://weather.noaa.gov/pub/data/forecasts/taf/stations"; break; case "ftp": - $this->_sourcePathTaf = "ftp://weather.noaa.gov/data/forecasts/taf/stations/"; + $this->_sourcePathTaf = "ftp://weather.noaa.gov/data/forecasts/taf/stations"; break; case "file": - $this->_sourcePathTaf = "./"; + $this->_sourcePathTaf = "."; break; } } + + return true; } // }}} @@ -302,20 +320,91 @@ } // }}} + /** + * Downloads the weather- or forecast-data for an id from the server dependant on the datatype and returns it + * + * @param string $id + * @param string $dataType + * @return PEAR_Error|array + * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA + * @access private + */ + // {{{ _retrieveServerData() + function _retrieveServerData($id, $dataType) { + switch($this->{"_source".ucfirst($dataType)}) { + case "file": + $source = realpath($this->{"_sourcePath".ucfirst($dataType)}."/".$id.".TXT"); + $data = @file_get_contents($source); + if ($data === false) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + break; + case "http": + include_once "HTTP/Request.php"; + + $request = &new HTTP_Request($this->{"_sourcePath".ucfirst($dataType)}."/".$id.".TXT", $this->_httpOptions); + $status = $request->sendRequest(); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $data = $request->getResponseBody(); + break; + case "ftp": + include_once "Net/FTP.php"; + + $server = parse_url($this->{"_sourcePath".ucfirst($dataType)}."/".$id.".TXT"); + + if (!isset($server["port"]) || $server["port"] == "" || $server["port"] == 0) { + $server["port"] = 21; + } + if (!isset($server["user"]) || $server["user"] == "") { + $server["user"] = "ftp"; + } + if (!isset($server["pass"]) || $server["pass"] == "") { + $server["pass"] = "ftp@"; + } + + $ftp = &new Net_FTP($server["host"], $server["port"], $this->_httpOptions["timeout"]); + $status = $ftp->connect(); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $status = $ftp->login($server["user"], $server["pass"]); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $tempfile = tempnam(); + $status = $ftp->get($server["path"], $tempfile, true, FTP_ASCII); + if (Services_Weather::isError($status)) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + $ftp->disconnect(); + $data = @file_get_contents($tempfile); + break; + } + + return preg_split("/\n|\r\n|\n\r/", $data); + } + // }}} + // {{{ _parseWeatherData() /** - * Parses the data returned by the provided source and caches it + * Parses the data and caches it * * METAR KPIT 091955Z COR 22015G25KT 3/4SM R28L/2600FT TSRA OVC010CB * 18/16 A2992 RMK SLP045 T01820159 * - * @param string $source + * @param array $data * @return PEAR_Error|array * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION * @access private */ - function _parseWeatherData($source) + function _parseWeatherData($data) { static $compass; static $clouds; @@ -416,386 +505,380 @@ "maintain" => "[\$]" ); - $data = @file($source); + if (SERVICES_WEATHER_DEBUG) { + for ($i = 0; $i < sizeof($data); $i++) { + echo $data[$i]; + } + } + // Start with parsing the first line for the last update + $weatherData = array(); + $weatherData["station"] = ""; + $weatherData["dataRaw"] = implode(" ", $data); + $weatherData["update"] = strtotime(trim($data[0])." GMT"); + $weatherData["updateRaw"] = trim($data[0]); + // and prepare the rest for stepping through + array_shift($data); + $metar = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); + + // Add a few local variables for data processing + $trendCount = 0; // If we have trends, we need this + $pointer =& $weatherData; // Pointer to the array we add the data to + for ($i = 0; $i < sizeof($metar); $i++) { + // Check for whitespace and step loop, if nothing's there + $metar[$i] = trim($metar[$i]); + if (!strlen($metar[$i])) { + continue; + } - // Check for correct data, 2 lines in size - if (!$data || !is_array($data) || sizeof($data) < 2) { - return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); - } else { if (SERVICES_WEATHER_DEBUG) { - for ($i = 0; $i < sizeof($data); $i++) { - echo $data[$i]; - } + $tab = str_repeat("\t", 2 - floor((strlen($metar[$i]) + 2) / 8)); + echo "\"".$metar[$i]."\"".$tab."-> "; } - // Ok, we have correct data, start with parsing the first line for the last update - $weatherData = array(); - $weatherData["station"] = ""; - $weatherData["dataRaw"] = implode(" ", $data); - $weatherData["update"] = strtotime(trim($data[0])." GMT"); - $weatherData["updateRaw"] = trim($data[0]); - // and prepare the rest for stepping through - array_shift($data); - $metar = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); - - // Add a few local variables for data processing - $trendCount = 0; // If we have trends, we need this - $pointer =& $weatherData; // Pointer to the array we add the data to - for ($i = 0; $i < sizeof($metar); $i++) { - // Check for whitespace and step loop, if nothing's there - $metar[$i] = trim($metar[$i]); - if (!strlen($metar[$i])) { - continue; - } - - if (SERVICES_WEATHER_DEBUG) { - $tab = str_repeat("\t", 2 - floor((strlen($metar[$i]) + 2) / 8)); - echo "\"".$metar[$i]."\"".$tab."-> "; - } - - // Initialize some arrays - $result = array(); - $resultVF = array(); - $lresult = array(); - - $found = false; - foreach ($metarCode as $key => $regexp) { - // Check if current code matches current metar snippet - if (($found = preg_match("/^".$regexp."$/i", $metar[$i], $result)) == true) { - switch ($key) { - case "station": - $pointer["station"] = $result[0]; - unset($metarCode["station"]); + + // Initialize some arrays + $result = array(); + $resultVF = array(); + $lresult = array(); + + $found = false; + foreach ($metarCode as $key => $regexp) { + // Check if current code matches current metar snippet + if (($found = preg_match("/^".$regexp."$/i", $metar[$i], $result)) == true) { + switch ($key) { + case "station": + $pointer["station"] = $result[0]; + unset($metarCode["station"]); + break; + case "wind": + // Parse wind data, first the speed, convert from kt to chosen unit + $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); + if ($result[1] == "VAR" || $result[1] == "VRB") { + // Variable winds + $pointer["windDegrees"] = "Variable"; + $pointer["windDirection"] = "Variable"; + } else { + // Save wind degree and calc direction + $pointer["windDegrees"] = intval($result[1]); + $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; + } + if (is_numeric($result[4])) { + // Wind with gusts... + $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); + } + break; + case "windVar": + // Once more wind, now variability around the current wind-direction + $pointer["windVariability"] = array("from" => intval($result[1]), "to" => intval($result[2])); + break; + case "visFrac": + // Possible fractional visibility here. Check if it matches with the next METAR piece for visibility + if (!isset($metar[$i + 1]) || !preg_match("/^".$metarCode["visibility"]."$/i", $result[1]." ".$metar[$i + 1], $resultVF)) { + // No next METAR piece available or not matching. Match against next METAR code + $found = false; break; - case "wind": - // Parse wind data, first the speed, convert from kt to chosen unit - $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); - if ($result[1] == "VAR" || $result[1] == "VRB") { - // Variable winds - $pointer["windDegrees"] = "Variable"; - $pointer["windDirection"] = "Variable"; - } else { - // Save wind degree and calc direction - $pointer["windDegrees"] = intval($result[1]); - $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; - } - if (is_numeric($result[4])) { - // Wind with gusts... - $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); + } else { + // Match. Hand over result and advance METAR + if (SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + echo "\"".$result[1]." ".$metar[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$metar[$i + 1]) + 2) / 8))."-> "; + } + $key = "visibility"; + $result = $resultVF; + $i++; + } + case "visibility": + $pointer["visQualifier"] = "AT"; + if (is_numeric($result[1]) && ($result[1] == 9999)) { + // Upper limit of visibility range + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["visQualifier"] = "BEYOND"; + } elseif (is_numeric($result[1])) { + // 4-digit visibility in m + $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); + } elseif (!isset($result[11]) || $result[11] != "CAVOK") { + if ($result[3] == "M") { + $pointer["visQualifier"] = "BELOW"; + } elseif ($result[3] == "P") { + $pointer["visQualifier"] = "BEYOND"; } - break; - case "windVar": - // Once more wind, now variability around the current wind-direction - $pointer["windVariability"] = array("from" => intval($result[1]), "to" => intval($result[2])); - break; - case "visFrac": - // Possible fractional visibility here. Check if it matches with the next METAR piece for visibility - if (!isset($metar[$i + 1]) || !preg_match("/^".$metarCode["visibility"]."$/i", $result[1]." ".$metar[$i + 1], $resultVF)) { - // No next METAR piece available or not matching. Match against next METAR code - $found = false; - break; + if (is_numeric($result[5])) { + // visibility as one/two-digit number + $visibility = $this->convertDistance($result[5], $result[10], "sm"); } else { - // Match. Hand over result and advance METAR - if (SERVICES_WEATHER_DEBUG) { - echo $key."\n"; - echo "\"".$result[1]." ".$metar[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$metar[$i + 1]) + 2) / 8))."-> "; - } - $key = "visibility"; - $result = $resultVF; - $i++; - } - case "visibility": - $pointer["visQualifier"] = "AT"; - if (is_numeric($result[1]) && ($result[1] == 9999)) { - // Upper limit of visibility range - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["visQualifier"] = "BEYOND"; - } elseif (is_numeric($result[1])) { - // 4-digit visibility in m - $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); - } elseif (!isset($result[11]) || $result[11] != "CAVOK") { - if ($result[3] == "M") { - $pointer["visQualifier"] = "BELOW"; - } elseif ($result[3] == "P") { - $pointer["visQualifier"] = "BEYOND"; - } - if (is_numeric($result[5])) { - // visibility as one/two-digit number - $visibility = $this->convertDistance($result[5], $result[10], "sm"); + // the y/z part, add if we had a x part (see visibility1) + if (is_numeric($result[7])) { + $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); } else { - // the y/z part, add if we had a x part (see visibility1) - if (is_numeric($result[7])) { - $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); - } else { - $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); - } + $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); } - } else { - $pointer["visQualifier"] = "BEYOND"; - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); - $pointer["condition"] = "no significant weather"; - } - $pointer["visibility"] = $visibility; - break; - case "condition": - // First some basic setups - if (!isset($pointer["condition"])) { - $pointer["condition"] = ""; - } elseif (strlen($pointer["condition"]) > 0) { - $pointer["condition"] .= ","; } + } else { + $pointer["visQualifier"] = "BEYOND"; + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); + $pointer["condition"] = "no significant weather"; + } + $pointer["visibility"] = $visibility; + break; + case "condition": + // First some basic setups + if (!isset($pointer["condition"])) { + $pointer["condition"] = ""; + } elseif (strlen($pointer["condition"]) > 0) { + $pointer["condition"] .= ","; + } - if (in_array(strtolower($result[0]), $conditions)) { - // First try matching the complete string - $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; - } else { - // No luck, match part by part - array_shift($result); - $result = array_unique($result); - foreach ($result as $condition) { - if (strlen($condition) > 0) { - $pointer["condition"] .= " ".$conditions[strtolower($condition)]; - } + if (in_array(strtolower($result[0]), $conditions)) { + // First try matching the complete string + $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; + } else { + // No luck, match part by part + array_shift($result); + $result = array_unique($result); + foreach ($result as $condition) { + if (strlen($condition) > 0) { + $pointer["condition"] .= " ".$conditions[strtolower($condition)]; } } - $pointer["condition"] = trim($pointer["condition"]); - break; - case "clouds": - if (!isset($pointer["clouds"])) { - $pointer["clouds"] = array(); - } + } + $pointer["condition"] = trim($pointer["condition"]); + break; + case "clouds": + if (!isset($pointer["clouds"])) { + $pointer["clouds"] = array(); + } - if (sizeof($result) == 5) { - // Only amount and height - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100)); - } - elseif (sizeof($result) == 6) { - // Amount, height and type - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100), "type" => $clouds[strtolower($result[5])]); - } - else { - // SKC or CLR or NSC - $cloud = array("amount" => $clouds[strtolower($result[0])]); - } - $pointer["clouds"][] = $cloud; - break; - case "temperature": - // normal temperature in first part - // negative value - if ($result[1] == "M") { - $result[2] *= -1; - } - $pointer["temperature"] = $this->convertTemperature($result[2], "c", "f"); - if (sizeof($result) > 4) { - // same for dewpoint - if ($result[4] == "M") { - $result[5] *= -1; - } - $pointer["dewPoint"] = $this->convertTemperature($result[5], "c", "f"); - $pointer["humidity"] = $this->calculateHumidity($result[2], $result[5]); - } - if (isset($pointer["wind"])) { - // Now calculate windchill from temperature and windspeed - $pointer["feltTemperature"] = $this->calculateWindChill($pointer["temperature"], $pointer["wind"]); - } - break; - case "pressure": - if ($result[1] == "A") { - // Pressure provided in inches - $pointer["pressure"] = $result[2] / 100; - } elseif ($result[3] == "Q") { - // ... in hectopascal - $pointer["pressure"] = $this->convertPressure($result[4], "hpa", "in"); - } - break; - case "trend": - // We may have a trend here... extract type and set pointer on - // created new array - if (!isset($weatherData["trend"])) { - $weatherData["trend"] = array(); - $weatherData["trend"][$trendCount] = array(); - } - $pointer =& $weatherData["trend"][$trendCount]; - $trendCount++; - $pointer["type"] = $result[0]; - while (isset($metar[$i + 1]) && preg_match("/^(FM|TL|AT)(\d{2})(\d{2})$/i", $metar[$i + 1], $lresult)) { - if ($lresult[1] == "FM") { - $pointer["from"] = $lresult[2].":".$lresult[3]; - } elseif ($lresult[1] == "TL") { - $pointer["to"] = $lresult[2].":".$lresult[3]; - } else { - $pointer["at"] = $lresult[2].":".$lresult[3]; - } - // As we have just extracted the time for this trend - // from our METAR, increase field-counter - $i++; + if (sizeof($result) == 5) { + // Only amount and height + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100)); + } + elseif (sizeof($result) == 6) { + // Amount, height and type + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4]*100), "type" => $clouds[strtolower($result[5])]); + } + else { + // SKC or CLR or NSC + $cloud = array("amount" => $clouds[strtolower($result[0])]); + } + $pointer["clouds"][] = $cloud; + break; + case "temperature": + // normal temperature in first part + // negative value + if ($result[1] == "M") { + $result[2] *= -1; + } + $pointer["temperature"] = $this->convertTemperature($result[2], "c", "f"); + if (sizeof($result) > 4) { + // same for dewpoint + if ($result[4] == "M") { + $result[5] *= -1; } - break; - case "remark": - // Remark part begins - $metarCode = $remarks; - $weatherData["remark"] = array(); - break; - case "autostation": - // Which autostation do we have here? - if ($result[1] == 0) { - $weatherData["remark"]["autostation"] = "Automatic weatherstation w/o precipitation discriminator"; + $pointer["dewPoint"] = $this->convertTemperature($result[5], "c", "f"); + $pointer["humidity"] = $this->calculateHumidity($result[2], $result[5]); + } + if (isset($pointer["wind"])) { + // Now calculate windchill from temperature and windspeed + $pointer["feltTemperature"] = $this->calculateWindChill($pointer["temperature"], $pointer["wind"]); + } + break; + case "pressure": + if ($result[1] == "A") { + // Pressure provided in inches + $pointer["pressure"] = $result[2] / 100; + } elseif ($result[3] == "Q") { + // ... in hectopascal + $pointer["pressure"] = $this->convertPressure($result[4], "hpa", "in"); + } + break; + case "trend": + // We may have a trend here... extract type and set pointer on + // created new array + if (!isset($weatherData["trend"])) { + $weatherData["trend"] = array(); + $weatherData["trend"][$trendCount] = array(); + } + $pointer =& $weatherData["trend"][$trendCount]; + $trendCount++; + $pointer["type"] = $result[0]; + while (isset($metar[$i + 1]) && preg_match("/^(FM|TL|AT)(\d{2})(\d{2})$/i", $metar[$i + 1], $lresult)) { + if ($lresult[1] == "FM") { + $pointer["from"] = $lresult[2].":".$lresult[3]; + } elseif ($lresult[1] == "TL") { + $pointer["to"] = $lresult[2].":".$lresult[3]; } else { - $weatherData["remark"]["autostation"] = "Automatic weatherstation w/ precipitation discriminator"; + $pointer["at"] = $lresult[2].":".$lresult[3]; } - unset($metarCode["autostation"]); - break; - case "presschg": - // Decoding for rapid pressure changes - if (strtolower($result[1]) == "r") { - $weatherData["remark"]["presschg"] = "Pressure rising rapidly"; + // As we have just extracted the time for this trend + // from our METAR, increase field-counter + $i++; + } + break; + case "remark": + // Remark part begins + $metarCode = $remarks; + $weatherData["remark"] = array(); + break; + case "autostation": + // Which autostation do we have here? + if ($result[1] == 0) { + $weatherData["remark"]["autostation"] = "Automatic weatherstation w/o precipitation discriminator"; + } else { + $weatherData["remark"]["autostation"] = "Automatic weatherstation w/ precipitation discriminator"; + } + unset($metarCode["autostation"]); + break; + case "presschg": + // Decoding for rapid pressure changes + if (strtolower($result[1]) == "r") { + $weatherData["remark"]["presschg"] = "Pressure rising rapidly"; + } else { + $weatherData["remark"]["presschg"] = "Pressure falling rapidly"; + } + unset($metarCode["presschg"]); + break; + case "seapressure": + // Pressure at sea level (delivered in hpa) + // Decoding is a bit obscure as 982 gets 998.2 + // whereas 113 becomes 1113 -> no real rule here + if (strtolower($result[1]) != "no") { + if ($result[1] > 500) { + $press = 900 + round($result[1] / 100, 1); } else { - $weatherData["remark"]["presschg"] = "Pressure falling rapidly"; - } - unset($metarCode["presschg"]); - break; - case "seapressure": - // Pressure at sea level (delivered in hpa) - // Decoding is a bit obscure as 982 gets 998.2 - // whereas 113 becomes 1113 -> no real rule here - if (strtolower($result[1]) != "no") { - if ($result[1] > 500) { - $press = 900 + round($result[1] / 100, 1); - } else { - $press = 1000 + $result[1]; - } - $weatherData["remark"]["seapressure"] = $this->convertPressure($press, "hpa", "in"); - } - unset($metarCode["seapressure"]); - break; - case "precip": - // Precipitation in inches - static $hours; - if (!isset($weatherData["precipitation"])) { - $weatherData["precipitation"] = array(); - $hours = array("P" => "1", "6" => "3/6", "7" => "24"); - } - if (!is_numeric($result[2])) { - $precip = "indeterminable"; - } elseif ($result[2] == "0000") { - $precip = "traceable"; - }else { - $precip = $result[2] / 100; - } - $weatherData["precipitation"][] = array( - "amount" => $precip, - "hours" => $hours[$result[1]] - ); - break; - case "snowdepth": - // Snow depth in inches - $weatherData["remark"]["snowdepth"] = $result[1]; - unset($metarCode["snowdepth"]); - break; - case "snowequiv": - // Same for equivalent in Water... (inches) - $weatherData["remark"]["snowequiv"] = $result[1] / 10; - unset($metarCode["snowequiv"]); - break; - case "cloudtypes": - // Cloud types, haven't found a way for decent decoding (yet) - unset($metarCode["cloudtypes"]); - break; - case "sunduration": - // Duration of sunshine (in minutes) - $weatherData["remark"]["sunduration"] = "Total minutes of sunshine: ".$result[1]; - unset($metarCode["sunduration"]); - break; - case "1htempdew": - // Temperatures in the last hour in C - if ($result[1] == "1") { - $result[2] *= -1; + $press = 1000 + $result[1]; } - $weatherData["remark"]["1htemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + $weatherData["remark"]["seapressure"] = $this->convertPressure($press, "hpa", "in"); + } + unset($metarCode["seapressure"]); + break; + case "precip": + // Precipitation in inches + static $hours; + if (!isset($weatherData["precipitation"])) { + $weatherData["precipitation"] = array(); + $hours = array("P" => "1", "6" => "3/6", "7" => "24"); + } + if (!is_numeric($result[2])) { + $precip = "indeterminable"; + } elseif ($result[2] == "0000") { + $precip = "traceable"; + }else { + $precip = $result[2] / 100; + } + $weatherData["precipitation"][] = array( + "amount" => $precip, + "hours" => $hours[$result[1]] + ); + break; + case "snowdepth": + // Snow depth in inches + $weatherData["remark"]["snowdepth"] = $result[1]; + unset($metarCode["snowdepth"]); + break; + case "snowequiv": + // Same for equivalent in Water... (inches) + $weatherData["remark"]["snowequiv"] = $result[1] / 10; + unset($metarCode["snowequiv"]); + break; + case "cloudtypes": + // Cloud types, haven't found a way for decent decoding (yet) + unset($metarCode["cloudtypes"]); + break; + case "sunduration": + // Duration of sunshine (in minutes) + $weatherData["remark"]["sunduration"] = "Total minutes of sunshine: ".$result[1]; + unset($metarCode["sunduration"]); + break; + case "1htempdew": + // Temperatures in the last hour in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["1htemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - if (sizeof($result) > 3) { - // same for dewpoint - if ($result[4] == "1") { - $result[5] *= -1; - } - $weatherData["remark"]["1hdew"] = $this->convertTemperature($result[5] / 10, "c", "f"); - } - unset($metarCode["1htempdew"]); - break; - case "6hmaxtemp": - // Max temperature in the last 6 hours in C - if ($result[1] == "1") { - $result[2] *= -1; + if (sizeof($result) > 3) { + // same for dewpoint + if ($result[4] == "1") { + $result[5] *= -1; } - $weatherData["remark"]["6hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - unset($metarCode["6hmaxtemp"]); - break; - case "6hmintemp": - // Min temperature in the last 6 hours in C - if ($result[1] == "1") { - $result[2] *= -1; - } - $weatherData["remark"]["6hmintemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - unset($metarCode["6hmintemp"]); - break; - case "24htemp": - // Max/Min temperatures in the last 24 hours in C - if ($result[1] == "1") { - $result[2] *= -1; - } - $weatherData["remark"]["24hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + $weatherData["remark"]["1hdew"] = $this->convertTemperature($result[5] / 10, "c", "f"); + } + unset($metarCode["1htempdew"]); + break; + case "6hmaxtemp": + // Max temperature in the last 6 hours in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["6hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + unset($metarCode["6hmaxtemp"]); + break; + case "6hmintemp": + // Min temperature in the last 6 hours in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["6hmintemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); + unset($metarCode["6hmintemp"]); + break; + case "24htemp": + // Max/Min temperatures in the last 24 hours in C + if ($result[1] == "1") { + $result[2] *= -1; + } + $weatherData["remark"]["24hmaxtemp"] = $this->convertTemperature($result[2] / 10, "c", "f"); - if ($result[3] == "1") { - $result[4] *= -1; - } - $weatherData["remark"]["24hmintemp"] = $this->convertTemperature($result[4] / 10, "c", "f"); - unset($metarCode["24htemp"]); - break; - case "3hpresstend": - // We don't save the pressure during the day, so no decoding - // possible, sorry - unset($metarCode["3hpresstend"]); - break; - case "nospeci": - // No change during the last hour - $weatherData["remark"]["nospeci"] = "No changes in weather conditions"; - unset($metarCode["nospeci"]); - break; - case "sensors": - // We may have multiple broken sensors, so do not unset - if (!isset($weatherData["remark"]["sensors"])) { - $weatherData["remark"]["sensors"] = array(); - } - $weatherData["remark"]["sensors"][strtolower($result[0])] = $sensors[strtolower($result[0])]; - break; - case "maintain": - $weatherData["remark"]["maintain"] = "Maintainance needed"; - unset($metarCode["maintain"]); - break; - default: - // Do nothing, just prevent further matching - unset($metarCode[$key]); - break; - } - if ($found && !SERVICES_WEATHER_DEBUG) { + if ($result[3] == "1") { + $result[4] *= -1; + } + $weatherData["remark"]["24hmintemp"] = $this->convertTemperature($result[4] / 10, "c", "f"); + unset($metarCode["24htemp"]); break; - } elseif ($found && SERVICES_WEATHER_DEBUG) { - echo $key."\n"; + case "3hpresstend": + // We don't save the pressure during the day, so no decoding + // possible, sorry + unset($metarCode["3hpresstend"]); + break; + case "nospeci": + // No change during the last hour + $weatherData["remark"]["nospeci"] = "No changes in weather conditions"; + unset($metarCode["nospeci"]); + break; + case "sensors": + // We may have multiple broken sensors, so do not unset + if (!isset($weatherData["remark"]["sensors"])) { + $weatherData["remark"]["sensors"] = array(); + } + $weatherData["remark"]["sensors"][strtolower($result[0])] = $sensors[strtolower($result[0])]; + break; + case "maintain": + $weatherData["remark"]["maintain"] = "Maintainance needed"; + unset($metarCode["maintain"]); + break; + default: + // Do nothing, just prevent further matching + unset($metarCode[$key]); break; - } - } - } - if (!$found) { - if (SERVICES_WEATHER_DEBUG) { - echo "n/a\n"; } - if (!isset($weatherData["noparse"])) { - $weatherData["noparse"] = array(); + if ($found && !SERVICES_WEATHER_DEBUG) { + break; + } elseif ($found && SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + break; } - $weatherData["noparse"][] = $metar[$i]; } } + if (!$found) { + if (SERVICES_WEATHER_DEBUG) { + echo "n/a\n"; + } + if (!isset($weatherData["noparse"])) { + $weatherData["noparse"] = array(); + } + $weatherData["noparse"][] = $metar[$i]; + } } + if (isset($weatherData["noparse"])) { $weatherData["noparse"] = implode(" ", $weatherData["noparse"]); } @@ -806,7 +889,7 @@ // {{{ _parseForecastData() /** - * Parses the data returned by the provided source and caches it + * Parses the data and caches it * * TAF KLGA 271734Z 271818 11007KT P6SM -RA SCT020 BKN200 * FM2300 14007KT P6SM SCT030 BKN150 @@ -815,13 +898,13 @@ * TEMPO 1215 5SM -RA BR SCT009 BKN015 * BECMG 1517 16007KT P6SM NSW SCT015 BKN070 * - * @param string $source + * @param array $data * @return PEAR_Error|array * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION * @access private */ - function _parseForecastData($source) + function _parseForecastData($data) { static $compass; static $clouds; @@ -894,315 +977,309 @@ "fmc" => "(PROB|BECMG|TEMPO)(\d{2})?" ); - $data = @file($source); + if (SERVICES_WEATHER_DEBUG) { + for ($i = 0; $i < sizeof($data); $i++) { + echo $data[$i]; + } + } + // Ok, we have correct data, start with parsing the first line for the last update + $forecastData = array(); + $forecastData["station"] = ""; + $forecastData["dataRaw"] = implode(" ", $data); + $forecastData["update"] = strtotime(trim($data[0])." GMT"); + $forecastData["updateRaw"] = trim($data[0]); + // and prepare the rest for stepping through + array_shift($data); + $taf = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); + + // Add a few local variables for data processing + $fromTime = ""; // The timeperiod the data gets added to + $fmcCount = 0; // If we have FMCs (Forecast Meteorological Conditions), we need this + $pointer =& $forecastData; // Pointer to the array we add the data to + for ($i = 0; $i < sizeof($taf); $i++) { + // Check for whitespace and step loop, if nothing's there + $taf[$i] = trim($taf[$i]); + if (!strlen($taf[$i])) { + continue; + } - // Check for correct data - if (!$data || !is_array($data) || sizeof($data) < 2) { - return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); - } else { if (SERVICES_WEATHER_DEBUG) { - for ($i = 0; $i < sizeof($data); $i++) { - echo $data[$i]; - } + $tab = str_repeat("\t", 2 - floor((strlen($taf[$i]) + 2) / 8)); + echo "\"".$taf[$i]."\"".$tab."-> "; } - // Ok, we have correct data, start with parsing the first line for the last update - $forecastData = array(); - $forecastData["station"] = ""; - $forecastData["dataRaw"] = implode(" ", $data); - $forecastData["update"] = strtotime(trim($data[0])." GMT"); - $forecastData["updateRaw"] = trim($data[0]); - // and prepare the rest for stepping through - array_shift($data); - $taf = explode(" ", preg_replace("/\s{2,}/", " ", implode(" ", $data))); - - // Add a few local variables for data processing - $fromTime = ""; // The timeperiod the data gets added to - $fmcCount = 0; // If we have FMCs (Forecast Meteorological Conditions), we need this - $pointer =& $forecastData; // Pointer to the array we add the data to - for ($i = 0; $i < sizeof($taf); $i++) { - // Check for whitespace and step loop, if nothing's there - $taf[$i] = trim($taf[$i]); - if (!strlen($taf[$i])) { - continue; - } - - if (SERVICES_WEATHER_DEBUG) { - $tab = str_repeat("\t", 2 - floor((strlen($taf[$i]) + 2) / 8)); - echo "\"".$taf[$i]."\"".$tab."-> "; - } - // Initialize some arrays - $result = array(); - $resultVF = array(); - $lresult = array(); - - $found = false; - foreach ($tafCode as $key => $regexp) { - // Check if current code matches current taf snippet - if (($found = preg_match("/^".$regexp."$/i", $taf[$i], $result)) == true) { - $insert = array(); - switch ($key) { - case "station": - $pointer["station"] = $result[0]; - unset($tafCode["station"]); - break; - case "valid": - $pointer["validRaw"] = $result[0]; - // Generates the timeperiod the report is valid for - list($year, $month, $day) = explode("-", date("Y-m-d", $forecastData["update"])); - // Date is in next month - if ($result[1] < $day) { - $month++; - } - $pointer["validFrom"] = gmmktime($result[2], 0, 0, $month, $result[1], $year); - // Valid time ends next day - if ($result[2] >= $result[3]) { - $result[1]++; - } - $pointer["validTo"] = gmmktime($result[3], 0, 0, $month, $result[1], $year); - unset($tafCode["valid"]); - // Now the groups will start, so initialize the time groups - $pointer["time"] = array(); - $fromTime = $result[2].":00"; - $pointer["time"][$fromTime] = array(); - // Set pointer to the first timeperiod - $pointer =& $pointer["time"][$fromTime]; + // Initialize some arrays + $result = array(); + $resultVF = array(); + $lresult = array(); + + $found = false; + foreach ($tafCode as $key => $regexp) { + // Check if current code matches current taf snippet + if (($found = preg_match("/^".$regexp."$/i", $taf[$i], $result)) == true) { + $insert = array(); + switch ($key) { + case "station": + $pointer["station"] = $result[0]; + unset($tafCode["station"]); + break; + case "valid": + $pointer["validRaw"] = $result[0]; + // Generates the timeperiod the report is valid for + list($year, $month, $day) = explode("-", date("Y-m-d", $forecastData["update"])); + // Date is in next month + if ($result[1] < $day) { + $month++; + } + $pointer["validFrom"] = gmmktime($result[2], 0, 0, $month, $result[1], $year); + // Valid time ends next day + if ($result[2] >= $result[3]) { + $result[1]++; + } + $pointer["validTo"] = gmmktime($result[3], 0, 0, $month, $result[1], $year); + unset($tafCode["valid"]); + // Now the groups will start, so initialize the time groups + $pointer["time"] = array(); + $fromTime = $result[2].":00"; + $pointer["time"][$fromTime] = array(); + // Set pointer to the first timeperiod + $pointer =& $pointer["time"][$fromTime]; + break; + case "wind": + // Parse wind data, first the speed, convert from kt to chosen unit + $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); + if ($result[1] == "VAR" || $result[1] == "VRB") { + // Variable winds + $pointer["windDegrees"] = "Variable"; + $pointer["windDirection"] = "Variable"; + } else { + // Save wind degree and calc direction + $pointer["windDegrees"] = $result[1]; + $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; + } + if (is_numeric($result[4])) { + // Wind with gusts... + $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); + } + if (isset($probability)) { + $pointer["windProb"] = $probability; + unset($probability); + } + break; + case "visFrac": + // Possible fractional visibility here. Check if it matches with the next TAF piece for visibility + if (!isset($taf[$i + 1]) || !preg_match("/^".$tafCode["visibility"]."$/i", $result[1]." ".$taf[$i + 1], $resultVF)) { + // No next TAF piece available or not matching. Match against next TAF code + $found = false; break; - case "wind": - // Parse wind data, first the speed, convert from kt to chosen unit - $pointer["wind"] = $this->convertSpeed($result[2], strtolower($result[5]), "mph"); - if ($result[1] == "VAR" || $result[1] == "VRB") { - // Variable winds - $pointer["windDegrees"] = "Variable"; - $pointer["windDirection"] = "Variable"; - } else { - // Save wind degree and calc direction - $pointer["windDegrees"] = $result[1]; - $pointer["windDirection"] = $compass[round($result[1] / 22.5) % 16]; - } - if (is_numeric($result[4])) { - // Wind with gusts... - $pointer["windGust"] = $this->convertSpeed($result[4], strtolower($result[5]), "mph"); - } - if (isset($probability)) { - $pointer["windProb"] = $probability; - unset($probability); + } else { + // Match. Hand over result and advance TAF + if (SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + echo "\"".$result[1]." ".$taf[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$taf[$i + 1]) + 2) / 8))."-> "; + } + $key = "visibility"; + $result = $resultVF; + $i++; + } + case "visibility": + $pointer["visQualifier"] = "AT"; + if (is_numeric($result[1]) && ($result[1] == 9999)) { + // Upper limit of visibility range + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["visQualifier"] = "BEYOND"; + } elseif (is_numeric($result[1])) { + // 4-digit visibility in m + $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); + } elseif (!isset($result[11]) || $result[11] != "CAVOK") { + if ($result[3] == "M") { + $pointer["visQualifier"] = "BELOW"; + } elseif ($result[3] == "P") { + $pointer["visQualifier"] = "BEYOND"; } - break; - case "visFrac": - // Possible fractional visibility here. Check if it matches with the next TAF piece for visibility - if (!isset($taf[$i + 1]) || !preg_match("/^".$tafCode["visibility"]."$/i", $result[1]." ".$taf[$i + 1], $resultVF)) { - // No next TAF piece available or not matching. Match against next TAF code - $found = false; - break; + if (is_numeric($result[5])) { + // visibility as one/two-digit number + $visibility = $this->convertDistance($result[5], $result[10], "sm"); } else { - // Match. Hand over result and advance TAF - if (SERVICES_WEATHER_DEBUG) { - echo $key."\n"; - echo "\"".$result[1]." ".$taf[$i + 1]."\"".str_repeat("\t", 2 - floor((strlen($result[1]." ".$taf[$i + 1]) + 2) / 8))."-> "; - } - $key = "visibility"; - $result = $resultVF; - $i++; - } - case "visibility": - $pointer["visQualifier"] = "AT"; - if (is_numeric($result[1]) && ($result[1] == 9999)) { - // Upper limit of visibility range - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["visQualifier"] = "BEYOND"; - } elseif (is_numeric($result[1])) { - // 4-digit visibility in m - $visibility = $this->convertDistance(($result[1]/1000), "km", "sm"); - } elseif (!isset($result[11]) || $result[11] != "CAVOK") { - if ($result[3] == "M") { - $pointer["visQualifier"] = "BELOW"; - } elseif ($result[3] == "P") { - $pointer["visQualifier"] = "BEYOND"; - } - if (is_numeric($result[5])) { - // visibility as one/two-digit number - $visibility = $this->convertDistance($result[5], $result[10], "sm"); + // the y/z part, add if we had a x part (see visibility1) + if (is_numeric($result[7])) { + $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); } else { - // the y/z part, add if we had a x part (see visibility1) - if (is_numeric($result[7])) { - $visibility = $this->convertDistance($result[7] + $result[8] / $result[9], $result[10], "sm"); - } else { - $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); - } + $visibility = $this->convertDistance($result[8] / $result[9], $result[10], "sm"); } - } else { - $pointer["visQualifier"] = "BEYOND"; - $visibility = $this->convertDistance(10, "km", "sm"); - $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); - $pointer["condition"] = "no significant weather"; - } - if (isset($probability)) { - $pointer["visProb"] = $probability; - unset($probability); - } - $pointer["visibility"] = $visibility; - break; - case "condition": - // First some basic setups - if (!isset($pointer["condition"])) { - $pointer["condition"] = ""; - } elseif (strlen($pointer["condition"]) > 0) { - $pointer["condition"] .= ","; } + } else { + $pointer["visQualifier"] = "BEYOND"; + $visibility = $this->convertDistance(10, "km", "sm"); + $pointer["clouds"] = array(array("amount" => "Clear below", "height" => 5000)); + $pointer["condition"] = "no significant weather"; + } + if (isset($probability)) { + $pointer["visProb"] = $probability; + unset($probability); + } + $pointer["visibility"] = $visibility; + break; + case "condition": + // First some basic setups + if (!isset($pointer["condition"])) { + $pointer["condition"] = ""; + } elseif (strlen($pointer["condition"]) > 0) { + $pointer["condition"] .= ","; + } - if (in_array(strtolower($result[0]), $conditions)) { - // First try matching the complete string - $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; - } else { - // No luck, match part by part - array_shift($result); - $result = array_unique($result); - foreach ($result as $condition) { - if (strlen($condition) > 0) { - $pointer["condition"] .= " ".$conditions[strtolower($condition)]; - } + if (in_array(strtolower($result[0]), $conditions)) { + // First try matching the complete string + $pointer["condition"] .= " ".$conditions[strtolower($result[0])]; + } else { + // No luck, match part by part + array_shift($result); + $result = array_unique($result); + foreach ($result as $condition) { + if (strlen($condition) > 0) { + $pointer["condition"] .= " ".$conditions[strtolower($condition)]; } } - $pointer["condition"] = trim($pointer["condition"]); - if (isset($probability)) { - $pointer["condition"] .= " (".$probability."% prob.)"; - unset($probability); - } - break; - case "clouds": - if (!isset($pointer["clouds"])) { - $pointer["clouds"] = array(); - } + } + $pointer["condition"] = trim($pointer["condition"]); + if (isset($probability)) { + $pointer["condition"] .= " (".$probability."% prob.)"; + unset($probability); + } + break; + case "clouds": + if (!isset($pointer["clouds"])) { + $pointer["clouds"] = array(); + } - if (sizeof($result) == 5) { - // Only amount and height - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100)); - } - elseif (sizeof($result) == 6) { - // Amount, height and type - $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100), "type" => $clouds[strtolower($result[5])]); - } - else { - // SKC or CLR or NSC - $cloud = array("amount" => $clouds[strtolower($result[0])]); - } - if(isset($probability)) { - $cloud["prob"] = $probability; - unset($probability); - } - $pointer["clouds"][] = $cloud; - break; - case "windshear": - // Parse windshear, if available - $pointer["windshear"] = $this->convertSpeed($result[3], strtolower($result[4]), "mph"); - $pointer["windshearHeight"] = $result[1] * 100; - $pointer["windshearDegrees"] = $result[2]; - $pointer["windshearDirection"] = $compass[round($result[2] / 22.5) % 16]; - break; - case "tempmax": - $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); - break; - case "tempmin": - // Parse max/min temperature - $forecastData["temperatureLow"] = $this->convertTemperature($result[1], "c", "f"); - break; - case "tempmaxmin": - $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); - $forecastData["temperatureLow"] = $this->convertTemperature($result[4], "c", "f"); - break; - case "from": - // Next timeperiod is coming up, prepare array and - // set pointer accordingly - if (sizeof($result) > 2) { - // The ICAO way - $fromTime = $result[1].":".$result[2]; - } else { - // The Australian way (Hey mates!) - $fromTime = $result[1].":00"; + if (sizeof($result) == 5) { + // Only amount and height + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100)); + } + elseif (sizeof($result) == 6) { + // Amount, height and type + $cloud = array("amount" => $clouds[strtolower($result[3])], "height" => ($result[4] * 100), "type" => $clouds[strtolower($result[5])]); + } + else { + // SKC or CLR or NSC + $cloud = array("amount" => $clouds[strtolower($result[0])]); + } + if(isset($probability)) { + $cloud["prob"] = $probability; + unset($probability); + } + $pointer["clouds"][] = $cloud; + break; + case "windshear": + // Parse windshear, if available + $pointer["windshear"] = $this->convertSpeed($result[3], strtolower($result[4]), "mph"); + $pointer["windshearHeight"] = $result[1] * 100; + $pointer["windshearDegrees"] = $result[2]; + $pointer["windshearDirection"] = $compass[round($result[2] / 22.5) % 16]; + break; + case "tempmax": + $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); + break; + case "tempmin": + // Parse max/min temperature + $forecastData["temperatureLow"] = $this->convertTemperature($result[1], "c", "f"); + break; + case "tempmaxmin": + $forecastData["temperatureHigh"] = $this->convertTemperature($result[1], "c", "f"); + $forecastData["temperatureLow"] = $this->convertTemperature($result[4], "c", "f"); + break; + case "from": + // Next timeperiod is coming up, prepare array and + // set pointer accordingly + if (sizeof($result) > 2) { + // The ICAO way + $fromTime = $result[1].":".$result[2]; + } else { + // The Australian way (Hey mates!) + $fromTime = $result[1].":00"; + } + $forecastData["time"][$fromTime] = array(); + $fmcCount = 0; + $pointer =& $forecastData["time"][$fromTime]; + break; + case "fmc"; + // Test, if this is a probability for the next FMC + if (preg_match("/^BECMG|TEMPO$/i", $taf[$i + 1], $lresult)) { + // Set type to BECMG or TEMPO + $type = $lresult[0]; + // Set probability + $probability = $result[2]; + // Now extract time for this group + preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 2], $lresult); + $from = $lresult[1].":00"; + $to = $lresult[2].":00"; + $to = ($to == "24:00") ? "00:00" : $to; + // As we now have type, probability and time for this FMC + // from our TAF, increase field-counter + $i += 2; + } elseif (preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 1], $lresult)) { + // Normal group, set type and use extracted time + $type = $result[1]; + // Check for PROBdd + if (isset($result[2])) { + $probability = $result[2]; } - $forecastData["time"][$fromTime] = array(); - $fmcCount = 0; - $pointer =& $forecastData["time"][$fromTime]; - break; - case "fmc"; - // Test, if this is a probability for the next FMC - if (preg_match("/^BECMG|TEMPO$/i", $taf[$i + 1], $lresult)) { - // Set type to BECMG or TEMPO - $type = $lresult[0]; - // Set probability + $from = $lresult[1].":00"; + $to = $lresult[2].":00"; + $to = ($to == "24:00") ? "00:00" : $to; + // Same as above, we have a time for this FMC from our TAF, + // increase field-counter + $i += 1; + } else { + // This is either a PROBdd or a malformed TAF + if (isset($result[2])) { $probability = $result[2]; - // Now extract time for this group - preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 2], $lresult); - $from = $lresult[1].":00"; - $to = $lresult[2].":00"; - $to = ($to == "24:00") ? "00:00" : $to; - // As we now have type, probability and time for this FMC - // from our TAF, increase field-counter - $i += 2; - } elseif (preg_match("/^(\d{2})(\d{2})$/i", $taf[$i + 1], $lresult)) { - // Normal group, set type and use extracted time - $type = $result[1]; - // Check for PROBdd - if (isset($result[2])) { - $probability = $result[2]; - } - $from = $lresult[1].":00"; - $to = $lresult[2].":00"; - $to = ($to == "24:00") ? "00:00" : $to; - // Same as above, we have a time for this FMC from our TAF, - // increase field-counter - $i += 1; - } else { - // This is either a PROBdd or a malformed TAF - if (isset($result[2])) { - $probability = $result[2]; - } } + } - // Handle the FMC, generate neccessary array if it's the first... - if (isset($type)) { - if (!isset($forecastData["time"][$fromTime]["fmc"])) { - $forecastData["time"][$fromTime]["fmc"] = array(); - } - $forecastData["time"][$fromTime]["fmc"][$fmcCount] = array(); - // ...and set pointer. - $pointer =& $forecastData["time"][$fromTime]["fmc"][$fmcCount]; - $fmcCount++; - // Insert data - $pointer["type"] = $type; - $pointer["from"] = $from; - $pointer["to"] = $to; - unset($type, $from, $to); - if (isset($probability)) { - $pointer["probability"] = $probability; - unset($probability); - } + // Handle the FMC, generate neccessary array if it's the first... + if (isset($type)) { + if (!isset($forecastData["time"][$fromTime]["fmc"])) { + $forecastData["time"][$fromTime]["fmc"] = array(); + } + $forecastData["time"][$fromTime]["fmc"][$fmcCount] = array(); + // ...and set pointer. + $pointer =& $forecastData["time"][$fromTime]["fmc"][$fmcCount]; + $fmcCount++; + // Insert data + $pointer["type"] = $type; + $pointer["from"] = $from; + $pointer["to"] = $to; + unset($type, $from, $to); + if (isset($probability)) { + $pointer["probability"] = $probability; + unset($probability); } - break; - default: - // Do nothing - break; - } - if ($found && !SERVICES_WEATHER_DEBUG) { + } break; - } elseif ($found && SERVICES_WEATHER_DEBUG) { - echo $key."\n"; + default: + // Do nothing break; - } - } - } - if (!$found) { - if (SERVICES_WEATHER_DEBUG) { - echo "n/a\n"; } - if (!isset($forecastData["noparse"])) { - $forecastData["noparse"] = array(); + if ($found && !SERVICES_WEATHER_DEBUG) { + break; + } elseif ($found && SERVICES_WEATHER_DEBUG) { + echo $key."\n"; + break; } - $forecastData["noparse"][] = $taf[$i]; } } + if (!$found) { + if (SERVICES_WEATHER_DEBUG) { + echo "n/a\n"; + } + if (!isset($forecastData["noparse"])) { + $forecastData["noparse"] = array(); + } + $forecastData["noparse"][] = $taf[$i]; + } } + if (isset($forecastData["noparse"])) { $forecastData["noparse"] = implode(" ", $forecastData["noparse"]); } @@ -1625,15 +1702,16 @@ $this->_weather = $weatherReturn; $weatherReturn["cache"] = "HIT"; } else { - // Set the source - if ($this->_sourceMetar == "file") { - $source = realpath($this->_sourcePathMetar."/".$id.".TXT"); - } else { - $source = $this->_sourcePathMetar."/".$id.".TXT"; - } - - // Download and parse weather - $weatherReturn = $this->_parseWeatherData($source); + // Download weather + $weatherData = $this->_retrieveServerData($id, "metar"); + if (Services_Weather::isError($weatherData)) { + return $weatherData; + } elseif (!is_array($weatherData) || sizeof($weatherData) < 2) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); + } + + // Parse weather + $weatherReturn = $this->_parseWeatherData($weatherData); if (Services_Weather::isError($weatherReturn)) { return $weatherReturn; @@ -1688,15 +1766,16 @@ $this->_forecast = $forecastReturn; $forecastReturn["cache"] = "HIT"; } else { - // Set the source - if ($this->_sourceTaf == "file") { - $source = realpath($this->_sourcePathTaf."/".$id.".TXT"); - } else { - $source = $this->_sourcePathTaf."/".$id.".TXT"; + // Download forecast + $forecastData = $this->_retrieveServerData($id, "taf"); + if (Services_Weather::isError($forecastData)) { + return $forecastData; + } elseif (!is_array($forecastData) || sizeof($forecastData) < 2) { + return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__); } - // Download and parse weather - $forecastReturn = $this->_parseForecastData($source); + // Parse forecast + $forecastReturn = $this->_parseForecastData($forecastData); if (Services_Weather::isError($forecastReturn)) { return $forecastReturn; http://cvs.php.net/diff.php/pear/Services_Weather/Weather/Common.php?r1=1.46&r2=1.47&ty=u Index: pear/Services_Weather/Weather/Common.php diff -u pear/Services_Weather/Weather/Common.php:1.46 pear/Services_Weather/Weather/Common.php:1.47 --- pear/Services_Weather/Weather/Common.php:1.46 Wed Nov 9 18:46:56 2005 +++ pear/Services_Weather/Weather/Common.php Fri Nov 11 09:33:14 2005 @@ -40,7 +40,7 @@ * @author Alexander Wirtz <alex@pc4p.net> * @copyright 2005 Alexander Wirtz * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: Common.php,v 1.46 2005/11/09 23:46:56 eru Exp $ + * @version CVS: $Id: Common.php,v 1.47 2005/11/11 14:33:14 eru Exp $ * @link http://pear.php.net/package/Services_Weather * @filesource */ @@ -327,20 +327,18 @@ */ function setHttpProxy($httpProxy) { - $proxy = array(); - - if (preg_match("#http://(?:([^:^@]+)?:?([^@]+)?@)?([^:]+)(?::(\d+))?#", $httpProxy, $proxy)) { - if (isset($proxy[1]) && $proxy[1] != "") { - $this->_httpOptions["proxy_user"] = $proxy[1]; + if (($proxy = parse_url($httpProxy)) !== false && $proxy["scheme"] == "http") { + if (isset($proxy["user"]) && $proxy["user"] != "") { + $this->_httpOptions["proxy_user"] = $proxy["user"]; } - if (isset($proxy[2]) && $proxy[2] != "") { - $this->_httpOptions["proxy_pass"] = $proxy[2]; + if (isset($proxy["pass"]) && $proxy["pass"] != "") { + $this->_httpOptions["proxy_pass"] = $proxy["pass"]; } - if (isset($proxy[3]) && $proxy[3] != "") { - $this->_httpOptions["proxy_host"] = $proxy[3]; + if (isset($proxy["host"]) && $proxy["host"] != "") { + $this->_httpOptions["proxy_host"] = $proxy["host"]; } - if (isset($proxy[4]) && $proxy[4] != "") { - $this->_httpOptions["proxy_port"] = $proxy[4]; + if (isset($proxy["port"]) && $proxy["port"] != "") { + $this->_httpOptions["proxy_port"] = $proxy["port"]; } return true; http://cvs.php.net/diff.php/pear/Services_Weather/Weather.php?r1=1.39&r2=1.40&ty=u Index: pear/Services_Weather/Weather.php diff -u pear/Services_Weather/Weather.php:1.39 pear/Services_Weather/Weather.php:1.40 --- pear/Services_Weather/Weather.php:1.39 Wed Nov 9 16:47:17 2005 +++ pear/Services_Weather/Weather.php Fri Nov 11 09:33:15 2005 @@ -46,7 +46,7 @@ * @author Alexander Wirtz <alex@pc4p.net> * @copyright 2005 Alexander Wirtz * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: Weather.php,v 1.39 2005/11/09 21:47:17 eru Exp $ + * @version CVS: $Id: Weather.php,v 1.40 2005/11/11 14:33:15 eru Exp $ * @link http://pear.php.net/package/Services_Weather * @filesource */ @@ -69,6 +69,7 @@ define("SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID", 15); define("SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID", 16); define("SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID", 17); +define("SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID", 18); // }}} // {{{ error codes defined by weather.com @@ -205,6 +206,7 @@ SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID => "The given proxy is not valid, please use the notation http://[user[:pass]@]host[:port].", SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID => "The date you've provided for calculation of sunrise/sunset is not a timestamp.", SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID => "The return format you've provided for calculation of sunrise/sunset is not valid.", + SERVICES_WEATHER_ERROR_METAR_SOURCE_INVALID => "The METAR/TAF source you've provided has an invalid type or path.", SERVICES_WEATHER_ERROR_UNKNOWN_ERROR => "An unknown error has occured.", SERVICES_WEATHER_ERROR_NO_LOCATION => "No location provided.", SERVICES_WEATHER_ERROR_INVALID_LOCATION => "Invalid location provided.",