// this script is free to download, modify, and use // requires php, curl, gd, allow_url_fopen // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // configuration // see http://w1.weather.gov/xml/current_obs/ // to find the URL for your local weather $xml_url = 'http://w1.weather.gov/xml/current_obs/KDEN.xml'; $location = 'Denver, CO'; $local_icons = ''; // get icons from www.weather.gov $temp_in = 'C'; // C or F $cache_image = '/tmp/weather.gif'; // cache image on server $cache_time = 900; // update every 15 minutes $background = '#000000'; $text_color = '#FFFFFF'; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // showtime header('Content-type: image/gif'); if ($cache_image) { if ($image = check_image($cache_image)) { readfile($image); } } else { rebuild_image(null); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // check cached image function check_image ($cache_image) { global $cache_time; $rebuild_image = false; if (is_file($cache_image)) { if ($_GET['rebuild']) { $rebuild_image = true; } else if ((time() - filemtime($cache_image)) > $cache_time) { $rebuild_image = true; } } else { $rebuild_image = true; } if ($rebuild_image) { return rebuild_image($cache_image); } else { return $cache_image; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // rebuild image function rebuild_image ($file) { global $xml_url, $location; global $background, $text_color; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // get data if ($data = get_xml_data($xml_url)) { $data = hack_data($data); } else { return false; } $n = count($data['keys']); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // image parameters $width = 200; $height = 100; // will be computed $loc_f = 4; $line_f = 2; $margin = 3; $loc_h = imagefontheight($loc_f) + $margin; $line_h = imagefontheight($line_f) + $margin; $block_h = $n * $line_h; if ($icon = get_icon($data)) { $icon_h = imagesy($icon) + $margin; if ($icon_h > $block_h) { $height = $margin + $loc_h + $icon_h + $line_h; } else { $height = $margin + $loc_h + $block_h + $line_h; } } else { $height = $margin + $loc_h + $block_h + $line_h; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // create image $image = imagecreatetruecolor($width,$height); $background = alloc_color($image,$background,255,255,255); imagefill($image,0,0,$background); $x = (2 * $margin); $y = $margin; $text_color = alloc_color($image,$text_color,0,0,0); if ($center_location) { $loc_w = strlen($location) * imagefontwidth($loc_f); $c = intval(($width - $loc_w) / 2); if ($c > $x) $x = $c; } imagestring($image,$loc_f,$x,$y,$location,$text_color); $x = (2 * $margin); $y += $loc_h; if ($icon) { imagecopy($image,$icon,$x,$y,0,0,imagesx($icon),imagesy($icon)); $x += imagesx($icon) + (2 * $margin); $clear_y = $y + $icon_h; } foreach ($data['keys'] as $key) { imagestring($image,$line_f,$x,$y,$data[$key],$text_color); $y += $line_h; } $x = (2 * $margin); if ($clear_y > $y) $y = $clear_y; imagestring($image,$line_f,$x,$y,$data['updated'],$text_color); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (imagegif($image,$file)) { return $file; } else { imagegif($image); return; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // get xml data function get_xml_data ($url) { $get = curl_init($url); curl_setopt($get,CURLOPT_USERAGENT,'Netscape/0.92b'); curl_setopt($get,CURLOPT_FAILONERROR,true); curl_setopt($get,CURLOPT_RETURNTRANSFER,true); $xml = curl_exec($get); $info = curl_getinfo($get); if (curl_errno($get) || ! $xml || $info['http_code'] != 200) { curl_close($get); return false; } else { curl_close($get); return parse_xml($xml); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // parse xml // an alarmingly simple parser function parse_xml (&$tokens,$parent = '') { if (! is_array($tokens)) { $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE; $tokens = preg_split('/(<[^>]+>)\s*/',$tokens,-1,$flags); } if ($parent) { $end_tag = sprintf('!/',$token)) { continue; } else if ($end_tag && preg_match($end_tag,$token)) { return $data; } else if (preg_match('/<(\w+)/',$token,$match)) { $data[$match[1]] = parse_xml($tokens,$match[1]); } else { $data = $token; } } return $data; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // hack data function hack_data ($data) { global $temp_in; $data = $data['current_observation']; if ($data['weather'] != 'NA') { $keys = array('weather'); } else { $data['none'] = 'No weather information'; $data['keys'] = array('none'); return $data; } if ($temp = hack_temp($data)) { $data['temp'] = $temp; $keys[] = 'temp'; } if (($pct = $data['relative_humidity']) != 'NA') { $data['humidity'] = sprintf('%d%% humidity',$pct); $keys[] = 'humidity'; } if ($wind = hack_wind($data)) { $data['wind'] = $wind; $keys[] = 'wind'; } if ($data['pressure_in'] != 'NA') { $u = ($temp_in == 'C') ? 'mb' : 'in'; $fmt = 'Barometer %s %s'; $data['barometer'] = sprintf($fmt,$data['pressure_'.$u],$u); $keys[] = 'barometer'; } $data['keys'] = $keys; if ($time = $data['observation_time']) { if (preg_match('/on (\w+ \d+, \d+:\d+ \w+)/',$time,$match)) { $data['updated'] = 'Updated: '.$match[1]; } } return $data; } function lc ($string) { return strtolower($string); } function uc ($string) { return strtoupper($string); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // hack temperature function hack_temp ($data) { global $temp_in; $temp_fmt = '%d'.$temp_in; $ext_fmt = "$temp_fmt ($temp_fmt %s)"; $t = lc($temp_in); if (($deg = $data['temp_'.$t]) != 'NA') { if (($ext = $data['heat_index_'.$t]) != 'NA') { $temp = sprintf($ext_fmt,$deg,$ext,'heat index'); } else if (($ext = $data['windchill_'.$t]) != 'NA') { $temp = sprintf($ext_fmt,$deg,$ext,'windchill'); } else { $temp = sprintf($temp_fmt,$deg); } } return $temp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // hack wind function hack_wind ($data) { global $temp_in; $speed_fmt = '%d %s'; $wind_fmt = 'Wind %s at %s'; if ($wind_str = $data['wind_string']) { if ($wind_str == 'Calm') { return 'Wind calm'; } } if ($wind_dir = $data['wind_dir']) { if ($wind_dir == 'None') { return 'No wind'; } else if ($wind_dir == 'Variable') { $wind_dir = 'Vary'; } else if (preg_match('/^([NS])\w+([ew])\w+/',$wind_dir,$match)) { $wind_dir = uc($match[1].$match[2]); } else if (preg_match('/^([NSEW])\w+/',$wind_dir,$match)) { $wind_dir = uc($match[1]); } } if (($speed = $data['wind_mph']) != 'NA') { if ($temp_in == 'C') { $speed = sprintf($speed_fmt,(($speed * 1.609) + 0.5),'kph'); } else { $speed = sprintf($speed_fmt,($speed + 0.5),'mph'); } } if ($wind_dir && $speed) { $wind = sprintf($wind_fmt,$wind_dir,$speed); } return $wind; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // get icon function get_icon ($data) { global $local_icons; if ($local_icons) { $icon_path = $local_icons.'/'.$data['icon_url_name']; } else { $icon_path = $data['icon_url_base'].$data['icon_url_name']; ini_set('user_agent','Netscape/0.92b'); } if (preg_match('/\.gif/',$data['icon_url_name'])) { $icon = imagecreatefromgif($icon_path); } else if (preg_match('/\.(jpg|jpeg)/',$data['icon_url_name'])) { $icon = imagecreatefromjpeg($icon_path); } else if (preg_match('/\.png/',$data['icon_url_name'])) { fclose(STDERR); // dump interlace error in libpng $icon = imagecreatefrompng($icon_path); } return $icon; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // allocate color function alloc_color ($image,$color,$r,$g,$b) { $dec_re = '/(\d+),\s*(\d+),\s*(\d+)/'; $hex_re = '/#([0-9a-z]{2})([0-9a-z]{2})([0-9a-z]{2})/i'; if (preg_match($dec_re,$color,$m)) { $r = $m[1]; $g = $m[2]; $b = $m[3]; } else if (preg_match($hex_re,$color,$m)) { $r = hexdec($m[1]); $g = hexdec($m[2]); $b = hexdec($m[3]); } return imagecolorallocate($image,$r,$g,$b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ?>