View Source

The actual code behind this page. No minification. No transpilation. What you see is what runs.

↓ Download PHP edition
weather.php 138 lines
<?php
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 &middot; Observed <?= htmlspecialchars($weather['time']) ?></p>
 
<?php endif ?>
<?php require_once __DIR__ . '/includes/footer.php'; ?>