A Slightly More Robust WeatherBox

Snow days lead inevitably to template hacking. :) Over the last couple of weeks, I’ve noticed that my “weatherbox” has started to show a broken image under certain conditions. I discovered that my XML stream is sending me an empty tag where it should be sending me the name of a graphic.

Under these brilliant conditions, my PHP was set to display “nothing.gif”, which, of course, led to the decidedly-unprofessional looking red X in place of the graphic. Today I made the PHP code just a tiny bit more robust by bracketing the <img> tag with an if condition. Read on to see the resulting code.

“I’m all about open source.”

Below is the code for the WeatherBox. The only parts I really contributed to it are the <? php ?> tags in the markup below. The code towards the top is the work of Michael Reilly (thanks again, Mike), which I found on php.net. The new if tags are boldfaced.

<?php
   // Array to store current xml path
   $ary_path = array();
   // Array to store parsed data
   $ary_parsed_file = array();
   // Starting level – Set to 0 to display all levels. Set to 1 or higher
   // to skip a level that is common to all the fields.
   $int_starting_level = 1;
   // what are we parsing?
   $xml_file = ‘http://weather.interceptvector.com/weather.xml?&state=NJ&city=Wharton’;
   // declare the character set – UTF-8 is the default
   $type = ‘UTF-8′;
   // create our parser
   $xml_parser = xml_parser_create($type);
   // set some parser options
   xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false);
   xml_parser_set_option($xml_parser, XML_OPTION_TARGET_ENCODING, ‘UTF-8′);

   // this tells PHP what functions to call when it finds an element
   // these funcitons also handle the element’s attributes
   xml_set_element_handler($xml_parser, ‘startElement’,'endElement’);

   // this tells PHP what function to use on the character data
   xml_set_character_data_handler($xml_parser, ‘characterData’);

   if (!($fp = fopen($xml_file, ‘r’))) {
      die(“Could not open $xml_file for parsing!”);
   }
   // loop through the file and parse baby!
   while ($data = fread($fp, 4096)) {
      if (!($data = utf8_encode($data))) {
         echo ‘ERROR’;
      }
      if (!xml_parse($xml_parser, $data, feof($fp))) {
         die(sprintf( “XML error: %s at line %d”,
         xml_error_string(xml_get_error_code($xml_parser)),
         xml_get_current_line_number($xml_parser)));
      }
   }
   xml_parser_free($xml_parser);
   // Display the array
   // print_r($ary_parsed_file);
   // This function is called for every opening XML tag. We
   // need to keep track of our path in the XML file, so we
   // will use this function to add the tag name to an array
   function startElement($parser, $name, $attrs=”){
      // Make sure we can access the path array
      global $ary_path;
      // Push the tag into the array
      array_push($ary_path, $name);
   }
   // This function is called for every closing XML tag. We
   // need to keep track of our path in the XML file, so we
   // will use this function to remove the last item of the array.
   function endElement($parser, $name, $attrs=”){
      // Make sure we can access the path array
      global $ary_path;
      // Push the tag into the array
      array_pop($ary_path);
   }
   // This function is called for every data portion found between
   // opening and closing tags. We will use it to insert values
   // into the array.
   function characterData($parser, $data){
      // Make sure we can access the path and parsed file arrays
      // and the starting level value
      global $ary_parsed_file, $ary_path, $int_starting_level;
      // Remove extra white space from the data (so we can tell if it’s empty)
      $str_trimmed_data = trim($data);
      // Since this function gets called whether there is text data or not,
      // we need to prevent it from being called when there is no text data
      // or it overwrites previous legitimate data.
      if (!empty($str_trimmed_data)) {
         // Build the array definition string
         $str_array_define = ‘$ary_parsed_file’;
         // Add a [''] and data for each level. (Starting level can be defined.)
         for ($i = $int_starting_level; $i < count($ary_path); $i++) {
            $str_array_define .= ‘['' . $ary_path[$i] . ”]’;
   
         }
         // Add the value portion of the statement
         $str_array_define .= ” = ‘” . $str_trimmed_data . “‘;”;
         // Evaluate the statement we just created
         eval($str_array_define);
      } // if
   }
?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
   <meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″ />
   <link rel=”stylesheet” href=”<$MTBlogURL$>styles-site.css” type=”text/css” />
   <link rel=”alternate” type=”application/rss+xml” title=”RSS” href=”<$MTBlogURL$>index.rdf” />
   <title>Ken & Sarah Walker | WeatherBox </title>
   <script language=”javascript” type=”text/javascript” src=”<$MTBlogURL$>global.js”></script>
</head>
<body>
   <? if ($ary_parsed_file['wid'] <> “”) { ?>
      <img src=”http://weather.interceptvector.com/common/weather/icons/<?php echo $ary_parsed_file['wid']; ?>.gif” title=”<?php echo $ary_parsed_file['sky']; ?>” alt=”Weather Graphic” style=”float: right; margin: 20px;” />
   <? } ?>
   <div class=”sidetitle”>Weather</div>
   <div class=”side-content”>
      <br />
      <?php echo $ary_parsed_file['city']; ?>, <?php echo $ary_parsed_file['state']; ?><br />
      <?php echo $ary_parsed_file['sky']; ?><br />
      <br />
      Temp: <?php echo $ary_parsed_file['realtemp']; ?>°<?php echo substr($ary_parsed_file['tempScale'],0,1); ?><br />
      Humidity: <?php echo $ary_parsed_file['humidity']; ?>%<br />
      Barometer: <?php echo $ary_parsed_file['barometer']; ?>in<br />
      Wind: <?php echo $ary_parsed_file['wind']['direction']; ?> at <?php echo $ary_parsed_file['wind']['strength']; ?>mph<br />
      <?php echo $ary_parsed_file['date']; ?>
   </div>
</body>
</html>

7 thoughts on “A Slightly More Robust WeatherBox

  1. Hmm. Why not use the MT Plugin for weather, and the perl script from the MT-RSS plugin to cron a regular rebuild of the index pages? That way you don’t need to run realtime fetching/php, reduce your bandwidth needs, speed up page loads, and don’t get red x’s. ;)

  2. Well, I kind of like the whole real-time weather aspect of the PHP. Though, the stream is only refreshed every hour or so. Do you think it’s worth having a plugin rebuild the index page every hour? Aside from that, having a plugin rebuild the page at least everyday would be nice–then my calendar would be accurate! ;-)

  3. If your stream only refreshes hourly, it’s definately worth the plugin rebuild. Just running the PHP takes server load, and can slow down your page. Dumping raw html is /much/ /much/ faster. In fact, another idea would be to replace the php for the rotating image with an img tag, where the src points at a php script. Then your index would load even faster, and the php src script could return a random image and its mime type, etc.

    Lots of fun stuff.

  4. ok.

    http://mt-plugins.org/archives/entry/mtrss_feed.php

    should start you on the right path. That is for parsing RSS feeds. It is compatible with MT-List if you want to parse lots of RSS feeds, otherwise it only uses one per tagset. Oh, and I believe that includes the perl script.

    Now to get the weather plugin, go to http://mt-plugins.org/archives/entry/weather.php

    You can then use the perl from MT-RSS_Feed to rebuild your indexes via cron, and the MT-Weather plugin will update your weather box in the process.

    I don’t do the weather, but I use the RSS update on begroovy, when my server isn’t busy crashing.

  5. Ryan, you rock. Thanks. I’ll have to spend another snow day working on this. :) BTW, what did happen to the RyanAbramsWeb yesterday? I noticed the sites (begroovy, dcindustrial, etc.) were having some issues?

  6. Well, the dedicated box seems to have a minor case of the hiccups. Hopefully they will stabilize, but I am thinking about cronning a regularly scheduled backup of the db’s… “just in case”