| |
CRH.noaa.gov redirects (no point forecasts)
// Version 2.02 - 02-Mar-2007 - added auto-failover to CRH and better include in page.
// Version 2.03 - 29-Apr-2007 - modified for /images/wtf -> /forecast/images change
// Version 2.04 - 05-Jun-2007 - improvement to auto-failover
// Version 2.05 - 29-Jun-2007 - additional check for alternative no-icon forecast, then failover.
// Version 2.06 - 24-Nov-2007 - rewrite for zone forecast, intrepret icons from text-only forecast
// Version 2.07 - 24-Nov-2007 - support new zone forecast with different temp formats
// Version 2.08 - 25-Nov-2007 - fix zone forecast icons, new temp formats supported
// Version 2.09 - 26-Nov-2007 - add support for new temperature phrases and below zero temps
// Version 2.10 - 17-Dec-2007 - added safety features from Mike Challis http://www.carmosaic.com/weather/
//
$Version = 'advforecast2.php - V2.10 - 17-Dec-2007';
//
//import NOAA Forecast info
//data ends up in four different arrays:
//$forecasticons[x] x = 0 thru 9 This is the icon and text around it
//$forecasttemp[x] x= 0 thru 9 This is forecast temperature with styling
//$forecasttitles[x] x = 0 thru 12 This is the title word for the text forecast time period
//$forecasttext[x] x = 0 thru 12 This is the detail text for the text forecast time period
//
//$forecastupdate This is the time of last update
//$forecastcity This is the city name for the forecast
//$forecastoffice This is the NWS Office providing the forecast
//
//Also, in order for this to work correctly, you need the NOAA icons (or make your own...
//there are over 200!). These need to be placed in the path where the original NOAA icons
//are located. In my case, they are at: \forecast\images\
//properly (so make a folder in your web HTML root called "forecast", then make a folder in it
//called "images", and place the icons in this folder)
//
//http://members.cox.net/carterlakeweather/forecasticons.zip (380K)
//
//URL below --MUST BE-- the Printable Point Forecast from the NOAA website
//
//Not every area of the US has a printable point forecast
//
//This script will ONLY WORK with a printable point forecast!
//
//To find yours in your area:
//
//Go to www.weather.gov
//Put your city, state in the search box and press Search
//Scroll down to the "Additional Forecasts & Info" on the page displayed
//Click on Printable Forecast
// copy the URL from your browser into the $fileName variable below.
// Also put your NOAA Warning Zone (like ssZnnn) in caps in the $NOAAZone variable below.
//
// also set your NOAA warning zone here to use for automatic backup in case
// the point printable forecast is not available.
//
// ----------------------SETTINGS---------------------------------------------
//
$NOAAZone = 'IAZ055'; // change this line to your NOAA warning zone.
// set $fileName to the URL for the point-printable forecast for your area
$fileName = "http://forecast.weather.gov/MapClick.php?CityName=Missouri+Valley&state=IA&site=OAX&textField1=41.5589&textField2=-95.8951&e=0&TextType=2";
//
// ----------------------END OF SETTINGS--------------------------------------
// Get the forecast.txt file or a new one from NOAA
// You have to have a forecast.txt in place for this script to work
// You can see ours at http://www.carterlake.org/forecast.txt
// This is version 1.2 with Ken's modifications from Saratoga Weather
// http://saratoga-weather.org/
// You can now force the cache to update by adding ?force=1 to the end of the URL
if ( empty($_REQUEST['force']) )
$_REQUEST['force']="0";
$Force = $_REQUEST['force'];
$forceBackup = false;
if ($Force > 1) {$forceBackup = true; }
$cacheName = "forecast.txt";
// dont change the next line....
$backupfileName = "http://forecast.weather.gov/MapClick.php?zoneid=$NOAAZone";
$Status = "\n\n\n";
if (isset($_REQUEST['sce']) && strtolower($_REQUEST['sce']) == 'view' ) {
//--self downloader --
$filenameReal = __FILE__;
$download_size = filesize($filenameReal);
header('Pragma: public');
header('Cache-Control: private');
header('Cache-Control: no-cache, must-revalidate');
header("Content-type: text/plain");
header("Accept-Ranges: bytes");
header("Content-Length: $download_size");
header('Connection: close');
readfile($filenameReal);
exit;
}
$fcstPeriods = array( // for filling in the ' Through ' zone forecasts.
'Monday','Monday Night',
'Tuesday','Tuesday Night',
'Wednesday','Wednesday Night',
'Thursday','Thursday Night',
'Friday','Friday Night',
'Saturday','Saturday Night',
'Sunday','Sunday Night',
'Monday','Monday Night',
'Tuesday','Tuesday Night',
'Wednesday','Wednesday Night',
'Thursday','Thursday Night',
'Friday','Friday Night',
'Saturday','Saturday Night',
'Sunday','Sunday Night'
);
$usingFile = "";
if ($Force==1) {
$html = fetchUrlWithoutHanging($fileName,$cacheName);
if (preg_match('/Temporary|Location:|defaulting to/Uis',$html)) {
$usingFile = "(Zone forecast)";
$html = fetchUrlWithoutHanging($backupfileName,$cacheName);
}
$fp = fopen($cacheName, "w");
if ($fp) {
$write = fputs($fp, $html);
fclose($fp);
} else {
$Status .= "\n";
}
}
if ($Force==2) {
$html = fetchUrlWithoutHanging($backupfileName,$cacheName);
$fp = fopen($cacheName, "w");
if ($fp) {
$write = fputs($fp, $html);
fclose($fp);
} else {
$Status .= "\n";
}
$usingFile = "(Zone forecast)";
}
// The number 1800 below is the number of seconds the cache will be used instead of pulling a new file
// 1800 = 60s x 30m so it retreives every 30 minutes.
if (filemtime($cacheName) + 1800 > time()) {
$Status .= "\n";
$html = implode('', file($cacheName));
if (preg_match('/Temporary|Location:|defaulting to/is',$html)) {
$usingFile = "(Zone forecast)";
$html = fetchUrlWithoutHanging($backupfileName,$cacheName);
}
} else {
$html = fetchUrlWithoutHanging($fileName,$cacheName);
if (preg_match('/Temporary|Location:|defaulting to/Uis',$html)) {
$usingFile = "(Zone forecast)";
$html = fetchUrlWithoutHanging($backupfileName,$cacheName);
}
$fp = fopen($cacheName, "w");
if ($fp) {
$write = fputs($fp, $html);
fclose($fp);
} else {
$Status .= "\n";
}
}
if (isset($_REQUEST['test'])) {
$tfile = "./forecast-" . trim($_REQUEST['test']) . '.txt';
if(file_exists($tfile)) {
$Status .= "\n";
$html = implode('',file($tfile));
} else {
$Status .= "\n";
}
}
$isZone = preg_match('|Zone Forecast: |i',$html); // here with Zone forecast sans icons
if ($isZone) { // using the zone forecast
$usingFile = "(Zone forecast)";
$Conditions = array(); // prepare for parsing the icon based on the text forecast
load_cond_data(); // initialize the conditions to look for
preg_match(
'|(.*)|Uis',
$html, $betweenspan);
// $Status .= "\n";
$forecastop = $betweenspan[1];
// slice off the text forecast from the Zone forecast
preg_match_all("|(.*)\.\.\.(.*)
|Uis", $forecastop, $headers);
$forecaststuff = $headers[1];
// $Status .= "\n";
// Breakup multi-day forecasts if needed
$i = 0;
foreach ($headers[1] as $j => $period) {
if (preg_match('/^(.*) (Through|And) (.*)/i',$period,$mtemp)) { // got period1 thru period2
list($fcstLow,$fcstHigh) = explode("\t",split_fcst($headers[2][$j]));
$startPeriod = $mtemp[1];
$periodType = $mtemp[2];
$endPeriod = $mtemp[3];
$startIndex = 0;
$endIndex = 0;
$Status .= "\n";
for ($k=0;$k\n";
$i++;
}
continue;
}
$forecasttitles[$i] = $period;
$forecasttext[$i] = $headers[2][$j];
$Status .= "\n";
$i++;
} // end of multi-day forecast split
for ($i=0;$i<=min(8,count($headers[1])-1);$i++) { // intrepet the text for icons, summary, temp, PoP
list($forecasticons[$i],$forecasttemp[$i],$forecastpop[$i]) =
explode("\t",make_icon($forecasttitles[$i],$forecasttext[$i]) );
}
} else { // original format point printable forecast
preg_match('|(.*)(.*)<\/td>/Uis", $forecastop, $headers);
$forecasticons = $headers[1];
}
// saratoga-weather.org mod: fix up html for XHTML 1.0-Strict
// $Status .= "\n";
for ($i=0;$i \s+$|is',
"",$forecasticons[$i]);
// $forecasticons[$i] = preg_replace('|temperatures|is','temps',$forecasticons[$i]);
// $forecasticons[$i] = preg_replace('|Falling|is',' Falling',$forecasticons[$i]);
$forecasticons[$i] = preg_replace('|\'|is','"',$forecasticons[$i]); // change all ' to "
$forecasticons[$i] = preg_replace('|\\\\" > |is','" /> ',$forecasticons[$i]);
$forecasticons[$i] = preg_replace('|(.*)|Uis',
"$2",$forecasticons[$i]);
preg_match_all('| ([^<]+)(.*)|is',$forecasticons[$i],$matches);
// $Status .= "\n";
if(isset($matches[2][0]) and preg_match('| |i',$matches[2][0])) {
$t = $matches[2][0];
$t = preg_replace('| |i',
" ",$t);
$matches[2][0] = $t;
}
if (! $isZone) {
$forecasttemp[$i] = $matches[1][0] . $matches[2][0]; // just the temp line
# mchallis added security feature
$forecasttemp[$i] = strip_tags($forecasttemp[$i], '
');
}
// remove the temp from the forecasticons
if(isset($matches[0][0])) {
$forecasticons[$i] = preg_replace('|'.$matches[0][0].'|is','',$forecasticons[$i]);
}
// fix up the to be for XHTML compatibility
$forecasticons[$i] = preg_replace('| |Uis',' ',$forecasticons[$i]);
# mchallis added security feature
$forecasticons[$i] = strip_tags($forecasticons[$i], '
');
// $forecasttemp[$i] = preg_replace('| |Uis',' ',$forecasttemp[$i]);
// $forecasttemp[$i] = trim($forecasttemp[$i]);
}
// $Status .= "\n";
// end saratoga-weather.org XHTML 1.0-Strict mod
if ($isZone) { // special handling for ERH->CRH redirection
// Grab the Last Update date and time.
preg_match('|Last Update:(.*) |', $html, $betweenspan);
$forecastupdated = $betweenspan[1];
# mchallis added security feature
$forecastupdated = strip_tags($forecastupdated, '
');
// saratoga-weather.org mod:
// Grab the NWS Forecast for (city name)
preg_match('|class="white1">\s*(.*)
');
// Grab the Issued by office
preg_match('|]+>(.*) Zone Forecast:|is',$html,$betweenspan);
$forecastoffice = trim($betweenspan[1]);
$forecastoffice = preg_replace('| |s','',$forecastoffice);
} else { // begin regular handling
// Now get just the bottom of the NWS page for editing
preg_match('| (.*) |s', $html, $betweenspan);
$forecast = $betweenspan[1];
# mchallis added security feature
$forecast = strip_tags($forecast, '
');
// Chop up each title text and place in array
preg_match_all('|(.*): |Ui', $forecast, $headers);
$forecasttitles = $headers[1];
// Chop up each forecast text and place in array
preg_match_all('|(.*) |Ui', $forecast, $headers);
$forecasttext = $headers[1];
# BOF mchallis added security feature
for ($i=0;$i
');
$forecasttext[$i] = strip_tags($forecasttext[$i], '
');
}
# EOF mchallis added security feature
// Grab the Last Update date and time.
preg_match('|Last Update: (.*)|', $html, $betweenspan);
$forecastupdated = $betweenspan[1];
$forecastupdated = preg_replace('|<[^>]+>|Uis','',$forecastupdated); // remove html markup
// saratoga-weather.org mod:
// Grab the NWS Forecast for (city name)
preg_match('|NWS Forecast for: (.*)|',$html,$betweenspan);
$forecastcity = $betweenspan[1];
# mchallis added security feature
$forecastcity = strip_tags($forecastcity, '
');
// Grab the Issued by office
preg_match('|Issued by: (.*) |',$html,$betweenspan);
$forecastoffice = $betweenspan[1];
# mchallis added security feature
$forecastoffice = strip_tags($forecastoffice, '
');
} // end regular handling
$IncludeMode = false;
$PrintMode = true;
if (isset($doPrintNWS) && ! $doPrintNWS ) {
return;
}
if (isset($_REQUEST['inc']) &&
strtolower($_REQUEST['inc']) == 'noprint' ) {
return;
}
if (isset($_REQUEST['inc']) && strtolower($_REQUEST['inc']) == 'y') {
$IncludeMode = true;
}
if (isset($doIncludeNWS)) {
$IncludeMode = $doIncludeNWS;
}
// end saratoga-weather.org mod
//------------------------------------------------------------------------------------------
function fetchUrlWithoutHanging($url,$cacheurl)
{
global $Status;
// Set maximum number of seconds (can have floating-point) to wait for feed before displaying page without feed
$numberOfSeconds=4;
// Suppress error reporting so Web site visitors are unaware if the feed fails
error_reporting(0);
// Extract resource path and domain from URL ready for fsockopen
$url = str_replace("http://","",$url);
$urlComponents = explode("/",$url);
$domain = $urlComponents[0];
$resourcePath = str_replace($domain,"",$url);
// Establish a connection
$socketConnection = fsockopen($domain, 80, $errno, $errstr, $numberOfSeconds);
if (!$socketConnection)
{
$Status .= "";
$html = implode('', file($cacheurl));
return($html);
// You may wish to remove the following debugging line on a live Web site
} // end if
else {
$xml = '';
fputs($socketConnection, "GET $resourcePath HTTP/1.0\r\nHost: $domain\r\n\r\n");
// Loop until end of file
while (!feof($socketConnection))
{
$xml .= fgets($socketConnection, 4096);
} // end while
fclose ($socketConnection);
} // end else
return($xml);
} // end fetchUrlWithoutHanging function
//------------------------------------------------------------------------------------------
// split off Low and High from multiday forecast
function split_fcst($fcst) {
global $Status;
$f = explode(". ",$fcst . ' ');
$lowpart = 0;
$highpart = 0;
foreach ($f as $n => $part) { // find the Low and High sentences
if(preg_match('/Low/i',$part)) { $lowpart = $n; }
if(preg_match('/High/i',$part)) { $highpart = $n; }
}
$f[$lowpart] = preg_replace('|(\d+) below|s',"-$1",$f[$lowpart]);
$f[$lowpart] = preg_replace('/( above| below| zero)/s','',$f[$lowpart]);
$f[$lowpart] .= '.';
$f[$highpart] = preg_replace('|(\d+) below|s',"-$1",$f[$highpart]);
$f[$highpart] = preg_replace('/( above| below| zero)/s','',$f[$highpart]);
$f[$highpart] .= '.';
$replpart = min($lowpart,$highpart)-1;
$fcststr = '';
for ($i=0;$i<=$replpart;$i++) {$fcststr .= $f[$i] . '. '; } // generate static fcst text
$fcstLow = $fcststr . ' ' . $f[$lowpart];
$fcstHigh = $fcststr . ' ' . $f[$highpart];
return("$fcstLow\t$fcstHigh");
}
//------------------------------------------------------------------------------------------
// function make_icon: parse text and find suitable icon from zone forecast text for period
function make_icon($day,$textforecast) {
global $Conditions,$Status;
if (preg_match('| |i',$day) ) {
$icon = "" . preg_replace('| |',' ',$day,1) . ' ';
} else {
$icon = "" . $day . '
';
}
$temperature = 'n/a';
$pop = '';
$iconimage = 'na.jpg';
$condition = 'N/A';
if (preg_match('|(\S+) (\d+) percent|',$textforecast,$mtemp)) { // found a PoP
// $Status .= "\n";
$pop = $mtemp[2];
}
if (preg_match('/(Highs|Lows|Temperatures nearly steady|Temperatures falling to|Temperatures rising to|Near steady temperature) (in the upper|in the lower|in the mid|in the low to mid|in the mid to upper|in the|around|near|nearly|above|below|from) ([\d|-]+)/i',$textforecast,$mtemp)) { // found temp
// $Status .= "\n";
if (substr($mtemp[1],0,1) == 'T' or substr($mtemp[1],0,1) == 'N') { // use day for highs/night for lows if 'Temperatures nearly steady'
$mtemp[1] = 'Highs';
if (preg_match('|night|i',$day)) {
$mtemp[1] = 'Lows';
}
}
$tcolor = '#FF0000';
if (strtoupper(substr($mtemp[1],0,1)) == 'L') {
$tcolor = '#0000FF';
}
$temperature = ucfirst(substr($mtemp[1],0,2) . ' ');
$t = $mtemp[3]; // the raw temp
if (preg_match('/(low to mid|mid to upper|upper|lower|mid|in the)/',$mtemp[2],$ttemp) ) {
$t = $t + 5;
if ($ttemp[1] == 'upper') {
$temperature .= '>' . $t;
}
if ($ttemp[1] == 'lower') {
$temperature .= '<' . $t ;
}
if ($ttemp[1] == 'mid') {
$temperature .= '≈' . $t;
}
if ($ttemp[1] == 'in the') {
$temperature .= '≈' . $t;
}
if ($ttemp[1] == 'low to mid') {
$t = $t -2;
$temperature .= '≈' . $t;
}
if ($ttemp[1] == 'mid to upper') {
$t = $t + 2;
$temperature .= '≈' . $t;
}
}
if (preg_match('/(near|around)/',$mtemp[2],$ttemp) ) {
$temperature .= '≈' . $mtemp[3];
}
$temperature .= '°F';
}
if (preg_match('/(Highs|Lows) ([\d|-]+) to ([\d|-]+)/i',$textforecast,$mtemp) ) { // temp range forecast
$tcolor = '#FF0000';
if (strtoupper(substr($mtemp[1],0,1)) == 'L') {
$tcolor = '#0000FF';
}
$temperature = ucfirst(substr($mtemp[1],0,2) . ' ');
$tavg = sprintf("%0d",round(($mtemp[3] + $mtemp[2]) / 2,0));
$temperature .= '≈' . $tavg . '°F';
}
// $Status .= "\n";
// now look for harshest conditions first.. (in order in -data file
reset($Conditions); // Do search in load order
foreach ($Conditions as $cond => $condrec) { // look for matching condition
if(preg_match("!$cond!i",$textforecast,$mtemp)) {
list($dayicon,$nighticon,$condition) = explode("\t",$condrec);
if (preg_match('|night|i',$day)) {
$iconimage = $nighticon . $pop . '.jpg';
} else {
$iconimage = $dayicon . $pop . '.jpg';
}
break;
}
} // end of conditions search
$icon .= ' ' . $condition;
return("$icon\t$temperature\t$pop");
} // end make_icons function
//------------------------------------------------------------------------------------------
// load the $Conditions array for icon selection based on key phrases
function load_cond_data () {
global $Conditions, $Status;
$Condstring = '
#
cond|tornado|nsvrtsra|nsvrtsra|Severe storm|
cond|showery or intermittent. Some thunder|scttsra|nscttsra|Showers storms|
cond|thunder possible|scttsra|nscttsra|Showers storms|
cond|thunder|tsra|ntsra|Thunder storm|
cond|rain and sleet|raip|nraip|Rain Sleet|
cond|freezing rain and snow|raip|nraip|FrzgRn Snow|
cond|rain and snow|rasn|nrasn|Rain and Snow|
cond|rain or snow|rasn|nrasn|Rain or Snow|
cond|freezing rain|fzra|fzra|Freezing Rain|
cond|rain likely|ra|nra|Rain likely|
cond|chance of rain|ra|nra|Chance rain|
cond|mix|rasn|rasn|Mix|
cond|sleet|ip|ip|Sleet|
cond|snow|sn|nsn|Snow
cond|fog in the morning|sctfg|nbknfg|Fog a.m.|
cond|fog after midnight|sctfg|nbknfg|Fog late|
cond|fog|fg|nfg|Fog|
cond|wind chill down to -|cold|cold|Very Cold|
cond|heat index up to 1|hot|hot|Very Hot|
cond|overcast|ovc|novc|Overcast|
cond|mostly cloudy|bkn|nbkn|Mostly Cloudy|
cond|partly cloudy|sct|nsct|Partly Cloudy|
cond|cloudy|cloudy|ncloudy|Cloudy|
cond|partly sunny|sct|nsct|Partly Sunny|
cond|mostly sunny|few|nfew|Mostly Sunny|
cond|mostly clear|few|nfew|Mostly Clear|
cond|sunny|skc|nskc|Sunny|
cond|clear|skc|nskc|Clear|
cond|fair|few|nfew|Fair|
cond|cloud|bkn|nbkn|Variable Clouds|
#
';
$config = explode("\n",$Condstring);
foreach ($config as $key => $rec) { // load the parser condition strings
$recin = trim($rec);
if ($recin and substr($recin,0,1) <> '#') { // got a non comment record
list($type,$keyword,$dayicon,$nighticon,$condition) = explode('|',$recin . '|||||');
if (isset($type) and strtolower($type) == 'cond' and isset($condition)) {
$Conditions["$keyword"] = "$dayicon\t$nighticon\t$condition";
// $Status .= "\n";
}
} // end if not comment or blank
} // end loading of loop over config recs
} // end of load_cond_data function
//------------------------------------------------------------------------------------------
if (! $IncludeMode and $PrintMode) { ?>
NWS Forecast for
Forecast blank? Force Update
';
}
if ($PrintMode) {?>
National Weather Service Forecast for:
Issued by:
|
| Updated:
|
$forecasticons[$i]\n";
}
?>
$forecasttemp[$i]\n";
}
?>
|
\n";
print "$forecasttitles[$i]
| \n";
print "$forecasttext[$i] | \n";
print "\n";
}
?>
Forecast from NOAA-NWS
for .
| |