View Source
The actual code behind this page. No minification. No transpilation. What you see is what runs.
|
| require_once __DIR__ . '/includes/config.php'; |
| $pageTitle = 'Weather — dispelled.ca'; |
| $currentPage = 'weather'; |
| $WMO = [ |
| 0 => ['label' => 'Clear sky', 'icon' => '☀️'], |
| 1 => ['label' => 'Mainly clear', 'icon' => '🌤️'], |
| 2 => ['label' => 'Partly cloudy', 'icon' => '⛅'], |
| 3 => ['label' => 'Overcast', 'icon' => '☁️'], |
| 45 => ['label' => 'Foggy', 'icon' => '🌫️'], |
| 48 => ['label' => 'Icy fog', 'icon' => '🌫️'], |
| 51 => ['label' => 'Light drizzle', 'icon' => '🌦️'], |
| 53 => ['label' => 'Drizzle', 'icon' => '🌦️'], |
| 55 => ['label' => 'Heavy drizzle', 'icon' => '🌧️'], |
| 61 => ['label' => 'Light rain', 'icon' => '🌧️'], |
| 63 => ['label' => 'Rain', 'icon' => '🌧️'], |
| 65 => ['label' => 'Heavy rain', 'icon' => '🌧️'], |
| 71 => ['label' => 'Light snow', 'icon' => '🌨️'], |
| 73 => ['label' => 'Snow', 'icon' => '❄️'], |
| 75 => ['label' => 'Heavy snow', 'icon' => '❄️'], |
| 77 => ['label' => 'Snow grains', 'icon' => '🌨️'], |
| 80 => ['label' => 'Light showers', 'icon' => '🌦️'], |
| 81 => ['label' => 'Showers', 'icon' => '🌧️'], |
| 82 => ['label' => 'Heavy showers', 'icon' => '🌧️'], |
| 85 => ['label' => 'Snow showers', 'icon' => '🌨️'], |
| 86 => ['label' => 'Heavy snow showers', 'icon' => '❄️'], |
| 95 => ['label' => 'Thunderstorm', 'icon' => '⛈️'], |
| 96 => ['label' => 'Thunderstorm w/ hail', 'icon' => '⛈️'], |
| 99 => ['label' => 'Thunderstorm w/ hvy hail', 'icon' => '⛈️'], |
| ]; |
| $windDirs = ['N','NE','E','SE','S','SW','W','NW']; |
| $wmo = fn($c) => $WMO[$c] ?? ['label' => 'Unknown', 'icon' => '🌡️']; |
| $windDir = fn($d) => $windDirs[round($d / 45) % 8]; |
| $cacheFile = sys_get_temp_dir() . '/dispelled_weather_php.json'; |
| $weather = null; |
| if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < 600) { |
| $weather = json_decode(file_get_contents($cacheFile), true); |
| } |
| if (!$weather) { |
| $p = http_build_query([ |
| 'latitude' => 49.94, |
| 'longitude' => -105.96, |
| 'current' => 'temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,wind_direction_10m', |
| 'daily' => 'weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max', |
| 'temperature_unit' => 'celsius', |
| 'wind_speed_unit' => 'kmh', |
| 'timezone' => 'America/Regina', |
| 'forecast_days' => '7', |
| ]); |
| $ctx = stream_context_create(['http' => ['timeout' => 8]]); |
| $raw = @file_get_contents("https://api.open-meteo.com/v1/forecast?{$p}", false, $ctx); |
| if ($raw) { |
| $j = json_decode($raw, true); |
| $c = $j['current']; |
| $d = $j['daily']; |
| $cw = $wmo($c['weather_code']); |
| $forecast = []; |
| foreach ($d['time'] as $i => $date) { |
| $fw = $wmo($d['weather_code'][$i]); |
| $forecast[] = [ |
| 'date' => $date, |
| 'high' => (int) round($d['temperature_2m_max'][$i]), |
| 'low' => (int) round($d['temperature_2m_min'][$i]), |
| 'label' => $fw['label'], |
| 'icon' => $fw['icon'], |
| 'precip' => $d['precipitation_probability_max'][$i] ?? 0, |
| ]; |
| } |
| $weather = [ |
| 'location' => 'Ardill, SK', |
| 'temp' => (int) round($c['temperature_2m']), |
| 'feelsLike' => (int) round($c['apparent_temperature']), |
| 'humidity' => $c['relative_humidity_2m'], |
| 'windSpeed' => (int) round($c['wind_speed_10m']), |
| 'windDir' => $windDir($c['wind_direction_10m']), |
| 'label' => $cw['label'], |
| 'icon' => $cw['icon'], |
| 'time' => $c['time'], |
| 'forecast' => $forecast, |
| ]; |
| file_put_contents($cacheFile, json_encode($weather)); |
| } |
| } |
| $days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; |
| require_once __DIR__ . '/includes/header.php'; |
| ?> |
| <h1 class="page-title">Weather</h1> |
| <?php if (!$weather): ?> |
| <p style="color:var(--primary-light);font-family:monospace">Could not load weather data.</p> |
| <?php else: ?> |
| <div class="weather-current"> |
| <div class="weather-main"> |
| <p class="weather-location"><?= htmlspecialchars($weather['location']) ?></p> |
| <div class="weather-temp-row"> |
| <span class="weather-temp"><?= $weather['temp'] ?>°</span> |
| <span class="weather-icon-lg"><?= $weather['icon'] ?></span> |
| </div> |
| <p class="weather-condition"><?= htmlspecialchars($weather['label']) ?></p> |
| </div> |
| <div class="weather-details"> |
| <p>Feels like <strong><?= $weather['feelsLike'] ?>°C</strong></p> |
| <p>Humidity <strong><?= $weather['humidity'] ?>%</strong></p> |
| <p>Wind <strong><?= $weather['windSpeed'] ?> km/h <?= $weather['windDir'] ?></strong></p> |
| </div> |
| </div> |
| <h2 class="section-subtitle">7-Day Forecast</h2> |
| <div class="weather-forecast"> |
| <?php foreach ($weather['forecast'] as $day): |
| $ts = strtotime($day['date'] . 'T12:00:00'); |
| $dow = $days[(int) date('w', $ts)]; |
| ?> |
| <div class="forecast-day"> |
| <p class="forecast-dow"><?= $dow ?></p> |
| <p class="forecast-icon"><?= $day['icon'] ?></p> |
| <p class="forecast-high"><?= $day['high'] ?>°</p> |
| <p class="forecast-low"><?= $day['low'] ?>°</p> |
| <?php if ($day['precip'] > 0): ?> |
| <p class="forecast-precip"><?= $day['precip'] ?>%</p> |
| <?php endif ?> |
| </div> |
| <?php endforeach ?> |
| </div> |
| <p class="data-attr">Data via Open-Meteo · Observed <?= htmlspecialchars($weather['time']) ?></p> |
| <?php endif ?> |
| <?php require_once __DIR__ . '/includes/footer.php'; ?> |
dispelled