and from output // heading=n - (default)='y' suppress printing of heading (forecast city/by/date) // icons=n - (default)='y' suppress printing of the icons+conditions+temp+wind+UV // text=n - (default)='y' suppress printing of the periods/forecast text // // // You can also invoke these options directly in the PHP like this // // $doIncludeVC = true; // include("VC-forecast.php"); for just the text // or ------------ // $doPrintVC = false; // include("VC-forecast.php"); for setting up the $VCforecast... variables without printing // // or ------------ // $doIncludeVC = true; // $doPrintConditions = true; // $doPrintHeadingVC = true; // $doPrintIconsVC = true; // $doPrintTextVC = false // include("VC-forecast.php"); include mode, print only heading and icon set // // Variables returned (useful for printing an icon or forecast or two...) // // $VCforecastcity - Name of city from VC Forecast header // // The following variables exist for $i=0 to $i= number of forecast periods minus 1 // a loop of for ($i=0;$i and Short legend. // $VCforecastwarnings = styled text with hotlinks to advisories/warnings // $VCcurrentConditions = table with current conds at point close to lat/long selected // // Settings --------------------------------------------------------------- // REQUIRED: a visualcrossing.com API KEY.. sign up at https://visualcrossing.com/ $VCAPIkey = 'specify-for-standalone-use-here'; // use this only for standalone / non-template use // NOTE: if using the Saratoga template, add to Settings.php a line with: // $SITE['VCAPIkey'] = 'your-api-key-here'; // and that will enable the script to operate correctly in your template // $iconDir ='./forecast/images/'; // directory for carterlake icons './forecast/images/' $iconType = '.jpg'; // default type='.jpg' // use '.gif' for animated icons fromhttp://www.meteotreviglio.com/ // // The forecast(s) .. make sure the first entry is the default forecast location. // The contents will be replaced by $SITE['VCforecasts'] if specified in your Settings.php $VCforecasts = array( // Location|lat,long (separated by | characters) 'Saratoga, CA, USA|37.27465,-122.02295', 'Auckland, NZ|-36.910,174.771', // Awhitu, Waiuku New Zealand 'Assen, NL|53.02277,6.59037', 'Blankenburg, DE|51.8089941,10.9080649', 'Cheyenne, WY, USA|41.144259,-104.83497', 'Carcassonne, FR|43.2077801,2.2790407', 'Braniewo, PL|54.3793635,19.7853585', 'Omaha, NE, USA|41.19043,-96.13114', 'Johanngeorgenstadt, DE|50.439339,12.706085', 'Athens, GR|37.97830,23.715363', 'Haifa, IL|32.7996029,34.9467358', ); // $maxWidth = '640px'; // max width of tables (could be '100%') $maxIcons = 8; // max number of icons to display $maxForecasts = 15; // max number of Text forecast periods to display $maxForecastLegendWords = 4; // more words in forecast legend than this number will use our forecast words $numIconsInFoldedRow = 8; // if words cause overflow of $maxWidth pixels, then put this num of icons in rows $autoSetTemplate = true; // =true set icons based on wide/narrow template design $cacheFileDir = './'; // default cache file directory $cacheName = "VC-forecast-json.txt"; // locally cached page from VC $refetchSeconds = 99993600; // cache lifetime (3600sec = 60 minutes) // // Units: // base: SI units (K,m/s,hPa,mm,km) // metric: same as base, except that temp in C and windSpeed and windGust are in kilometers per hour // uk: same as metric, except that nearestStormDistance and visibility are in miles, and windSpeed and windGust in miles per hour // us: Imperial units (F,mph,inHg,in,miles) // $showUnitsAs = 'metric'; // ='us' for imperial, , ='metric' for metric, ='uk' for UK // $charsetOutput = 'ISO-8859-1'; // default character encoding of output //$charsetOutput = 'UTF-8'; // for standalone use if desired $lang = 'en'; // default language $foldIconRow = false; // =true to display icons in rows of 5 if long texts are found $timeFormat = 'Y-m-d H:i T'; // default time display format $showConditions = true; // set to true to show current conditions box // ---- end of settings --------------------------------------------------- // overrides from Settings.php if available global $SITE; if (isset($SITE['VCforecasts'])) {$VCforecasts = $SITE['VCforecasts']; } if (isset($SITE['VCAPIkey'])) {$VCAPIkey = $SITE['VCAPIkey']; } // new V3.00 if (isset($SITE['VCshowUnitsAs'])) { $showUnitsAs = $SITE['VCshowUnitsAs']; } if (isset($SITE['fcsticonsdir'])) {$iconDir = $SITE['fcsticonsdir'];} if (isset($SITE['fcsticonstype'])) {$iconType = $SITE['fcsticonstype'];} if (isset($SITE['xlateCOP'])) {$xlateCOP = $SITE['xlateCOP'];} if (isset($LANGLOOKUP['Chance of precipitation'])) { $xlateCOP = $LANGLOOKUP['Chance of precipitation']; } if (isset($SITE['charset'])) {$charsetOutput = strtoupper($SITE['charset']); } if (isset($SITE['lang'])) {$lang = $SITE['lang'];} if (isset($SITE['cacheFileDir'])) {$cacheFileDir = $SITE['cacheFileDir']; } if (isset($SITE['foldIconRow'])) {$foldIconRow = $SITE['foldIconRow']; } if (isset($SITE['RTL-LANG'])) {$RTLlang = $SITE['RTL-LANG']; } if (isset($SITE['timeFormat'])) {$timeFormat = $SITE['timeFormat']; } if (isset($SITE['VCshowConditions'])) {$showConditions = $SITE['VCshowConditions'];} // new V1.05 // end of overrides from Settings.php // // -------------------begin code ------------------------------------------ $RTLlang = ',he,jp,cn,'; // languages that use right-to-left order 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; } $Status = "\n"; $VCcurrentConditions = ''; // HTML for table of current conditions //------------------------------------------------ if(preg_match('|specify|i',$VCAPIkey)) { print "

Note: the VC-forecast.php script requires an API key from Visualcrossing.com to operate.
"; print "Visit Visualcrossing.com to "; print "register for an API key.

\n"; if( isset($SITE['fcsturlVC']) ) { print "

Insert in Settings.php an entry for:

\n"; print "\$SITE['VCAPIkey'] = 'your-key-here';

\n"; print "replacing your-key-here with your VC API key.

\n"; } return; } /* iconSet=icons1 (default) Icon id Weather Conditions snow Amount of snow is greater than zero rain Amount of rainfall is greater than zero fog Visibility is low (lower than one kilometer or mile) wind Wind speed is high (greater than 30 kph or mph) cloudy Cloud cover is greater than 90% cover partly-cloudy-day Cloud cover is greater than 20% cover during day time. partly-cloudy-night Cloud cover is greater than 20% cover during night time. clear-day Cloud cover is less than 20% cover during day time clear-night Cloud cover is less than 20% cover during night time iconSet=icons2 Icon id Weather Conditions snow Amount of snow is greater than zero snow-showers-day Periods of snow during the day snow-showers-night Periods of snow during the night thunder-rain Thunderstorms throughout the day or night thunder-showers-day Possible thunderstorms throughout the day thunder-showers-night Possible thunderstorms throughout the night rain Amount of rainfall is greater than zero showers-day Rain showers during the day showers-night Rain showers during the night fog Visibility is low (lower than one kilometer or mile) wind Wind speed is high (greater than 30 kph or mph) cloudy Cloud cover is greater than 90% cover partly-cloudy-day Cloud cover is greater than 20% cover during day time. partly-cloudy-night Cloud cover is greater than 20% cover during night time. clear-day Cloud cover is less than 20% cover during day time clear-night Cloud cover is less than 20% cover during night time */ $NWSiconlist = array( // visualcrossing.com ICON definitions 'clear-day' => 'skc.jpg', 'clear-night' => 'nskc.jpg', 'rain' => 'ra.jpg', 'showers-day' => 'shra.jpg', 'showers-night' => 'nshra.jpg', 'snow' => 'sn.jpg', 'snow-showers-day' => 'sn.jpg', 'snow-showers-night' => 'nsn.jpg', 'sleet' => 'fzra.jpg', 'wind' => 'wind.jpg', 'fog' => 'fg.jpg', 'cloudy' => 'ovc.jpg', 'partly-cloudy-day' => 'sct.jpg', 'partly-cloudy-night' => 'nsct.jpg', 'hail' => 'ip.jpg', 'thunderstorm' => 'tsra.jpg', 'thunder-showers-day' => 'hi_tsra.jpg', 'thunder-showers-night' => 'hi_ntsra.jpg', 'tornado' => 'tor.jpg', 'wind' => 'wind.jpg', ); // $windUnits = array( 'base' => 'm/s', 'us' => 'mph', 'metric' => 'km/h', 'uk' => 'mph' ); $UnitsTab = array( 'base' => array('T'=>'°K','W'=>'m/s','P'=>'hPa','R'=>'mm','D'=>'km'), 'metric' => array('T'=>'°C','W'=>'km/s','P'=>'hPa','R'=>'mm','D'=>'km'), 'uk' => array('T'=>'°C','W'=>'mph','P'=>'mb','R'=>'mm','D'=>'mi'), 'us' => array('T'=>'°F','W'=>'mph','P'=>'inHg','R'=>'in','D'=>'mi'), ); if(isset($UnitsTab[$showUnitsAs])) { $Units = $UnitsTab[$showUnitsAs]; } else { $Units = $UnitsTab['metric']; } if(!function_exists('langtransstr')) { // shim function if not running in template set function langtransstr($input) { return($input); } } if(!function_exists('json_last_error')) { // shim function if not running PHP 5.3+ function json_last_error() { return('- N/A'); } $Status .= "\n"; if(!defined('JSON_ERROR_NONE')) { define('JSON_ERROR_NONE',0); } if(!defined('JSON_ERROR_DEPTH')) { define('JSON_ERROR_DEPTH',1); } if(!defined('JSON_ERROR_STATE_MISMATCH')) { define('JSON_ERROR_STATE_MISMATCH',2); } if(!defined('JSON_ERROR_CTRL_CHAR')) { define('JSON_ERROR_CTRL_CHAR',3); } if(!defined('JSON_ERROR_SYNTAX')) { define('JSON_ERROR_SYNTAX',4); } if(!defined('JSON_ERROR_UTF8')) { define('JSON_ERROR_UTF8',5); } } VC_loadLangDefaults (); // set up the language defaults if($charsetOutput == 'UTF-8') { foreach ($VClangCharsets as $l => $cs) { $VClangCharsets[$l] = 'UTF-8'; } $Status .= "\n"; $Status .= "\n"; } $VCLANG = 'en'; // Default to English for API $lang = strtolower($lang); if( isset($VClanguages[$lang]) ) { // if $lang is specified, use it $SITE['lang'] = $lang; $VCLANG = $VClanguages[$lang]; $charsetOutput = (isset($VClangCharsets[$lang]))?$VClangCharsets[$lang]:$charsetOutput; } if(isset($_GET['lang']) and isset($VClanguages[strtolower($_GET['lang'])]) ) { // template override $lang = strtolower($_GET['lang']); $SITE['lang'] = $lang; $VCLANG = $VClanguages[$lang]; $charsetOutput = (isset($VClangCharsets[$lang]))?$VClangCharsets[$lang]:$charsetOutput; } $doRTL = (strpos($RTLlang,$lang) !== false)?true:false; // format RTL language in Right-to-left in output if(isset($SITE['copyr']) and $doRTL) { // running in a Saratoga template. Turn off $doRTL $Status .= "\n"; $doRTL = false; } if(isset($doShowConditions)) {$showConditions = $doShowConditions;} if($doRTL) {$RTLopt = ' style="direction: rtl;"'; } else {$RTLopt = '';}; // get the selected forecast location code $haveIndex = '0'; if (!empty($_GET['z']) && preg_match("/^[0-9]+$/i", htmlspecialchars($_GET['z']))) { $haveIndex = htmlspecialchars(strip_tags($_GET['z'])); // valid zone syntax from input } if(!isset($VCforecasts[0])) { // print "\n"; $VCforecasts = array("Saratoga|37.27465,-122.02295"); // create default entry } if(isset($useUTF8) and $useUTF8) { $charsetOutput = 'UTF-8'; $Status .= "\n"; } if($charsetOutput == 'UTF-8') { foreach ($VClangCharsets as $l => $cs) { $VClangCharsets[$l] = 'UTF-8'; } $Status .= "\n"; $Status .= "\n"; } if($showUnitsAs == 'us' or strpos($timeFormat,'g') !== false) { $showAMPMtime = true; $Status .= "\n"; } else { $showAMPMtime = false; $Status .= "\n"; } if(!headers_sent()) { header('Content-type: text/html,charset='.$charsetOutput); } // print "\n"; // Set the default zone. The first entry in the $SITE['NWSforecasts'] array. list($Nl,$Nn) = explode('|',$VCforecasts[0].'|||'); $FCSTlocation = $Nl; $VC_LATLONG = $Nn; if(!isset($VCforecasts[$haveIndex])) { $haveIndex = 0; } // locations added to the drop down menu and set selected zone values $dDownMenu = ''; for ($m=0;$m".langtransstr($Nlocation)."\n"; } // build the drop down menu $ddMenu = ''; // create menu if at least two locations are listed in the array if (isset($VCforecasts[0]) and isset($VCforecasts[1])) { $ddMenu .= '

'; } $Force = false; if (isset($_REQUEST['force']) and $_REQUEST['force']=="1" ) { $Force = true; } $doDebug = false; if (isset($_REQUEST['debug']) and strtolower($_REQUEST['debug'])=='y' ) { $doDebug = true; } $showTempsAs = $UnitsTab[$showUnitsAs]['T']; $Status .= "\n"; $fileName = "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/$VC_LATLONG/" . "?key=$VCAPIkey&include=days,hours,alerts,current&lang=$VCLANG&unitGroup=$showUnitsAs&iconSet=icons2"; if ($doDebug) { $Status .= "\n"; } if ($autoSetTemplate and isset($_SESSION['CSSwidescreen'])) { if($_SESSION['CSSwidescreen'] == true) { $maxWidth = '900px'; $maxIcons = 8; $maxForecasts = 8; $numIconsInFoldedRow = 7; $Status .= "\n"; } if($_SESSION['CSSwidescreen'] == false) { $maxWidth = '640px'; $maxIcons = 8; $maxForecasts = 8; $numIconsInFoldedRow = 7; $Status .= "\n"; } } $cacheName = $cacheFileDir . $cacheName; $cacheName = preg_replace('|\.txt|is',"-$haveIndex-$showUnitsAs-$lang.txt",$cacheName); // unique cache per language used $APIfileName = $fileName; if($showConditions) { $refetchSeconds = 15*60; // shorter refresh time so conditions will be 'current' } if (! $Force and file_exists($cacheName) and filemtime($cacheName) + $refetchSeconds > time()) { $html = implode('', file($cacheName)); $Status .= "\n"; } else { $Status .= "\n"; $html = VC_fetchUrlWithoutHanging($APIfileName,false); $RC = ''; if (preg_match("|^HTTP\/\S+ (.*)\r\n|",$html,$matches)) { $RC = trim($matches[1]); } $Status .= "\n"; if (preg_match('|30\d|',$RC)) { // handle possible blocked redirect preg_match('|Location: (\S+)|is',$html,$matches); if(isset($matches[1])) { $sURL = $matches[1]; if(preg_match('|opendns.com|i',$sURL)) { $Status .= "\n"; } else { $Status .= "\n"; $html = VC_fetchUrlWithoutHanging($sURL,false); $RC = ''; if (preg_match("|^HTTP\/\S+ (.*)\r\n|",$html,$matches)) { $RC = trim($matches[1]); } $Status .= "\n"; } } } if(preg_match('!datetimeEpoch!is',$html)) { $fp = fopen($cacheName, "w"); if (!$fp) { $Status .= "\n"; } else { $write = fputs($fp, $html); fclose($fp); $Status .= "\n"; } } else { $Status .= "\n"; if(file_exists($cacheName) and filesize($cacheName) > 3000) { $html = implode('', file($cacheName)); $Status .= "\n"; } else { $Status .= "\n"; print $Status; print "

Sorry.. the Visualcrossing forecast is not available.

\n"; return; } } } $charsetInput = 'UTF-8'; $doIconv = ($charsetInput == $charsetOutput)?false:true; // only do iconv() if sets are different if($charsetOutput == 'UTF-8') { $doIconv = false; } $Status .= "\n"; $tranTab = VC_loadTranslate($lang); $i = strpos($html,"\r\n\r\n"); $headers = substr($html,0,$i-1); $content = substr($html,$i+4); // process the file .. select out the 7-day forecast part of the page $UnSupported = false; // -------------------------------------------------------------------------------------------------- $Status .= "\n"; $i = strpos($html,"\r\n\r\n"); $headers = substr($html,0,$i-1); $content = substr($html,$i+4); $rawJSON = $content; $Status .= "\n"; $rawJSON = VC_prepareJSON($rawJSON); $JSON = json_decode($rawJSON,true); // get as associative array $Status .= VC_decode_JSON_error(); if(isset($_GET['debug'])) {$Status .= "\n";} file_put_contents('VC-json.txt',var_export($JSON,true)); if(isset($JSON['days'][0]['datetime'])) { // got good JSON .. process it $UnSupported = false; $VCforecastcity = $FCSTlocation; if($doIconv) {$VCforecastcity = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCforecastcity);} if($doDebug) { $Status .= "\n"; } //$VCtitle = langtransstr("Forecast"); $VCtitle = isset($tranTab['Visualcrossing Forecast for:'])? $tranTab['Visualcrossing Forecast for:']:'Visualcrossing Forecast for:'; if($doIconv) {$VCtitle = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCtitle);} if($doDebug) { $Status .= "\n"; } /* array ( 'queryCost' => 1, 'latitude' => 37.27465, 'longitude' => -122.02295, 'resolvedAddress' => '37.27465,-122.02295', 'address' => '37.27465,-122.02295', 'timezone' => 'America/Los_Angeles', 'tzoffset' => -8.0, 'days' => array ( 0 => array ( 'datetime' => '2023-01-20', 'datetimeEpoch' => 1674201600, 'tempmax' => 12.5, 'tempmin' => 3.6, 'temp' => 6.5, 'feelslikemax' => 12.5, 'feelslikemin' => 1.0, 'feelslike' => 5.3, 'dew' => -0.3, 'humidity' => 63.8, 'precip' => 0.0, 'precipprob' => 0.0, 'precipcover' => 0.0, 'preciptype' => NULL, 'snow' => 0.0, 'snowdepth' => 0.0, 'windgust' => 33.5, 'windspeed' => 17.9, 'winddir' => 327.4, 'pressure' => 1025.7, 'cloudcover' => 2.0, 'visibility' => 16.1, 'solarradiation' => 140.9, 'solarenergy' => 11.9, 'uvindex' => 5.0, 'severerisk' => 10.0, 'sunrise' => '07:19:11', 'sunriseEpoch' => 1674227951, 'sunset' => '17:19:29', 'sunsetEpoch' => 1674263969, 'moonphase' => 0.99, 'conditions' => 'Clear', 'description' => 'Clear conditions throughout the day.', 'icon' => 'clear-day', 'stations' => array ( 0 => 'KSJC', 1 => 'C1792', 2 => 'KNUQ', 3 => 'KWVI', ), 'source' => 'comb', 'hours' => array ( 0 => */ if(isset($JSON['timezone'])) { date_default_timezone_set($JSON['timezone']); $Status .= "\n"; } if(isset($JSON['days'][0]['datetimeEpoch'])) { $VCupdated = $tranTab['Updated:']; if($doIconv) { $VCupdated = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCupdated). ' '; } $VCupdated .= date($timeFormat,$JSON['days'][0]['datetimeEpoch']); } else { $VCupdated = ''; } if($doDebug) { $Status .= "\n\n"; } if(isset($windUnits[$showUnitsAs])) { $windUnit = $windUnits[$showUnitsAs]; $Status .= "\n"; if(isset($tranTab[$windUnit])) { $windUnit = $tranTab[$windUnit]; $Status .= "\n"; } } else { $windUnit = ''; } $n = 0; foreach ($JSON['days'] as $i => $FCpart) { # process each daily entry list($tDay,$tTime) = explode(" ",date('l H:i:s',$FCpart['datetimeEpoch'])); if ($doDebug) { $Status .= "\n"; } $VCforecastdayname[$n] = $tDay; if(isset($tranTab[$tDay])) { $VCforecastday[$n] = $tranTab[$tDay]; } else { $VCforecastday[$n] = $tDay; } if($doIconv) { $VCforecastday[$n] = iconv("UTF-8",$charsetOutput.'//IGNORE',$VCforecastday[$n]); } $VCforecasttitles[$n] = $VCforecastday[$n]; if ($doDebug) { $Status .= "\n"; } $VCforecastcloudcover[$n] = $FCpart['cloudcover']/100.0; # convert to fraction percent # extract the temperatures $VCforecasttemp[$n] = "".VC_round($FCpart['tempmax'],0)."$showTempsAs"; $VCforecasttemp[$n] .= "
".VC_round($FCpart['tempmin'],0)."$showTempsAs"; # extract the icon to use $VCforecasticon[$n] = $FCpart['icon']; if ($doDebug) { $Status .= "\n"; } if(isset($FCpart['precipprob'])) { $VCforecastpop[$n] = round($FCpart['precipprob'],0); } else { $VCforecastpop[$n] = 0; } if ($doDebug) { $Status .= "\n"; } if(isset($FCpart['preciptype']) and !empty($FCpart['preciptype'])) { $VCforecastpreciptypeEN[$n] = join(',',$FCpart['preciptype']); $VCforecastpreciptype[$n] = $FCpart['preciptype']; } else { $VCforecastpreciptypeEN[$n] = ''; } $VCforecasttext[$n] = // replace problematic characters in forecast text str_replace( array('<', '>', '–','cm.','in.','.)'), array('<','>','-', 'cm', 'in',')'), trim($FCpart['description'])); if(strpos($VCforecasttext[$n],'.') === false) {$VCforecasttext[$n] .= '.'; } # Add info to the forecast text if($VCforecastpop[$n] > 0) { $tstr = ''; if(!empty($VCforecastpreciptype[$n])) { $t = $VCforecastpreciptype[$n]; foreach ($t as $k => $ptype) { if(!empty($ptype)) {$tstr .= $tranTab[$ptype].',';} } if(strlen($tstr)>0) { $tstr = '('.substr($tstr,0,strlen($tstr)-1) .') '; } $Status .= "\n"; } $VCforecasttext[$n] .= " ". $tranTab['Chance of precipitation']." $tstr".$VCforecastpop[$n]."%. "; } $VCforecasttext[$n] .= " ".$tranTab['High:']." ".VC_round($FCpart['tempmax'],0)."$showTempsAs. "; $VCforecasttext[$n] .= " ".$tranTab['Low:']." ".VC_round($FCpart['tempmin'],0)."$showTempsAs. "; $tWdir = VC_WindDir(round($FCpart['winddir'],0)); $VCforecasttext[$n] .= " ".$tranTab['Wind']." ".VC_WindDirTrans($tWdir); $VCforecasttext[$n] .= " ". round($FCpart['windspeed'],0)."->".round($FCpart['windgust'],0) . " $windUnit."; if(isset($FCpart['uvindex']) and $FCpart['uvindex'] > 1) { $VCforecasttext[$n] .= " ".$tranTab['UV index']." ".round($FCpart['uvindex'],0)."."; } if($doIconv) { $VCforecasttext[$n] = iconv("UTF-8",$charsetOutput.'//IGNORE',$VCforecasttext[$n]); } if ($doDebug) { $Status .= "\n"; } #$temp = explode('.',$VCforecasttext[$n]); // split as sentences (sort of). #$VCforecastcond[$n] = trim($temp[0]); // take first one as summary. $VCforecastcond[$n] = $FCpart['conditions']; if($doIconv) { $VCforecastcond[$n] = iconv("UTF-8",$charsetOutput.'//IGNORE',$VCforecastcond[$n]); } if ($doDebug) { $Status .= "\n"; } $VCpreciptype[$n] = $FCpart['preciptype']; $VCforecasticons[$n] = $VCforecastday[$n] . "
" . VC_img_replace( $VCforecasticon[$n], $VCforecastcond[$n], (integer)round($VCforecastpop[$n],-1), $VCforecastcloudcover[$n], $VCpreciptype[$n]) . ' ' . $VCforecastpreciptypeEN[$n] . "
" . $VCforecastcond[$n]; $n++; } // end of process text forecasts if(isset($JSON['flags']['sources'])) { $dsSources = VC_sources($JSON['flags']['sources']); // $Status .= "\n"; } else { $dsSources = ''; } // process alerts if any are available $VCforecastwarnings = ''; if (isset($JSON['alerts']) and is_array($JSON['alerts']) and count($JSON['alerts']) > 0) { $Status.= "\n"; foreach($JSON['alerts'] as $i => $ALERT) { $expireUTC = strtotime($ALERT['ends']); $expires = date($timeFormat,$ALERT['endsEpoch']); $Status.= "\n"; $regions = ''; if(isset($ALERT['regions']) and is_array($ALERT['regions'])) { foreach ($ALERT['regions'] as $i => $reg) { $regions .= $reg . ', '; } $regions = substr($regions,0,strlen($regions)-2); } if (time() < $expireUTC) { $VCforecastwarnings .= '' . '' . $ALERT['event'] . "
\n"; } else { $Status.= "\n"; } } } else { $Status.= "\n"; } // make the Current conditions table from $currently array $currently = $JSON['currentConditions']; /* 'currentConditions' => array ( 'datetime' => '15:57:10', 'datetimeEpoch' => 1674259030, 'temp' => 11.2, 'feelslike' => 11.2, 'humidity' => 46.0, 'dew' => -0.1, 'precip' => 0.0, 'precipprob' => 0.0, 'snow' => 0.0, 'snowdepth' => 0.0, 'preciptype' => NULL, 'windgust' => NULL, 'windspeed' => 11.9, 'winddir' => 316.0, 'pressure' => 1026.0, 'visibility' => 16.0, 'cloudcover' => 0.0, 'solarradiation' => 248.0, 'solarenergy' => 0.9, 'uvindex' => 2.0, 'conditions' => 'Clear', 'icon' => 'clear-day', 'stations' => array ( 0 => 'KSJC', 1 => 'C1792', 2 => 'KNUQ', ), 'source' => 'obs', 'sunrise' => '07:19:11', 'sunriseEpoch' => 1674227951, 'sunset' => '17:19:29', 'sunsetEpoch' => 1674263969, 'moonphase' => 0.99, ), */ $nCols = 3; // number of columns in the conditions table if (isset($currently['datetimeEpoch']) ) { // only generate if we have the data if (isset($currently['icon']) and ! $currently['icon'] ) { $nCols = 2; }; $VCcurrentConditions = '' . "\n"; $VCcurrentConditions .= ' ' . "\n\n"; if (isset($currently['icon'])) { $VCcurrentConditions .= ' '; } // end of icon $VCcurrentConditions .= " '; $VCcurrentConditions .= ' '; if(isset($JSON['daily']['summary'])) { if($doRTL) { $VCcurrentConditions .= ' '; } else { $VCcurrentConditions .= ' '; } } $VCcurrentConditions .= '
' . $tranTab['Currently'].': '. date($timeFormat,$currently['datetimeEpoch']) . "
\n"; $tS = $currently['stations'][0]; // Name of first station in list $tD = isset($JSON['stations'][$tS]['distance'])?$JSON['stations'][$tS]['distance']:0.0; switch ($showUnitsAs) { case 'base' : $tD = round($tD/1000,1); break; // in km case 'metric': $tD = round($tD/1000,1); break; case 'us' : $tD = round($tD*0.000621371,1); break; // in miles case 'uk' : $tD = round($tD*0.000621371,1); break; default : $tD = $tD; } $t = $tranTab['Weather conditions at 999 from forecast point.']; $t = str_replace('999',$tD.' '.$Units['D'],$t); $VCcurrentConditions .= $t . '
' . VC_img_replace( $currently['icon'], $currently['conditions'], round($currently['precipprob'],-1), $currently['cloudcover'], $currently['preciptype']) . "
\n" . $currently['conditions']; $VCcurrentConditions .= '
\n"; if (isset($currently['temp'])) { $VCcurrentConditions .= $tranTab['Temperature'].": ". VC_round($currently['temp'],0) . $Units['T'] . "
\n"; } if (isset($currently['windchill'])) { $VCcurrentConditions .= $tranTab['Wind chill'].": ". VC_round($currently['windchill'],0) . $Units['T']. "
\n"; } if (isset($currently['heatindex'])) { $VCcurrentConditions .= $tranTab['Heat index'].": " . VC_round($currently['heatindex']) . $Units['T']. "
\n"; } if (isset($currently['windspeed'])) { $tWdir = VC_WindDir(round($currently['winddir'],0)); $VCcurrentConditions .= $tranTab['Wind'].": ".VC_WindDirTrans($tWdir); $VCcurrentConditions .= " ".round($currently['windspeed'],0); $VCcurrentConditions .= isset($currently['windgust'])? "->".round($currently['windgust'],0):''; $VCcurrentConditions .= " $windUnit." . "
\n"; } if (isset($currently['humidity'])) { $VCcurrentConditions .= $tranTab['Humidity'].": ". round($currently['humidity'],0) . "%
\n"; } if (isset($currently['dew'])) { $VCcurrentConditions .= $tranTab['Dew Point'].": ". VC_round($currently['dew'],0) . $Units['T'] . "
\n"; } $VCcurrentConditions .= $tranTab['Barometer'].": ". VC_conv_baro($currently['pressure']) . " " . $Units['P'] . "
\n"; if (isset($currently['visibility'])) { $VCcurrentConditions .= $tranTab['Visibility'].": ". round($currently['visibility'],1) . " " . $Units['D']. "\n" ; } if (isset($currently['uvindex'])) { $VCcurrentConditions .= '
'.$tranTab['UV index'].": ". round($currently['uvindex'],0) . "\n" ; } $VCcurrentConditions .= '
'; if(isset($currently['sunriseEpoch']) and isset($currently['sunsetEpoch']) ) { $tFMT = 'H:i'; if($showUnitsAs == 'us' or strpos($timeFormat,'g') !== false) {$tFMT = 'g:ia'; } $VCcurrentConditions .= $tranTab['Sunrise'].': '. date($tFMT,$currently['sunriseEpoch']) . "
\n" . $tranTab['Sunset'].': '. date($tFMT,$currently['sunsetEpoch']) . "
\n" ; } $VCcurrentConditions .= '
' . $JSON['daily']['summary'] . '
' . $JSON['daily']['summary'] . '
'; if($doIconv) { $VCcurrentConditions = iconv('UTF-8',$charsetOutput.'//TRANSLIT',$VCcurrentConditions); } } // end of if isset($currently['cityobserved']) // end of current conditions mods /* icon meanings clear-day Cloud cover is less than 20% cover during day time clear-night Cloud cover is less than 20% cover during night time cloudy Cloud cover is greater than 90% cover fog Visibility is low (lower than one kilometer or mile) partly-cloudy-day Cloud cover is greater than 20% cover during day time. partly-cloudy-night Cloud cover is greater than 20% cover during night time. rain Amount of rainfall is greater than zero showers-day Rain showers during the day showers-night Rain showers during the night snow Amount of snow is greater than zero snow-showers-day Periods of snow during the day snow-showers-night Periods of snow during the night thunder-rain Thunderstorms throughout the day or night thunder-showers-day Possible thunderstorms throughout the day thunder-showers-night Possible thunderstorms throughout the night wind Wind speed is high (greater than 30 kph or mph)*/ $timelineColors = array( // timeline Colors to use for each condition "clear-day" => "#eeeef5", "clear-night" => "#eeeef5", "partly-cloudy-day" => "#d5dae2", "partly-cloudy-night" => "#d5dae2", "cloudy"=> "#b6bfcb", "rain" => "#4a80c7", "showers-day" => "#80a5d6", "showers-night" => "#80a5d6", "thunder-rain" => "#ffdead", "thunder-showers-day" => "#ffdead", "thunder-showers-night" => "#ffdead", "snow" => "#8c82ce", "snow-showers-day" => "#aba4db", "snow-showers-night" => "#aba4db", "Flurries"=> "#b7b2db", "Sleet"=> "#6264a7", "fog" => "#d5dae2", "wind" => "#ffdead", "Windy" => "#ffdead", ); if(isset($JSON['days'][0]['hours'][0]['datetimeEpoch'])) { // process Hourly forecast data /* 'hours' => array ( 0 => array ( 'datetime' => '00:00:00', 'datetimeEpoch' => 1674201600, 'temp' => 5.2, 'feelslike' => 5.2, 'humidity' => 80.74, 'dew' => 2.2, 'precip' => 0.0, 'precipprob' => 0.0, 'snow' => 0.0, 'snowdepth' => 0.0, 'preciptype' => NULL, 'windgust' => 11.2, 'windspeed' => 0.0, 'winddir' => 0.0, 'pressure' => 1024.1, 'visibility' => 16.0, 'cloudcover' => 0.0, 'solarradiation' => 0.0, 'solarenergy' => NULL, 'uvindex' => 0.0, 'severerisk' => 10.0, 'conditions' => 'Clear', 'icon' => 'clear-night', 'stations' => array ( 0 => 'KSJC', 1 => 'KNUQ', 2 => 'KWVI', ), 'source' => 'obs', ), */ $newJSON = array(); // storage for the merry-timeline JSON foreach ($JSON['days'] as $dayNumber => $dayData) { /* { "color": "#b7b2db", "text": "Flurries", "annotation": "0°", "time": 1672257600 }, */ $tempUOM = str_replace('°'," ",$UnitsTab[$showUnitsAs]['T']); foreach($dayData['hours'] as $i => $H) { $dayname = date('l',$H['datetimeEpoch']); if(isset($tranTab[$dayname])) {$dayname = $tranTab[$dayname]; if($doIconv) {iconv($charsetInput,$charsetOutput.'//TRANSLIT',$dayname); } $dayname .= ', '.date('d',$H['datetimeEpoch']); $tColor = isset($timelineColors[$H['icon']])?$timelineColors[$H['icon']]:'#fefefe'; $text = $H['conditions']; if($doIconv) {iconv($charsetInput,$charsetOutput.'//TRANSLIT',$text);} $newJSON[$dayname][] = array( 'color' => $tColor, 'text' => $text, 'annotation' => round($H['temp'],0).$tempUOM, 'time' => $H['datetimeEpoch'] ); } // end each hourly forecast parsing } // end process hourly forecast data } // end loop over day/hours $utfdata = json_encode($newJSON,JSON_UNESCAPED_UNICODE); $merrytimelineJSON = ($doIconv)?iconv('UTF-8',$charsetOutput.'//TRANSLIT//IGNORE',$utfdata):$utfdata; $hourlyData = "\n"; if(isset($_GET['debug'])) { $hourlyData .= "\n"; } if(isset($_GET['snapshot'])) { file_put_contents('./raw-weatherData-json.txt',$merrytimelineJSON); file_put_contents('./raw-newJSON-array.txt',var_export($newJSON,true)); $Status .= "\n"; } } // end setup for merry-timeline /* // old version if(isset($JSON['hourly']['data'][0]['time'])) { // process Hourly forecast data /* "hourly": { "summary": "Mostly cloudy throughout the day.", "icon": "partly-cloudy-night", "data": [{ "time": 1548018000, "summary": "Mostly Cloudy", "icon": "partly-cloudy-day", "precipIntensity": 0.1422, "precipProbability": 0.29, "precipType": "rain", "temperature": 14.91, "apparentTemperature": 14.91, "dewPoint": 11.49, "humidity": 0.8, "pressure": 1017.89, "windSpeed": 10.8, "windGust": 24.54, "windBearing": 226, "cloudCover": 0.88, "uvIndex": 2, "visibility": 14.11, "ozone": 289.95 }, { //*/ /* foreach($JSON['hourly']['data'] as $i => $FCpart) { $VCforecasticonHR[$i] = VC_gen_hourforecast($FCpart); if($doIconv) { $VCforecasticonHR[$i]['icon'] = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCforecasticonHR[$i]['icon']). ' '; $VCforecasticonHR[$i]['temp'] = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCforecasticonHR[$i]['temp']). ' '; $VCforecasticonHR[$i]['wind'] = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCforecasticonHR[$i]['wind']). ' '; $VCforecasticonHR[$i]['precip'] = iconv($charsetInput,$charsetOutput.'//TRANSLIT',$VCforecasticonHR[$i]['precip']). ' '; } if($doDebug) { $Status .= "\n"; } } // end each hourly forecast parsing } // end process hourly forecast data */ } // end got good JSON decode/process // end process JSON style -------------------------------------------------------------------- // All finished with parsing, now prepare to print if(!isset($VCforecasticons[0]) ) {print "

Forecast not available.

\n"; print $Status; exit(0); } $wdth = intval(100/count($VCforecasticons)); $ndays = intval(count($VCforecasticon)/2); $doNumIcons = $maxIcons; if(count($VCforecasticons) < $maxIcons) { $doNumIcons = count($VCforecasticons); } $IncludeMode = false; $PrintMode = true; if (isset($doPrintVC) && ! $doPrintVC ) { print $Status; return; } if (isset($_REQUEST['inc']) && strtolower($_REQUEST['inc']) == 'noprint' ) { print $Status; return; } if (isset($_REQUEST['inc']) && strtolower($_REQUEST['inc']) == 'y') { $IncludeMode = true; } if (isset($doIncludeVC)) { $IncludeMode = $doIncludeVC; } $printHeading = true; $printIcons = true; $printText = true; if (isset($doPrintHeadingVC)) { $printHeading = $doPrintHeadingVC; } if (isset($_REQUEST['heading']) ) { $printHeading = substr(strtolower($_REQUEST['heading']),0,1) == 'y'; } if (isset($doPrintIconsVC)) { $printIcons = $doPrintIconsVC; } if (isset($_REQUEST['icons']) ) { $printIcons = substr(strtolower($_REQUEST['icons']),0,1) == 'y'; } if (isset($doPrintTextVC)) { $printText = $doPrintTextVC; } if (isset($_REQUEST['text']) ) { $printText = substr(strtolower($_REQUEST['text']),0,1) == 'y'; } if (! $IncludeMode and $PrintMode) { ?> <?php echo $VCtitle . ' - ' . $VCforecastcity; ?> Sorry.. this forecast can not be processed at this time. EONAG ; } if (strlen($VCforecasttext[0])<2 and $PrintMode and ! $UnSupported ) { echo '

'.langtransstr('Forecast blank?').' ' . langtransstr('Force Update').'

'; } if ($PrintMode and ($printHeading or $printIcons)) { ?> \n"; } ?>
\n"; print $VCcurrentConditions; print "
0) { echo "
$VCupdated\n"; } ?>

 

\n"; $maxChars = 135; if($iTitleLen >= $maxChars or $iCondLen >= $maxChars or $iTempLen >= $maxChars ) { print "\n"; $doFoldRow = true; } } $startIcon = 0; $finIcon = $doNumIcons; $incr = $doNumIcons; $doFoldRow = false; if ($doFoldRow) { $wdth = $wdth*2; $incr = $numIconsInFoldedRow; } print "\n"; for ($k=$startIcon;$k<$doNumIcons-1;$k+=$incr) { // loop over icon rows, 5 at a time until done $startIcon = $k; if ($doFoldRow) { $finIcon = $startIcon+$numIconsInFoldedRow; } else { $finIcon = $doNumIcons; } $finIcon = min($finIcon,$doNumIcons); print "\n"; print " \n"; for ($i=$startIcon;$i<$finIcon;$i++) { $ni = $doRTL?$numIconsInFoldedRow-1-$i+$startIcon+$k:$i; print "\n"; print "\n"; } print " \n"; print " \n"; for ($i=$startIcon;$i<$finIcon;$i++) { $ni = $doRTL?$numIconsInFoldedRow-1-$i+$startIcon+$k:$i; print "\n"; } ?> $VCforecastcond[$ni]\n"; } print " \n"; print " \n"; for ($i=$startIcon;$i<$finIcon;$i++) { $ni = $doRTL?$numIconsInFoldedRow-1-$i+$startIcon+$k:$i; print "\n"; } ?> \n"; for ($i=$startIcon;$i<$finIcon;$i++) { $ni = $doRTL?$numIconsInFoldedRow-1-$i+$startIcon+$k:$i; print "\n"; } ?> \n"; for ($i=$startIcon;$i<$finIcon;$i++) { print "\n"; } print "\n"; } // end doFoldRow ?>
$VCforecasttitles[$ni]
" . VC_img_replace($VCforecasticon[$ni], $VCforecastcond[$ni], round($VCforecastpop[$ni],-1), $VCforecastcloudcover[$ni], $VCpreciptype[$ni]) . "
$VCforecasttemp[$ni]
"; if($VCforecastpop[$ni] > 0) { print "PoP: $VCforecastpop[$ni]%"; } else { print " "; } print "
 

'') { if($doIconv) { $VCforecastwarnings = iconv($charsetInput,$charsetOutput.'//IGNORE',$VCforecastwarnings); } $tW = 'width: 640px;'; if($doRTL) {$tW .= 'direction: rtl;';} print "

$VCforecastwarnings

\n"; } ?>
\n"; if(!$doRTL) { // normal Left-to-right print "\n"; print "\n"; } else { // print RTL format print "\n"; print "\n"; } print "\n"; } ?>
$VCforecasttitles[$i]
 
$VCforecasttext[$i]$VCforecasttext[$i]$VCforecasttitles[$i]
 

\n"; for ($n=$row*8;$n<$row*8+8;$n++) { $ni = $doRTL?($row+1)*8-$n-1+($row*8):$n; if(isset($VCforecasticonHR[$ni]['icon'])) { print ''.$VCforecasticonHR[$ni]['icon']."";; } else { print " "; } } print "\n"; print " \n"; for ($n=$row*8;$n<$row*8+8;$n++) { $ni = $doRTL?($row+1)*8-$n-1+($row*8):$n; if(isset($VCforecasticonHR[$ni]['temp'])) { print ''.$VCforecasticonHR[$ni]['temp']."";; } else { print " "; } } print "\n"; print " \n"; for ($n=$row*8;$n<$row*8+8;$n++) { $ni = $doRTL?($row+1)*8-$n-1+($row*8):$n; if(isset($VCforecasticonHR[$ni]['UV'])) { print ''.$VCforecasticonHR[$ni]['UV']."";; } else { print " "; } } print "\n"; print " \n"; for ($n=$row*8;$n<$row*8+8;$n++) { $ni = $doRTL?($row+1)*8-$n-1+($row*8):$n; if(isset($VCforecasticonHR[$ni]['wind'])) { print ''.$VCforecasticonHR[$ni]['wind']."";; } else { print " "; } } print "\n"; print " \n"; for ($n=$row*8;$n<$row*8+8;$n++) { $ni = $doRTL?($row+1)*8-$n-1+($row*8):$n; if(isset($VCforecasticonHR[$ni]['precip'])) { print ''.$VCforecasticonHR[$ni]['precip']."";; } else { print " "; } } print "\n"; print "
\n"; } // end rows */ ?>

Timeline display based on Merry-Timeline by Guillaume Carbonneau

 

Visualcrossing.com.
'.jpg') { print "
".langtransstr('Animated forecast icons courtesy of')." www.meteotreviglio.com."; } if(strlen($dsSources) > 1) { print "
".langtransstr('Sources for this forecast').": $dsSources\n"; } print "

\n"; ?> \n"; $ch = curl_init(); // initialize a cURL session curl_setopt($ch, CURLOPT_URL, $theURL); // connect to provided URL curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // don't verify peer certificate curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (VC-forecast.php - saratoga-weather.org)'); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $numberOfSeconds); // connection timeout curl_setopt($ch, CURLOPT_TIMEOUT, $numberOfSeconds); // data timeout curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // return the data transfer curl_setopt($ch, CURLOPT_NOBODY, false); // set nobody curl_setopt($ch, CURLOPT_HEADER, true); // include header information if (isset($needCookie[$domain])) { curl_setopt($ch, $needCookie[$domain]); // set the cookie for this request curl_setopt($ch, CURLOPT_COOKIESESSION, true); // and ignore prior cookies $Status .= "\n"; } $data = curl_exec($ch); // execute session if(curl_error($ch) <> '') { // IF there is an error $Status .= "\n"; // display error notice } $cinfo = curl_getinfo($ch); // get info on curl exec. /* curl info sample Array ( [url] => http://saratoga-weather.net/clientraw.txt [content_type] => text/plain [http_code] => 200 [header_size] => 266 [request_size] => 141 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.125 [namelookup_time] => 0.016 [connect_time] => 0.063 [pretransfer_time] => 0.063 [size_upload] => 0 [size_download] => 758 [speed_download] => 6064 [speed_upload] => 0 [download_content_length] => 758 [upload_content_length] => -1 [starttransfer_time] => 0.125 [redirect_time] => 0 [redirect_url] => [primary_ip] => 74.208.149.102 [certinfo] => Array ( ) [primary_port] => 80 [local_ip] => 192.168.1.104 [local_port] => 54156 ) */ $Status .= "\n"; //$Status .= "\n"; curl_close($ch); // close the cURL session //$Status .= "\n"; $i = strpos($data,"\r\n\r\n"); $headers = substr($data,0,$i); $content = substr($data,$i+4); if($cinfo['http_code'] <> 200) { $Status .= "\n"; } return $data; // return headers+contents } else { // print "\n"; $STRopts = array( 'http'=>array( 'method'=>"GET", 'protocol_version' => 1.1, 'header'=>"Cache-Control: no-cache, must-revalidate\r\n" . "Cache-control: max-age=0\r\n" . "Connection: close\r\n" . "User-agent: Mozilla/5.0 (VC-forecast.php - saratoga-weather.org)\r\n" . "Accept: text/plain,text/html\r\n" ), 'https'=>array( 'method'=>"GET", 'protocol_version' => 1.1, 'header'=>"Cache-Control: no-cache, must-revalidate\r\n" . "Cache-control: max-age=0\r\n" . "Connection: close\r\n" . "User-agent: Mozilla/5.0 (VC-forecast.php - saratoga-weather.org)\r\n" . "Accept: text/plain,text/html\r\n" ) ); $STRcontext = stream_context_create($STRopts); $T_start = VC_fetch_microtime(); $xml = file_get_contents($url,false,$STRcontext); $T_close = VC_fetch_microtime(); $headerarray = get_headers($url,0); $theaders = join("\r\n",$headerarray); $xml = $theaders . "\r\n\r\n" . $xml; $ms_total = sprintf("%01.3f",round($T_close - $T_start,3)); $Status .= "\n"; $Status .= "<-- get_headers returns\n".$theaders."\n -->\n"; // print " file() stats: total=$ms_total secs.\n"; $overall_end = time(); $overall_elapsed = $overall_end - $overall_start; $Status .= "\n"; // print "fetch function elapsed= $overall_elapsed secs.\n"; return($xml); } } // end VC_fetch_URL // ------------------------------------------------------------------ function VC_fetch_microtime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } // ------------------------------------------------------------------------------------------- function VC_img_replace ( $VCimage, $VCcondtext,$VCpop,$VCcloudcover,$VCpreciptype) { // // optionally replace the WeatherUnderground icon with an NWS icon instead. // global $NWSiconlist,$iconDir,$iconType,$Status; $curicon = isset($NWSiconlist[$VCimage])?$NWSiconlist[$VCimage]:''; // translated icon (if any) $tCCicon = VC_octets($VCcloudcover); if (!$curicon) { // no change.. use NA icon return("\"$VCcondtext\""); } // override icon with cloud coverage octets for Images of partly-cloudy-* and clear-* if(preg_match('/^(partly|clear)/i',$VCimage)) { $curicon = $tCCicon.'.jpg'; if(strpos($VCimage,'-night') !==false) { $curicon = 'n'.$curicon; } $Status .= "\n"; } if(preg_match('/^wind/i',$VCimage) and $iconType !== '.gif') { // note: Meteotriviglio icons do not have the wind_{sky}.gif icons, only wind.gif $curicon = 'wind_'.$tCCicon.'.jpg'; if(strpos($VCimage,'-night') !==false) { $curicon = 'n'.$curicon; } $Status .= "\n"; } if(isset($VCpreciptype) and is_array($VCpreciptype)) { $pTypes = array('junk','ice','freezingrain','snow','rain'); $pIcons = array('n/a','mix','fzra','sn','ra'); foreach($pTypes as $k => $type) { if(in_array($type,$VCpreciptype) !== false) { $curicon = $pIcons[$k]; $Status .= "\n"; break; } } if(strpos($VCimage,'-night') !== false) { $curicon = 'n'.$curicon; } $curicon .= '.jpg'; } if($iconType <> '.jpg') { $curicon = preg_replace('|\.jpg|',$iconType,$curicon); } $Status .= "\n"; return("\"$VCcondtext\""); } // ------------------------------------------------------------------------------------------- function VC_prepareJSON($input) { global $Status; //This will convert ASCII/ISO-8859-1 to UTF-8. //Be careful with the third parameter (encoding detect list), because //if set wrong, some input encodings will get garbled (including UTF-8!) list($isUTF8,$offset,$msg) = VC_check_utf8($input); if(!$isUTF8) { $Status .= "\n"; $str = utf8_encode($input); list($isUTF8,$offset,$msg) = VC_check_utf8($str); $Status .= "\n"; } else { $Status .= "\n"; $str = $input; } //Remove UTF-8 BOM if present, json_decode() does not like it. if(substr($str, 0, 3) == pack("CCC", 0xEF, 0xBB, 0xBF)) $str = substr($str, 3); return $str; } // ------------------------------------------------------------------------------------------- function VC_check_utf8($str) { // check all the characters for UTF-8 compliance so json_decode() won't choke // Sometimes, an ISO international character slips in the VC text string. $len = strlen($str); for($i = 0; $i < $len; $i++){ $c = ord($str[$i]); if ($c > 128) { if (($c > 247)) return array(false,$i,"c>247 c='$c'"); elseif ($c > 239) $bytes = 4; elseif ($c > 223) $bytes = 3; elseif ($c > 191) $bytes = 2; else return false; if (($i + $bytes) > $len) return array(false,$i,"i+bytes>len bytes=$bytes,len=$len"); while ($bytes > 1) { $i++; $b = ord($str[$i]); if ($b < 128 || $b > 191) return array(false,$i,"128191 b=$b"); $bytes--; } } } return array(true,$i,"Success. Valid UTF-8"); } // end of check_utf8 // ------------------------------------------------------------------------------------------- function VC_decode_JSON_error() { $Status = ''; $Status .= "\n"; return($Status); } // ------------------------------------------------------------------------------------------- function VC_fixup_text($text) { global $Status; // attempt to convert Imperial forecast temperatures to Metric in the text forecast if(preg_match_all('!([-|\d]+)([ º]*F)!s',$text,$m)) { //$newtext = str_replace('ºF','F',$text); $newtext = $text; foreach ($m[1] as $i => $tF) { $tI = $m[2][$i]; $tC = (float)(($tF - 32) / 1.8 ); $tC = round($tC,0); // $newtext = str_replace("{$tF}F","{$tC}C({$tF}F)",$newtext); $newtext = str_replace("{$tF}{$tI}","{$tC}C",$newtext); $Status .= "\n"; } return($newtext); } else { return($text); // no changes } } function VC_loadLangDefaults () { global $VClanguages, $VClangCharsets; /* en - [DEFAULT] English ar - Arabic az - Azerbaijani be - Belarusian bg - Bulgarian bs - Bosnian ca - Catalan cz - Czech da - Danish de - German fi - Finnish fr - French el - Greek et - Estonian hr - Croation hu - Hungarian id - Indonesian it - Italian is - Icelandic kw - Cornish lt - Lithuanian nb - Norwegian Bokmål nl - Dutch pl - Polish pt - Portuguese ro - Romanian ru - Russian sk - Slovak sl - Slovenian sr - Serbian sv - Swedish tr - Turkish uk - Ukrainian */ $VClanguages = array( // our template language codes v.s. lang:LL codes for JSON 'af' => 'en', 'bg' => 'bg', 'cs' => 'cs', 'ct' => 'ca', 'dk' => 'da', 'nl' => 'nl', 'en' => 'en', 'fi' => 'fi', 'fr' => 'fr', 'de' => 'de', 'el' => 'el', 'ga' => 'en', 'it' => 'it', 'he' => 'he', 'hu' => 'hu', 'no' => 'nb', 'pl' => 'pl', 'pt' => 'pt', 'ro' => 'ro', 'es' => 'es', 'se' => 'sv', 'si' => 'sl', 'sk' => 'sk', 'sr' => 'sr', ); $VClangCharsets = array( 'bg' => 'ISO-8859-5', 'cs' => 'ISO-8859-2', 'el' => 'ISO-8859-7', 'he' => 'UTF-8', 'hu' => 'ISO-8859-2', 'ro' => 'ISO-8859-2', 'pl' => 'ISO-8859-2', 'si' => 'ISO-8859-2', 'sk' => 'Windows-1250', 'sr' => 'Windows-1250', 'ru' => 'ISO-8859-5', ); } // end loadLangDefaults function VC_loadTranslate ($lang) { global $Status; /* Note: We packed up the translation array as it is a mix of various character set types and editing the raw text can easily change the character presentation. The TRANTABLE was created by using $transSerial = serialize($transArray); $b64 = base64_encode($transSerial); print "\n"; $tArr = str_split($b64,72); print "define('TRANTABLE',\n'"; $tStr = ''; foreach($tArr as $rec) { $tStr .= $rec."\n"; } $tStr = trim($tStr); print $tStr; print "'); // end of TRANTABLE encoded\n"; and that result included here. It will reconstitute with unserialize(base64_decode(TRANTABLE)) to look like: ... 'dk' => array ( 'charset' => 'ISO-8859-1', 'Sunday' => 'Søndag', 'Monday' => 'Mandag', 'Tuesday' => 'Tirsdag', 'Wednesday' => 'Onsdag', 'Thursday' => 'Torsdag', 'Friday' => 'Fredag', 'Saturday' => 'Lørdag', 'Sunday night' => 'Søndag nat', 'Monday night' => 'Mandag nat', 'Tuesday night' => 'Tirsdag nat', 'Wednesday night' => 'Onsdag nat', 'Thursday night' => 'Torsdag nat', 'Friday night' => 'Fredag nat', 'Saturday night' => 'Lørdag nat', 'Today' => 'I dag', 'Tonight' => 'I nat', 'This afternoon' => 'I eftermiddag', 'Rest of tonight' => 'Resten af natten', ), // end dk ... and the array for the chosen language will be returned, or the English version if the language is not in the array. */ if(!file_exists("VC-forecast-lang.php")) { print "

Warning: VC-forecast-lang.php translation file was not found. It is required"; print " to be in the same directory as VC-forecast.php.

\n"; exit; } include_once("VC-forecast-lang.php"); $default = array( 'charset' => 'ISO-8859-1', 'Sunday' => 'Sunday', 'Monday' => 'Monday', 'Tuesday' => 'Tuesday', 'Wednesday' => 'Wednesday', 'Thursday' => 'Thursday', 'Friday' => 'Friday', 'Saturday' => 'Saturday', 'Sunday night' => 'Sunday night', 'Monday night' => 'Monday night', 'Tuesday night' => 'Tuesday night', 'Wednesday night' => 'Wednesday night', 'Thursday night' => 'Thursday night', 'Friday night' => 'Friday night', 'Saturday night' => 'Saturday night', 'Today' => 'Today', 'Tonight' => 'Tonight', 'This afternoon' => 'This afternoon', 'Rest of tonight' => 'Rest of tonight', 'High:' => 'High:', 'Low:' => 'Low:', 'Updated:' => 'Updated:', 'Visualcrossing Forecast for:' => 'Visualcrossing Forecast for:', 'NESW' => 'NESW', // cardinal wind directions 'Wind' => 'Wind', 'UV index' => 'UV Index', 'Chance of precipitation' => 'Chance of precipitation', 'mph' => 'mph', 'kph' => 'km/h', 'mps' => 'm/s', 'Temperature' => 'Temperature', 'Barometer' => 'Barometer', 'Dew Point' => 'Dew Point', 'Humidity' => 'Humidity', 'Visibility' => 'Visibility', 'Wind chill' => 'Wind chill', 'Heat index' => 'Heat index', 'Humidex' => 'Humidex', 'Sunrise' => 'Sunrise', 'Sunset' => 'Sunset', 'Currently' => 'Currently', 'rain' => 'rain', 'snow' => 'snow', 'sleet' => 'sleet', 'Weather conditions at 999 from forecast point.' => 'Weather conditions at 999 from forecast point.', 'Daily Forecast' => 'Daily Forecast', 'Hourly Forecast' => 'Hourly Forecast', 'Meteogram' => 'Meteogram', ); $t = unserialize(base64_decode(TRANTABLE)); if(isset($t[$lang])) { $Status .= "\n"; return($t[$lang]); } else { $Status .= "\n"; return($default); } } // ------------------------------------------------------------------ // convert degrees into wind direction abbreviation function VC_WindDir ($degrees) { // figure out a text value for compass direction // Given the wind direction, return the text label // for that value. 16 point compass $winddir = $degrees; if ($winddir == "n/a") { return($winddir); } if (!isset($winddir)) { return "---"; } if (!is_numeric($winddir)) { return($winddir); } $windlabel = array ("N","NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW","SW", "WSW", "W", "WNW", "NW", "NNW"); $dir = $windlabel[ (integer)fmod((($winddir + 11) / 22.5),16) ]; return($dir); } // end function VC_WindDir // ------------------------------------------------------------------ function VC_WindDirTrans($inwdir) { global $tranTab, $Status; $wdirs = $tranTab['NESW']; // default directions $tstr = $inwdir; $Status .= "\n"; return($tstr); } function VC_round($item,$dp) { $t = round($item,$dp); if ($t == '-0') { $t = 0; } return ($t); } function VC_sources ($sArray) { $lookupSources = array( 'cmc' => 'The USA NCEP’s Canadian Meteorological Center ensemble model|http://nomads.ncep.noaa.gov/txt_descriptions/CMCENS_doc.shtml', 'darksky' => 'Dark Sky’s own hyperlocal precipitation forecasting system, backed by radar data from the USA NOAA’s NEXRAD system, available in the USA, and the UK Met Office’s NIMROD system, available in the UK and Ireland.|https://darksky.net/', 'ecpa' => 'Environment and Climate Change Canada’s Public Alert system|https://weather.gc.ca/warnings/index_e.html', 'gfs' => 'The USA NOAA’s Global Forecast System|http://en.wikipedia.org/wiki/Global_Forecast_System', 'hrrr' => 'The USA NOAA’s High-Resolution Rapid Refresh Model|https://rapidrefresh.noaa.gov/hrrr/', 'icon' => 'The German Meteorological Office’s icosahedral nonhydrostatic|https://www.dwd.de/EN/research/weatherforecasting/num_modelling/01_num_weather_prediction_modells/icon_description.html', 'isd' => 'The USA NOAA’s Integrated Surface Database|https://www.ncdc.noaa.gov/isd', 'madis' => 'The USA NOAA/ESRL’s Meteorological Assimilation Data Ingest System|https://madis.noaa.gov/', 'meteoalarm' => 'EUMETNET’s Meteoalarm weather alerting system|https://meteoalarm.eu/', 'nam' => 'The USA NOAA’s North American Mesoscale Model|http://en.wikipedia.org/wiki/North_American_Mesoscale_Model', 'nwspa' => 'The USA NOAA’s Public Alert system|https://alerts.weather.gov/', 'sref' => 'The USA NOAA/NCEP’s Short-Range Ensemble Forecast|https://www.emc.ncep.noaa.gov/mmb/SREF/SREF.html', ); $outStr = ''; foreach ($sArray as $source) { if(isset($lookupSources[$source])) { list($title,$url) = explode('|',$lookupSources[$source]); if(strlen($outStr) > 1) {$outStr .= ', ';} $outStr .= "".strtoupper($source)."\n"; } } return ($outStr); } function VC_octets ($coverage) { global $Status; $octets = round($coverage*100 / 12.5,1); $Status .= "\n"; return('skc'); } elseif ($octets < 3.0) { $Status .= " clouds=few -->\n"; return('few'); } elseif ($octets < 5.0) { $Status .= " clouds=sct -->\n"; return('sct'); } elseif ($octets < 8.0) { $Status .= " clouds=bkn -->\n"; return('bkn'); } else { $Status .= " clouds=ovc -->\n"; return('ovc'); } } function VC_conv_baro($hPa) { # even 'us' imperial returns pressure in hPa so we need to convert global $showUnitsAs; if($showUnitsAs == 'us') { $t = (float)$hPa * 0.02952998751; return(sprintf("%01.2f",$t)); } else { return( sprintf("%01.1f",$hPa) ); } } function VC_gen_hourforecast($FCpart) { global $doDebug,$Status,$showTempsAs,$tranTab,$windUnit,$Units,$showUnitsAs; /* $FCpart = { "time": 1548018000, "summary": "Mostly Cloudy", "icon": "partly-cloudy-day", "precipIntensity": 0.1422, "precipProbability": 0.29, "precipType": "rain", "temperature": 14.91, "apparentTemperature": 14.91, "dewPoint": 11.49, "humidity": 0.8, "pressure": 1017.89, "windSpeed": 10.8, "windGust": 24.54, "windBearing": 226, "cloudCover": 0.88, "uvIndex": 2, "visibility": 14.11, "ozone": 289.95 } */ $VCH = array(); //$newIcon = ''; if($showUnitsAs == 'us' or strpos($timeFormat,'g') !== false) { $t = explode(' ',date('g:ia n/j l',$FCpart['time'])); } else { $t = explode(' ',date('H:i j/n l',$FCpart['time'])); } $newIcon = ''.$t[0].'
'.$tranTab[$t[2]]."

\n"; $cloudcover = $FCpart['cloudCover']; if(isset($FCpart['precipProbability'])) { $pop = round($FCpart['precipProbability'],1)*100; } else { $pop = 0; } $temp = explode('.',$FCpart['summary'].'.'); // split as sentences (sort of). $condition = trim($temp[0]); // take first one as summary. $icon = $FCpart['icon']; $newIcon .= "
" . VC_img_replace( $icon,$condition,$pop,$cloudcover) . "
" . $condition; $VCH['icon'] = $newIcon; $VCH['temp'] = ''.VC_round($FCpart['temperature'],0)."$showTempsAs"; $VCH['UV'] = 'UV: '.$FCpart['uvIndex'].""; $tWdir = VC_WindDir(round($FCpart['windBearing'],0)); $VCH['wind'] = $tranTab['Wind']." ".VC_WindDirTrans($tWdir); $VCH['wind'] .= " ". round($FCpart['windSpeed'],0)."->".round($FCpart['windGust'],0) . " $windUnit\n"; if(isset($FCpart['precipType'])) { $preciptype = $FCpart['precipType']; } else { $preciptype = ''; } $tstr = ''; if($pop > 0) { if(!empty($preciptype)) { $t = explode(',',$preciptype.','); foreach ($t as $k => $ptype) { if(!empty($ptype)) {$tstr .= $tranTab[$ptype].',';} } if(isset($FCpart['precipAccumulation'])) { $amt = $FCpart['precipAccumulation']; if($showUnitsAs == 'us') { $U = 'in'; } else { $U = 'cm'; } $accum = ' ' . sprintf("%01.2f",$amt)."$U"; } else { $accum = ''; } if(strlen($tstr)>0) { $tstr = substr($tstr,0,strlen($tstr)-1). $accum; } else { $tstr = ' '; } } } $VCH['precip'] = "$tstr"; //$newIcon .= "\n"; return($VCH); } function setup_tabber() { ?>