Current Weather Conditions
2008-10-19 15:27:41
Category: php:xml
Description: PHP Class to retrieve local XML weather conditions from weather.gov. Can be used to display local weather on your website.
Author: detour
Viewed: 1940
Rating: (6 votes)


<?php
/* noaa-weather.php by detour@metalshell.com
 *
 * Simple PHP5 class to retrieve a list of weather stations for a state, and
 * specific data for a selected station.  Only supports US weather.
 *
 * http://www.metalshell.com/
 *
 */
 
// Change to get a list of stations in your state
define('STATION_LIST_STATE', 'FL');
// Copy and paste station XML URL for your closest location
define('WEATHER_STATION', 'http://weather.gov/xml/current_obs/KRSW.xml');
 
try {
  $weather = new weather();
 
  echo "Getting weather stations for " . STATION_LIST_STATE . "\n---------------------\n";
  $weather->show_weather_stations(STATION_LIST_STATE);
 
  $station_obs = $weather->get_weather_data(WEATHER_STATION);
  echo "\n\nGetting current weather observations\n---------------------\n";
 
  foreach($station_obs as $k=>$v) {
    echo "$k = $v\n";
  }
} catch (Exception $e) {
 
  echo "Error thrown: " . $e->getMessage();
 
}
 
class weather {
  private $xml_parser, $state, $current_element, $element_depth = 0;
  private $matched_stations = array(), $station_details = array();
  private $station_obs = array(), $parent_elements = array();
 
  // Store some information so we know the current element, and depth.
  private function start_element($parser, $name, $attribs) {
    $this->current_element = $name;
    $this->element_depth++;
    $this->parent_elements[$this->element_depth] = $name;
  }
 
  private function end_element($parser, $name) {
    $this->current_element = '';
    $this->element_depth--;
  }
 
  // If parent xml element is STATION, store the data
  private function station_parse($parser, $data) {
    if($this->current_element) {
      $parent_el = strtolower($this->parent_elements[$this->element_depth-1]);
      if($parent_el == 'station') {
        $this->station_details[$this->current_element] = $data;
      } else if($parent_el == 'wx_station_index' && count($this->station_details)) {
        $this->matched_stations[] = $this->station_details;
      }
    }
  }
 
  function __construct() {
  }
 
  function __destruct() {
    if(is_resource($this->xml_parser)) xml_parser_free($this->xml_parser);
  }
 
  // Parser must be cleared and recreated
  private function create_parser() {
    if(is_resource($this->xml_parser)) xml_parser_free($this->xml_parser);
 
    $this->xml_parser = xml_parser_create();
    xml_set_object($this->xml_parser, $this);
  }
 
  // Get current local conditions.
  public function get_weather_data($station_url) {
    $this->create_parser();
 
    xml_set_element_handler($this->xml_parser, "start_element", "end_element");
    xml_set_character_data_handler($this->xml_parser, "current_obs_data");
    $this->start_xml_parse($this->dl_xml($station_url));
 
    return $this->station_obs;
  }
 
  private function current_obs_data($parser, $data) {
    if($this->current_element) {
      $parent_el = strtolower($this->parent_elements[$this->element_depth-1]);
      if($parent_el == 'current_observation' && $this->current_element != 'IMAGE') {
        $this->station_obs[$this->current_element] = $data;
      }
    }
  }
 
  // Accepts 2 letter state, then echo's all stations in that state
  public function show_weather_stations($state) {
    if(strlen($state) != 2) throw new Exception("State should be 2 letter abbreviation.  i.e. FL, CA");
 
    $this->state = $state;
 
    $this->create_parser();
    xml_set_element_handler($this->xml_parser, "start_element", "end_element");
    xml_set_character_data_handler($this->xml_parser, "station_parse");
    $this->start_xml_parse($this->dl_xml('http://www.weather.gov/xml/current_obs/index.xml'));
 
    if(count($this->matched_stations)) {
      foreach($this->matched_stations as $k=>$detail) {
        if(strtolower($detail["STATE"]) == strtolower($this->state)) {
          echo "{$this->state} Station: {$detail["STATION_ID"]} ({$detail["STATION_NAME"]}) {$detail["XML_URL"]}\n";
        }
      }
    } else {
      throw new Exception("Unable to retrieve station list.");
    }
  }
 
  private function start_xml_parse($data) {
    if(!xml_parse($this->xml_parser, $data, true))
      throw new Exception(sprintf("XML error: %s at line %d",
        xml_error_string(xml_get_error_code($this->xml_parser)),
        xml_get_current_line_number($this->xml_parser)));
  }
 
  // D/L and return xml data.
  public function dl_xml($url) {
    $buf = '';
 
    $fd = fopen($url, "r");
    if(!$fd) throw new Exception("Unable to open '$url'");
 
    while(!feof($fd)) {
      $buf .= fgets($fd, 4096);
    }
 
    fclose($fd);
 
    return $buf;
  }
}