| [ PHPXref.com ] | [ Generated: Sun Jul 20 19:57:02 2008 ] | [ PHP Timeclock 1.02 ] |
| [ Index ] [ Variables ] [ Functions ] [ Classes ] [ Constants ] [ Statistics ] | ||
[Summary view] [Print] [Text view]
1 <?php 2 3 //////////////////////////////////////////// 4 /* Copied from PHP Weather version 1.62. */ 5 /* Line 109 was added for php timeclock. */ 6 /* Line 110 was edited for php timeclock. */ 7 //////////////////////////////////////////// 8 9 /* Unsets old language variables and loads new ones. */ 10 11 if (isset($strings)) { 12 /* The strings array is loaded - assume the same for the rest. */ 13 unset($strings); 14 unset($wind_dir_text_short_array); 15 unset($wind_dir_text_array); 16 unset($weather_array); 17 unset($cloud_condition_array); 18 } 19 20 /* Load the new strings */ 21 22 $wind_dir_text_short_array = array( 23 'N', 24 'N/NE', 25 'NE', 26 'E/NE', 27 'E', 28 'E/SE', 29 'SE', 30 'S/SE', 31 'S', 32 'S/SW', 33 'SW', 34 'W/SW', 35 'W', 36 'W/NW', 37 'NW', 38 'N/NW', 39 'N'); 40 41 $cloud_condition_array = array( 42 'SKC' => 'Clear', 43 'CLR' => 'Clear', 44 'VV' => 'Vertical Visibility', 45 'FEW' => 'Partly Cloudy', 46 'SCT' => 'Scattered Clouds', 47 'BKN' => 'Partly Cloudy', 48 'OVC' => 'Overcast'); 49 50 /* Offset in hours to add to the time of a report. If all your times 51 * are 2 hours off, then set this to -2. */ 52 $weather_offset = 0; 53 54 /* Make a connection to the MySQL database: */ 55 if (mysql_pconnect($db_hostname, $db_username, $db_password)) { 56 mysql_select_db($db_name); 57 } else { 58 echo "<p>Unable to connect to MySQL database!</p>"; 59 } 60 61 function store_speed($value, $windunit, &$meterspersec, &$knots, &$milesperhour) { 62 /* 63 * Helper function to convert and store speed based on unit. 64 * &$meterspersec, &$knots and &$milesperhour are passed on 65 * reference 66 */ 67 if ($windunit == 'KT') { 68 /* The windspeed measured in knots: */ 69 $knots = number_format($value); 70 /* The windspeed measured in meters per second, rounded to one 71 * decimal place: */ 72 $meterspersec = number_format($value * 0.51444, 1); 73 /* The windspeed measured in miles per hour, rounded to one 74 * decimal place: */ 75 $milesperhour = number_format($value * 1.1507695060844667, 1); 76 } elseif ($windunit == 'MPS') { 77 /* The windspeed measured in meters per second: */ 78 $meterspersec = number_format($value); 79 /* The windspeed measured in knots, rounded to one decimal 80 * place: */ 81 $knots = number_format($value / 0.51444, 1); 82 /* The windspeed measured in miles per hour, rounded to one 83 * decimal place: */ 84 $milesperhour = number_format($value / 0.51444 * 1.1507695060844667, 1); 85 } elseif ($windunit == 'KMH') { 86 /* The windspeed measured in kilometers per hour: */ 87 $meterspersec = number_format($value * 1000 / 3600, 1); 88 $knots = number_format($value * 1000 / 3600 / 0.51444, 1); 89 /* The windspeed measured in miles per hour, rounded to one 90 * decimal place: */ 91 $milesperhour = number_format($knots * 1.1507695060844667, 1); 92 } 93 } 94 95 function get_metar($station, $always_use_cache = 0) { 96 /* 97 * Looks in the database, and fetches a new metar is nesceary. If 98 * $always_use_cache is true, then it ignores the timestamp of the 99 * METAR and just returns it. 100 * 101 * You should pass a ICAO station identifier, eg. 'EKYT' for 102 * Aalborg, Denmark. 103 */ 104 105 global $conn, $dbmMetar, $dbmTimestamp; 106 107 $query = "SELECT metar, UNIX_TIMESTAMP(timestamp) FROM ".$db_prefix."metars WHERE station = '$station'"; 108 $result = mysql_query($query); 109 @$metar_rows = mysql_num_rows($result); /* this suppresses a php error message if the metars db has not yet been created. */ 110 if (isset($metar_rows)) { /* found station */ 111 list($metar, $timestamp) = mysql_fetch_row($result); 112 } 113 114 if (isset($metar)) { /* found station */ 115 if ($always_use_cache || $timestamp > time() - 3600) { 116 /* We have asked explicit for a cached metar, or the metar is 117 * still fresh. */ 118 return $metar; 119 } else { 120 /* We looked in the cache, but the metar was too old. */ 121 return fetch_metar($station, 0); 122 } 123 } else { 124 /* The station is new - we fetch a new METAR */ 125 return fetch_metar($station, 1); 126 } 127 } 128 129 function fetch_metar($station, $new) { 130 /* 131 * Fetches a new METER from weather.noaa.gov. If the $new variable 132 * is true, the metar is inserted, else it will replace the old 133 * metar. The new METAR is returned. 134 */ 135 global $conn, $dbmMetar, $dbmTimestamp; 136 137 $metar = ''; 138 $station = strtoupper($station); 139 140 /* We use the @ notation, because it might fail. */ 141 $file = @file('http://weather.noaa.gov/pub/data/' . 142 "observations/metar/stations/$station.TXT"); 143 144 /* Here we test to see if we actually got a METAR. */ 145 if (is_array($file)) { 146 $date = trim($file[0]); 147 $metar = trim($file[1]); 148 for ($i = 2; $i < count($file); $i++) { 149 $metar .= ' ' . trim($file[i]); 150 } 151 152 /* The date is in the form 2000/10/09 14:50 UTC. This seperates 153 the different parts. */ 154 $date_parts = explode(':', strtr($date, '/ ', '::')); 155 $date_unixtime = gmmktime($date_parts[3], $date_parts[4], 156 0, $date_parts[1], $date_parts[2], 157 $date_parts[0]); 158 159 if (!ereg('[0-9]{6}Z', $metar)) { 160 /* Some reports dont even have a time-part, so we insert the 161 * current time. This might not be the time of the report, but 162 * it was broken anyway :-) */ 163 $metar = gmdate('dHi', $date_unixtime) . 'Z ' . $metar; 164 } 165 166 if ($date_unixtime < (time() - 3300)) { 167 /* The timestamp in the metar is more than 55 minutes old. We 168 * adjust the timestamp, so that we won't try to fetch a new 169 * METAR within the next 5 minutes. After 5 minutes, the 170 * timestamp will again be more than 1 hour old. */ 171 $date_unixtime = time() - 3300; 172 } 173 174 } else { 175 /* If we end up here, it means that there was no file, we then set 176 * the metar to and empty string. We set the date to time() - 3000 177 * to give the server 10 minutes of peace. If the file is 178 * unavailable, we don't want to stress the server. */ 179 $metar = ''; 180 $date_unixtime = time() - 3000; 181 } 182 183 /* It might seam strange, that we make a local date, but MySQL 184 * expects a local when we insert the METAR. */ 185 $date = date('Y/m/d H:i', $date_unixtime); 186 187 if ($new) { 188 /* Insert the new record */ 189 $query = "INSERT INTO ".$db_prefix."metars SET station = '$station', " . 190 "metar = '$metar', timestamp = '$date'"; 191 } else { 192 /* Update the old record */ 193 $query = "UPDATE ".$db_prefix."metars SET metar = '$metar', " . 194 "timestamp = '$date' WHERE station = '$station'"; 195 } 196 mysql_query($query); 197 198 return $metar; 199 } 200 201 function process_metar($metar) { 202 /* This function decodes a raw METAR. The result is an associative 203 * array with entries like 'temp_c', 'visibility_miles' etc. */ 204 205 global $strings, $wind_dir_text_short_array, $wind_dir_text_array, 206 $cloud_condition_array, $weather_array, $weather_offset; 207 208 $temp_visibility_miles = ''; 209 $cloud_layers = 0; 210 $decoded_metar['remarks'] = ''; 211 $decoded_metar['weather'] = ''; 212 213 $cloud_coverage = array('SKC' => '0', 214 'CLR' => '0', 215 'VV' => '8/8', 216 'FEW' => '1/8 - 2/8', 217 'SCT' => '3/8 - 4/8', 218 'BKN' => '5/8 - 7/8', 219 'OVC' => '8/8'); 220 221 $decoded_metar['metar'] = $metar; 222 $parts = split('[ ]+', $metar); 223 $num_parts = count($parts); 224 for ($i = 0; $i < $num_parts; $i++) { 225 $part = $parts[$i]; 226 227 if (ereg('RMK|TEMPO|BECMG', $part)) { 228 /* The rest of the METAR is either a remark or temporary 229 * information. We skip the rest of the METAR. */ 230 $decoded_metar['remarks'] .= ' ' . $part; 231 break; 232 } elseif ($part == 'METAR') { 233 /* 234 * Type of Report: METAR 235 */ 236 $decoded_metar['type'] = 'METAR'; 237 } elseif ($part == 'SPECI') { 238 /* 239 * Type of Report: SPECI 240 */ 241 $decoded_metar['type'] = 'SPECI'; 242 } elseif (ereg('^[A-Z]{4}$', $part) && ! isset($decoded_metar['station'])) { 243 /* 244 * Station Identifier 245 */ 246 $decoded_metar['station'] = $part; 247 } elseif (ereg('([0-9]{2})([0-9]{2})([0-9]{2})Z', $part, $regs)) { 248 /* 249 * Date and Time of Report 250 * We return a standard Unix UTC/GMT timestamp suitable for 251 * gmdate() 252 */ 253 $decoded_metar['time'] = gmmktime($regs[2] + $weather_offset, $regs[3], 0, 254 gmdate('m'), $regs[1], gmdate('Y')); 255 } elseif (ereg('(AUTO|COR|RTD|CC[A-Z]|RR[A-Z])', $part, $regs)) { 256 /* 257 * Report Modifier: AUTO, COR, CCx or RRx 258 */ 259 $decoded_metar['report_mod'] = $regs[1]; 260 } elseif (ereg('([0-9]{3}|VRB)([0-9]{2,3}).*(KT|MPS|KMH)', $part, $regs)) { 261 /* Wind Group */ 262 $windunit = $regs[3]; /* do ereg in two parts to retrieve unit first */ 263 /* now do ereg to get the actual values */ 264 ereg("([0-9]{3}|VRB)([0-9]{2,3})(G([0-9]{2,3})?$windunit)", $part, $regs); 265 if ($regs[1] == 'VRB') { 266 $decoded_metar['wind_deg'] = $strings['wind_vrb_long']; 267 $decoded_metar['wind_dir_text'] = $strings['wind_vrb_long']; 268 $decoded_metar['wind_dir_text_short'] = $strings['wind_vrb_short']; 269 } else { 270 $decoded_metar['wind_deg'] = $regs[1]; 271 $decoded_metar['wind_dir_text'] = 272 $wind_dir_text_array[intval(round($regs[1]/22.5))]; 273 $decoded_metar['wind_dir_text_short'] = 274 $wind_dir_text_short_array[intval(round($regs[1]/22.5))]; 275 } 276 store_speed($regs[2], 277 $windunit, 278 $decoded_metar['wind_meters_per_second'], 279 $decoded_metar['wind_knots'], 280 $decoded_metar['wind_miles_per_hour']); 281 282 if (isset($regs[4])) { 283 /* We have a report with information about the gust. First we 284 have the gust measured in knots: */ 285 store_speed($regs[4],$windunit, 286 $decoded_metar['wind_gust_meters_per_second'], 287 $decoded_metar['wind_gust_knots'], 288 $decoded_metar['wind_gust_miles_per_hour']); 289 } 290 } elseif (ereg('^([0-9]{3})V([0-9]{3})$', $part, $regs)) { 291 /* 292 * Variable wind-direction 293 */ 294 $decoded_metar['wind_var_beg'] = $regs[1]; 295 $decoded_metar['wind_var_end'] = $regs[2]; 296 } elseif ($part == 9999) { 297 /* A strange value. When you look at other pages you see it 298 interpreted like this (where I use > to signify 'Greater 299 than'): */ 300 $decoded_metar['visibility_miles'] = '>6.2'; 301 $decoded_metar['visibility_km'] = '>10'; 302 } elseif(ereg('^([0-9]{4})$', $part, $regs)) { 303 /* 304 * Visibility in meters (4 digits only) 305 */ 306 $decoded_metar['visibility_km'] = number_format($regs[1]/1000, 1); 307 $decoded_metar['visibility_miles'] = 308 number_format( ($regs[1]/1000) / 1.609344, 1); 309 } elseif (ereg('^[0-9]$', $part)) { 310 /* 311 * Temp Visibility Group, single digit followed by space 312 */ 313 $temp_visibility_miles = $part; 314 } elseif (ereg('^M?(([0-9]?)[ ]?([0-9])(/?)([0-9]*))SM$', 315 $temp_visibility_miles . ' ' . 316 $parts[$i], $regs)) { 317 /* 318 * Visibility Group 319 */ 320 if ($regs[4] == '/') { 321 $vis_miles = $regs[2] + $regs[3]/$regs[5]; 322 } else { 323 $vis_miles = $regs[1]; 324 } 325 if ($regs[0][0] == 'M') { 326 /* The visibility measured in miles, prefixed with < to 327 indicate 'Less than' */ 328 $decoded_metar['visibility_miles'] = 329 '<' . number_format($vis_miles, 1); 330 /* The visibility measured in kilometers. The value is rounded 331 to one decimal place, prefixed with < to indicate 'Less 332 than' */ 333 $decoded_metar['visibility_km'] = 334 '<' . number_format($vis_miles * 1.609344, 1); 335 } else { 336 /* The visibility measured in mile.s */ 337 $decoded_metar['visibility_miles'] = number_format($vis_miles, 1); 338 /* The visibility measured in kilometers, rounded to one 339 decimal place. */ 340 $decoded_metar['visibility_km'] = 341 number_format($vis_miles * 1.609344, 1); 342 } 343 } elseif ($part == 'CAVOK') { 344 /* CAVOK: Used when the visibility is greather than 10 345 kilometers, the lowest cloud-base is at 5000 feet and there 346 is no significant weather. */ 347 $decoded_metar['visibility_km'] = '>10'; 348 $decoded_metar['visibility_miles'] = '>6.2'; 349 $decoded_metar['cloud_layer1_condition'] = 'CAVOK'; 350 } elseif (ereg('^R([0-9][0-9][RLC]?)/([MP]?[0-9]{4})V?(P?[0-9]{4})?F?T?$', $part, $regs)) { 351 $decoded_metar['runway_nr'] = $regs[1]; 352 if ($regs[3]) { 353 /* We have both min and max visibility. */ 354 $prefix = ''; 355 if ($regs[2][0] == 'M') { 356 /* Less than. */ 357 $prefix = '<'; 358 $regs[2] = substr($regs[2], 1); 359 } 360 $decoded_metar['runway_vis_min_ft'] = $prefix . number_format($regs[2]); 361 $decoded_metar['runway_vis_min_meter'] = $prefix . number_format($regs[2] * 0.3048); 362 363 $prefix = ''; 364 if ($regs[3][0] == 'P') { 365 /* Greather than. */ 366 $prefix = '>'; 367 $regs[3] = substr($regs[3], 1); 368 } 369 $decoded_metar['runway_vis_max_ft'] = $prefix . number_format($regs[3]); 370 $decoded_metar['runway_vis_max_meter'] = $prefix . number_format($regs[3] * 0.3048); 371 372 } else { 373 /* We only have a single visibility. */ 374 $prefix = ''; 375 if ($regs[2][0] == 'M') { 376 $prefix = '<'; 377 $regs[2] = substr($regs[2], 1); 378 } elseif ($regs[2][0] == 'P') { 379 $prefix = '>'; 380 $regs[2] = substr($regs[2], 1); 381 } 382 $decoded_metar['runway_vis_ft'] = $prefix . number_format($regs[2]); 383 $decoded_metar['runway_vis_meter'] = $prefix . number_format($regs[2] * 0.3048); 384 } 385 } elseif (ereg('^(-|\+|VC)?(TS|SH|FZ|BL|DR|MI|BC|PR|RA|DZ|SN|SG|GR|' . 386 'GS|PE|IC|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$', 387 $part)) { 388 /* 389 * Current weather-group 390 */ 391 if ($part[0] == '-') { 392 /* A light phenomenon */ 393 $decoded_metar['weather'] .= $strings['light']; 394 $part = substr($part, 1); 395 } elseif ($part[0] == '+') { 396 /* A heavy phenomenon */ 397 $decoded_metar['weather'] .= $strings['heavy']; 398 $part = substr($part, 1); 399 } elseif ($part[0].$part[1] == 'VC') { 400 /* Proximity Qualifier */ 401 $decoded_metar['weather'] .= $strings['nearby']; 402 $part = substr($part, 2); 403 } else { 404 /* no intensity code => moderate phenomenon */ 405 $decoded_metar['weather'] .= $strings['moderate']; 406 } 407 408 while ($bite = substr($part, 0, 2)) { 409 /* Now we take the first two letters and determine what they 410 mean. We append this to the variable so that we gradually 411 build up a phrase. */ 412 $decoded_metar['weather'] .= $weather_array[$bite]; 413 /* Here we chop off the two first letters, so that we can take 414 a new bite at top of the while-loop. */ 415 $part = substr($part, 2); 416 } 417 } elseif (ereg('(SKC|CLR)', $part, $regs)) { 418 /* 419 * Cloud-layer-group. 420 * There can be up to three of these groups, so we store them as 421 * cloud_layer1, cloud_layer2 and cloud_layer3. 422 */ 423 $cloud_layers++; 424 /* Again we have to translate the code-characters to a 425 meaningful string. */ 426 $decoded_metar['cloud_layer'. $cloud_layers.'_condition'] = 427 $cloud_condition_array[$regs[1]]; 428 $decoded_metar['cloud_layer'.$cloud_layers.'_coverage'] = 429 $cloud_coverage[$regs[1]]; 430 } elseif (ereg('^(VV|FEW|SCT|BKN|OVC)([0-9]{3})(CB|TCU)?$', 431 $part, $regs)) { 432 /* We have found (another) a cloud-layer-group. There can be up 433 to three of these groups, so we store them as cloud_layer1, 434 cloud_layer2 and cloud_layer3. */ 435 $cloud_layers++; 436 /* Again we have to translate the code-characters to a 437 meaningful string. */ 438 if ($regs[1] == 'OVC') { 439 $clouds_str_temp = ''; 440 } else { 441 $clouds_str_temp = $strings['clouds']; 442 } 443 if ($regs[3] == 'CB') { 444 /* cumulonimbus (CB) clouds were observed. */ 445 $decoded_metar['cloud_layer'.$cloud_layers.'_condition'] = 446 $cloud_condition_array[$regs[1]] . $strings['clouds_cb']; 447 } elseif ($regs[3] == 'TCU') { 448 /* towering cumulus (TCU) clouds were observed. */ 449 $decoded_metar['cloud_layer'.$cloud_layers.'_condition'] = 450 $cloud_condition_array[$regs[1]] . $strings['clouds_tcu']; 451 } else { 452 $decoded_metar['cloud_layer'.$cloud_layers.'_condition'] = 453 $cloud_condition_array[$regs[1]] . $clouds_str_temp; 454 } 455 $decoded_metar['cloud_layer'.$cloud_layers.'_coverage'] = 456 $cloud_coverage[$regs[1]]; 457 $decoded_metar['cloud_layer'.$cloud_layers.'_altitude_ft'] = 458 $regs[2] *100; 459 $decoded_metar['cloud_layer'.$cloud_layers.'_altitude_m'] = 460 round($regs[2] * 30.48); 461 } elseif (ereg('^(M?[0-9]{2})/(M?[0-9]{2})?$', $part, $regs)) { 462 /* 463 * Temperature/Dew Point Group 464 * The temperature and dew-point measured in Celsius. 465 */ 466 $decoded_metar['temp_c'] = number_format(strtr($regs[1], 'M', '-')); 467 $decoded_metar['dew_c'] = number_format(strtr($regs[2], 'M', '-')); 468 /* The temperature and dew-point measured in Fahrenheit, rounded 469 to the nearest degree. */ 470 $decoded_metar['temp_f'] = round(strtr($regs[1], 'M', '-') * (9/5) + 32); 471 $decoded_metar['dew_f'] = round(strtr($regs[2], 'M', '-') * (9/5) + 32); 472 } elseif(ereg('A([0-9]{4})', $part, $regs)) { 473 /* 474 * Altimeter 475 * The pressure measured in inHg 476 */ 477 $decoded_metar['altimeter_inhg'] = number_format($regs[1]/100, 2); 478 /* The pressure measured in mmHg, hPa and atm */ 479 $decoded_metar['altimeter_mmhg'] = number_format($regs[1] * 0.254, 1); 480 $decoded_metar['altimeter_hpa'] = number_format($regs[1] * 0.33863881578947); 481 $decoded_metar['altimeter_atm'] = number_format($regs[1] * 3.3421052631579e-4, 3); 482 } elseif(ereg('Q([0-9]{4})', $part, $regs)) { 483 /* 484 * Altimeter 485 * This is strange, the specification doesnt say anything about 486 * the Qxxxx-form, but it's in the METARs. 487 */ 488 /* The pressure measured in hPa */ 489 $decoded_metar['altimeter_hpa'] = number_format($regs[1]); 490 /* The pressure measured in mmHg, inHg and atm */ 491 $decoded_metar['altimeter_mmhg'] = number_format($regs[1] * 0.7500616827, 1); 492 $decoded_metar['altimeter_inhg'] = number_format($regs[1] * 0.0295299875, 2); 493 $decoded_metar['altimeter_atm'] = number_format($regs[1] * 9.869232667e-4, 3); 494 } elseif (ereg('^T([0-9]{4})([0-9]{4})', $part, $regs)) { 495 /* 496 * Temperature/Dew Point Group, coded to tenth of degree. 497 * The temperature and dew-point measured in Celsius. 498 */ 499 store_temp($regs[1],$decoded_metar,'temp_c','temp_f'); 500 store_temp($regs[2],$decoded_metar,'dew_c','dew_f'); 501 } elseif (ereg('^T([0-9]{4}$)', $part, $regs)) { 502 store_temp($regs[1],$decoded_metar,'temp_c','temp_f'); 503 } elseif (ereg('^1([0-9]{4}$)', $part, $regs)) { 504 /* 505 * 6 hour maximum temperature Celsius, coded to tenth of degree 506 */ 507 store_temp($regs[1],$decoded_metar,'temp_max6h_c','temp_max6h_f'); 508 } elseif (ereg('^2([0-9]{4}$)', $part, $regs)) { 509 /* 510 * 6 hour minimum temperature Celsius, coded to tenth of degree 511 */ 512 store_temp($regs[1],$decoded_metar,'temp_min6h_c','temp_min6h_f'); 513 } elseif (ereg('^4([0-9]{4})([0-9]{4})$', $part, $regs)) { 514 /* 515 * 24 hour maximum and minimum temperature Celsius, coded to 516 * tenth of degree 517 */ 518 store_temp($regs[1],$decoded_metar,'temp_max24h_c','temp_max24h_f'); 519 store_temp($regs[2],$decoded_metar,'temp_min24h_c','temp_min24h_f'); 520 } elseif(ereg('^P([0-9]{4})', $part, $regs)) { 521 /* 522 * Precipitation during last hour in hundredths of an inch 523 * (store as inches) 524 */ 525 $decoded_metar['precip_in'] = number_format($regs[1]/100, 2); 526 $decoded_metar['precip_mm'] = number_format(