diff --git a/.codex-temp/php-server.err.log b/.codex-temp/php-server.err.log index bd0859b..3f35db5 100644 --- a/.codex-temp/php-server.err.log +++ b/.codex-temp/php-server.err.log @@ -54,3 +54,154 @@ [Sat Apr 4 18:24:44 2026] 127.0.0.1:56614 Accepted [Sat Apr 4 18:25:51 2026] 127.0.0.1:56614 Closed without sending a request; it was probably just an unused speculative preconnection [Sat Apr 4 18:25:51 2026] 127.0.0.1:56614 Closing +[Sat Apr 4 18:38:50 2026] 127.0.0.1:62616 Accepted +[Sat Apr 4 18:39:01 2026] PHP Warning: Undefined variable $monthStartLocal in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1928 +[Sat Apr 4 18:39:01 2026] PHP Warning: Undefined variable $monthEndLocal in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1928 +[Sat Apr 4 18:39:01 2026] PHP Fatal error: Uncaught TypeError: findMonthForecastSolarLongitudeCrossing(): Argument #1 ($rangeStartLocal) must be of type DateTimeImmutable, null given, called in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1927 and defined in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php:488 +Stack trace: +#0 C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php(1927): findMonthForecastSolarLongitudeCrossing(NULL, NULL, 0.0, Object(DateTimeZone)) +#1 {main} + thrown in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 488 +[Sat Apr 4 18:39:01 2026] 127.0.0.1:62616 [200]: GET /wochenvorhersage.php?year=2026&week=14 - Uncaught TypeError: findMonthForecastSolarLongitudeCrossing(): Argument #1 ($rangeStartLocal) must be of type DateTimeImmutable, null given, called in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1927 and defined in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php:488 +Stack trace: +#0 C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php(1927): findMonthForecastSolarLongitudeCrossing(NULL, NULL, 0.0, Object(DateTimeZone)) +#1 {main} + thrown in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 488 +[Sat Apr 4 18:39:01 2026] 127.0.0.1:62616 Closing +[Sat Apr 4 18:39:55 2026] 127.0.0.1:52595 Accepted +[Sat Apr 4 18:40:06 2026] PHP Warning: Undefined variable $monthStartLocal in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1928 +[Sat Apr 4 18:40:06 2026] PHP Warning: Undefined variable $monthEndLocal in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1928 +[Sat Apr 4 18:40:06 2026] PHP Fatal error: Uncaught TypeError: findMonthForecastSolarLongitudeCrossing(): Argument #1 ($rangeStartLocal) must be of type DateTimeImmutable, null given, called in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1927 and defined in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php:488 +Stack trace: +#0 C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php(1927): findMonthForecastSolarLongitudeCrossing(NULL, NULL, 0.0, Object(DateTimeZone)) +#1 {main} + thrown in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 488 +[Sat Apr 4 18:40:06 2026] 127.0.0.1:52595 [200]: GET /wochenvorhersage.php?year=2026&week=14 - Uncaught TypeError: findMonthForecastSolarLongitudeCrossing(): Argument #1 ($rangeStartLocal) must be of type DateTimeImmutable, null given, called in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 1927 and defined in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php:488 +Stack trace: +#0 C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php(1927): findMonthForecastSolarLongitudeCrossing(NULL, NULL, 0.0, Object(DateTimeZone)) +#1 {main} + thrown in C:\Users\ich\source\repos\skyview.astronomiemuseum.de\public\wochenvorhersage.php on line 488 +[Sat Apr 4 18:40:06 2026] 127.0.0.1:52595 Closing +[Sat Apr 4 18:40:06 2026] 127.0.0.1:57969 Accepted +[Sat Apr 4 18:40:06 2026] 127.0.0.1:57969 [200]: GET /css/style.css +[Sat Apr 4 18:40:06 2026] 127.0.0.1:57969 Closing +[Sat Apr 4 18:40:06 2026] 127.0.0.1:53036 Accepted +[Sat Apr 4 18:40:06 2026] 127.0.0.1:53036 [200]: GET /images/star16x16.png +[Sat Apr 4 18:40:06 2026] 127.0.0.1:49569 Accepted +[Sat Apr 4 18:40:06 2026] 127.0.0.1:49569 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 18:40:06 2026] 127.0.0.1:53036 Closing +[Sat Apr 4 18:40:06 2026] 127.0.0.1:49569 Closing +[Sat Apr 4 18:40:06 2026] 127.0.0.1:49178 Accepted +[Sat Apr 4 18:40:07 2026] 127.0.0.1:49178 [200]: GET /favicon.ico +[Sat Apr 4 18:40:07 2026] 127.0.0.1:49178 Closing +[Sat Apr 4 18:40:59 2026] 127.0.0.1:49611 Accepted +[Sat Apr 4 18:41:10 2026] 127.0.0.1:49611 [200]: GET /wochenvorhersage.php?year=2026&week=14 +[Sat Apr 4 18:41:10 2026] 127.0.0.1:49611 Closing +[Sat Apr 4 18:41:10 2026] 127.0.0.1:51173 Accepted +[Sat Apr 4 18:41:21 2026] 127.0.0.1:51173 [200]: GET /wochenvorhersage.php?year=2026&week=14 +[Sat Apr 4 18:41:21 2026] 127.0.0.1:51173 Closing +[Sat Apr 4 18:41:21 2026] 127.0.0.1:58633 Accepted +[Sat Apr 4 18:41:21 2026] 127.0.0.1:51479 Accepted +[Sat Apr 4 18:41:21 2026] 127.0.0.1:58633 [200]: GET /css/style.css +[Sat Apr 4 18:41:21 2026] 127.0.0.1:51479 [200]: GET /js/astronomy.browser.min.js +[Sat Apr 4 18:41:21 2026] 127.0.0.1:58633 Closing +[Sat Apr 4 18:41:21 2026] 127.0.0.1:51479 Closing +[Sat Apr 4 18:41:21 2026] 127.0.0.1:61973 Accepted +[Sat Apr 4 18:41:21 2026] 127.0.0.1:61973 [200]: GET /images/star16x16.png +[Sat Apr 4 18:41:21 2026] 127.0.0.1:55305 Accepted +[Sat Apr 4 18:41:21 2026] 127.0.0.1:55305 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 18:41:21 2026] 127.0.0.1:61973 Closing +[Sat Apr 4 18:41:21 2026] 127.0.0.1:55305 Closing +[Sat Apr 4 18:41:21 2026] 127.0.0.1:54170 Accepted +[Sat Apr 4 18:41:21 2026] 127.0.0.1:54170 [200]: GET /images/moons/moon4geocron.png +[Sat Apr 4 18:41:21 2026] 127.0.0.1:54170 Closing +[Sat Apr 4 18:41:22 2026] 127.0.0.1:58395 Accepted +[Sat Apr 4 18:41:22 2026] 127.0.0.1:58395 [200]: GET /favicon.ico +[Sat Apr 4 18:41:22 2026] 127.0.0.1:58395 Closing +[Sat Apr 4 19:19:57 2026] 127.0.0.1:49351 Accepted +[Sat Apr 4 19:20:08 2026] 127.0.0.1:49351 [200]: GET /wochenvorhersage.php?year=2026&week=53 +[Sat Apr 4 19:20:08 2026] 127.0.0.1:49351 Closing +[Sat Apr 4 19:20:08 2026] 127.0.0.1:50066 Accepted +[Sat Apr 4 19:20:08 2026] 127.0.0.1:62275 Accepted +[Sat Apr 4 19:20:08 2026] 127.0.0.1:50066 [200]: GET /css/style.css +[Sat Apr 4 19:20:08 2026] 127.0.0.1:62275 [200]: GET /js/astronomy.browser.min.js +[Sat Apr 4 19:20:08 2026] 127.0.0.1:50066 Closing +[Sat Apr 4 19:20:08 2026] 127.0.0.1:62275 Closing +[Sat Apr 4 19:20:08 2026] 127.0.0.1:64582 Accepted +[Sat Apr 4 19:20:08 2026] 127.0.0.1:50907 Accepted +[Sat Apr 4 19:20:08 2026] 127.0.0.1:64582 [200]: GET /images/star16x16.png +[Sat Apr 4 19:20:08 2026] 127.0.0.1:50907 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 19:20:08 2026] 127.0.0.1:64582 Closing +[Sat Apr 4 19:20:08 2026] 127.0.0.1:50907 Closing +[Sat Apr 4 19:20:08 2026] 127.0.0.1:49787 Accepted +[Sat Apr 4 19:20:08 2026] 127.0.0.1:49787 [200]: GET /images/moons/moon4geocron.png +[Sat Apr 4 19:20:08 2026] 127.0.0.1:49787 Closing +[Sat Apr 4 19:20:08 2026] 127.0.0.1:63843 Accepted +[Sat Apr 4 19:20:09 2026] 127.0.0.1:63843 [200]: GET /favicon.ico +[Sat Apr 4 19:20:09 2026] 127.0.0.1:63843 Closing +[Sat Apr 4 19:21:05 2026] 127.0.0.1:53592 Accepted +[Sat Apr 4 19:21:20 2026] 127.0.0.1:53592 [200]: GET /wochenvorhersage.php?year=2026&week=12 +[Sat Apr 4 19:21:20 2026] 127.0.0.1:53592 Closing +[Sat Apr 4 19:21:20 2026] 127.0.0.1:55418 Accepted +[Sat Apr 4 19:21:20 2026] 127.0.0.1:64078 Accepted +[Sat Apr 4 19:21:20 2026] 127.0.0.1:55418 [200]: GET /css/style.css +[Sat Apr 4 19:21:20 2026] 127.0.0.1:64078 [200]: GET /js/astronomy.browser.min.js +[Sat Apr 4 19:21:20 2026] 127.0.0.1:55418 Closing +[Sat Apr 4 19:21:20 2026] 127.0.0.1:64078 Closing +[Sat Apr 4 19:21:20 2026] 127.0.0.1:50402 Accepted +[Sat Apr 4 19:21:20 2026] 127.0.0.1:50402 [200]: GET /images/star16x16.png +[Sat Apr 4 19:21:20 2026] 127.0.0.1:65488 Accepted +[Sat Apr 4 19:21:20 2026] 127.0.0.1:65488 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 19:21:20 2026] 127.0.0.1:50402 Closing +[Sat Apr 4 19:21:20 2026] 127.0.0.1:65488 Closing +[Sat Apr 4 19:21:20 2026] 127.0.0.1:59610 Accepted +[Sat Apr 4 19:21:20 2026] 127.0.0.1:59610 [200]: GET /images/moons/moon4geocron.png +[Sat Apr 4 19:21:20 2026] 127.0.0.1:59610 Closing +[Sat Apr 4 19:21:20 2026] 127.0.0.1:58943 Accepted +[Sat Apr 4 19:21:21 2026] 127.0.0.1:58943 [200]: GET /favicon.ico +[Sat Apr 4 19:21:21 2026] 127.0.0.1:58943 Closing +[Sat Apr 4 19:22:27 2026] 127.0.0.1:61751 Accepted +[Sat Apr 4 19:22:27 2026] 127.0.0.1:61751 [200]: GET /settings.php +[Sat Apr 4 19:22:27 2026] 127.0.0.1:61751 Closing +[Sat Apr 4 19:22:27 2026] 127.0.0.1:51920 Accepted +[Sat Apr 4 19:22:27 2026] 127.0.0.1:51920 [200]: GET /css/style.css +[Sat Apr 4 19:22:27 2026] 127.0.0.1:51920 Closing +[Sat Apr 4 19:22:27 2026] 127.0.0.1:60986 Accepted +[Sat Apr 4 19:22:27 2026] 127.0.0.1:52887 Accepted +[Sat Apr 4 19:22:27 2026] 127.0.0.1:60986 [200]: GET /images/star16x16.png +[Sat Apr 4 19:22:27 2026] 127.0.0.1:52887 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 19:22:27 2026] 127.0.0.1:60986 Closing +[Sat Apr 4 19:22:27 2026] 127.0.0.1:52887 Closing +[Sat Apr 4 19:22:27 2026] 127.0.0.1:61244 Accepted +[Sat Apr 4 19:22:28 2026] 127.0.0.1:61244 [200]: GET /favicon.ico +[Sat Apr 4 19:22:28 2026] 127.0.0.1:61244 Closing +[Sat Apr 4 19:33:35 2026] 127.0.0.1:55136 Accepted +[Sat Apr 4 19:33:35 2026] 127.0.0.1:55136 [200]: GET /settings.php +[Sat Apr 4 19:33:35 2026] 127.0.0.1:55136 Closing +[Sat Apr 4 19:33:35 2026] 127.0.0.1:58715 Accepted +[Sat Apr 4 19:33:35 2026] 127.0.0.1:58715 [200]: GET /css/style.css +[Sat Apr 4 19:33:35 2026] 127.0.0.1:58715 Closing +[Sat Apr 4 19:33:35 2026] 127.0.0.1:59506 Accepted +[Sat Apr 4 19:33:35 2026] 127.0.0.1:59506 [200]: GET /images/star16x16.png +[Sat Apr 4 19:33:35 2026] 127.0.0.1:49656 Accepted +[Sat Apr 4 19:33:35 2026] 127.0.0.1:49656 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 19:33:35 2026] 127.0.0.1:59506 Closing +[Sat Apr 4 19:33:35 2026] 127.0.0.1:49656 Closing +[Sat Apr 4 19:33:35 2026] 127.0.0.1:53331 Accepted +[Sat Apr 4 19:33:36 2026] 127.0.0.1:53331 [200]: GET /favicon.ico +[Sat Apr 4 19:33:36 2026] 127.0.0.1:53331 Closing +[Sat Apr 4 19:33:39 2026] 127.0.0.1:60359 Accepted +[Sat Apr 4 19:33:39 2026] 127.0.0.1:60359 [200]: GET /my_favorites.php +[Sat Apr 4 19:33:39 2026] 127.0.0.1:60359 Closing +[Sat Apr 4 19:33:39 2026] 127.0.0.1:57196 Accepted +[Sat Apr 4 19:33:39 2026] 127.0.0.1:57196 [200]: GET /css/style.css +[Sat Apr 4 19:33:39 2026] 127.0.0.1:57196 Closing +[Sat Apr 4 19:33:39 2026] 127.0.0.1:57348 Accepted +[Sat Apr 4 19:33:39 2026] 127.0.0.1:52349 Accepted +[Sat Apr 4 19:33:39 2026] 127.0.0.1:57348 [200]: GET /images/star16x16.png +[Sat Apr 4 19:33:39 2026] 127.0.0.1:52349 [200]: GET /images/star16x16_rays.png +[Sat Apr 4 19:33:39 2026] 127.0.0.1:57348 Closing +[Sat Apr 4 19:33:39 2026] 127.0.0.1:52349 Closing +[Sat Apr 4 19:33:39 2026] 127.0.0.1:51368 Accepted +[Sat Apr 4 19:33:40 2026] 127.0.0.1:51368 [200]: GET /favicon.ico +[Sat Apr 4 19:33:40 2026] 127.0.0.1:51368 Closing diff --git a/public/my_favorites.php b/public/my_favorites.php index a898071..7bc469c 100644 --- a/public/my_favorites.php +++ b/public/my_favorites.php @@ -46,6 +46,11 @@ function h(?string $value): string return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); } +function validTimezone(string $timezone): bool +{ + return in_array($timezone, timezone_identifiers_list(), true); +} + function setExclusiveFavorite(PDO $pdo, string $tableName, string $idColumn, int $userId, int $entityId): bool { $pdo->beginTransaction(); @@ -278,8 +283,222 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } } + + if ($action === 'add_location') { + $name = trim($_POST['name'] ?? ''); + $latitude = trim($_POST['latitude'] ?? ''); + $longitude = trim($_POST['longitude'] ?? ''); + $elevation = trim($_POST['elevation'] ?? ''); + $timezone = trim($_POST['timezone'] ?? 'Europe/Berlin'); + $isDefault = isset($_POST['is_default']) ? 1 : 0; + + if ($name === '') { + $errors[] = 'Bitte einen Namen fuer den Standort eingeben.'; + } + + if ($latitude === '' || !is_numeric($latitude)) { + $errors[] = 'Bitte einen gueltigen Breitengrad eingeben.'; + } else { + $lat = (float) $latitude; + if ($lat < -90 || $lat > 90) { + $errors[] = 'Der Breitengrad muss zwischen -90 und 90 liegen.'; + } + } + + if ($longitude === '' || !is_numeric($longitude)) { + $errors[] = 'Bitte einen gueltigen Laengengrad eingeben.'; + } else { + $lon = (float) $longitude; + if ($lon < -180 || $lon > 180) { + $errors[] = 'Der Laengengrad muss zwischen -180 und 180 liegen.'; + } + } + + if ($elevation !== '' && !is_numeric($elevation)) { + $errors[] = 'Die Hoehe muss numerisch sein.'; + } + + if (!validTimezone($timezone)) { + $errors[] = 'Bitte eine gueltige IANA-Zeitzone angeben, z. B. Europe/Berlin.'; + } + + if (empty($errors)) { + $pdo->beginTransaction(); + + try { + if ($isDefault === 1) { + $stmtReset = $pdo->prepare(" + UPDATE `app_user_locations` + SET `is_default` = 0 + WHERE `user_id` = :user_id + "); + $stmtReset->execute([ + ':user_id' => $userId, + ]); + } + + $stmtInsertLocation = $pdo->prepare(" + INSERT INTO `app_user_locations` ( + `user_id`, + `name`, + `latitude`, + `longitude`, + `elevation`, + `timezone`, + `is_default`, + `created_at`, + `updated_at` + ) VALUES ( + :user_id, + :name, + :latitude, + :longitude, + :elevation, + :timezone, + :is_default, + NOW(), + NOW() + ) + "); + $stmtInsertLocation->execute([ + ':user_id' => $userId, + ':name' => $name, + ':latitude' => (float) $latitude, + ':longitude' => (float) $longitude, + ':elevation' => $elevation !== '' ? (float) $elevation : null, + ':timezone' => $timezone, + ':is_default' => $isDefault, + ]); + + $pdo->commit(); + $successMessage = 'Der Standort wurde gespeichert.'; + $_POST = []; + } catch (Throwable $e) { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + $errors[] = 'Der Standort konnte nicht gespeichert werden.'; + } + } + } + + if ($action === 'set_default_location') { + $locationId = (int) ($_POST['location_id'] ?? 0); + + if ($locationId <= 0) { + $errors[] = 'Ungueltiger Standort.'; + } + + if (empty($errors)) { + $stmtCheckLocation = $pdo->prepare(" + SELECT `id` + FROM `app_user_locations` + WHERE `id` = :id + AND `user_id` = :user_id + LIMIT 1 + "); + $stmtCheckLocation->execute([ + ':id' => $locationId, + ':user_id' => $userId, + ]); + + if (!$stmtCheckLocation->fetch()) { + $errors[] = 'Der Standort wurde nicht gefunden.'; + } + } + + if (empty($errors)) { + $pdo->beginTransaction(); + + try { + $stmtReset = $pdo->prepare(" + UPDATE `app_user_locations` + SET `is_default` = 0 + WHERE `user_id` = :user_id + "); + $stmtReset->execute([ + ':user_id' => $userId, + ]); + + $stmtSet = $pdo->prepare(" + UPDATE `app_user_locations` + SET `is_default` = 1 + WHERE `id` = :id + AND `user_id` = :user_id + "); + $stmtSet->execute([ + ':id' => $locationId, + ':user_id' => $userId, + ]); + + $pdo->commit(); + $successMessage = 'Der Standard-Standort wurde gesetzt.'; + } catch (Throwable $e) { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + $errors[] = 'Der Standard-Standort konnte nicht gesetzt werden.'; + } + } + } + + if ($action === 'delete_location') { + $locationId = (int) ($_POST['location_id'] ?? 0); + + if ($locationId <= 0) { + $errors[] = 'Ungueltiger Standort.'; + } + + if (empty($errors)) { + $stmtDelete = $pdo->prepare(" + DELETE FROM `app_user_locations` + WHERE `id` = :id + AND `user_id` = :user_id + "); + $stmtDelete->execute([ + ':id' => $locationId, + ':user_id' => $userId, + ]); + + $successMessage = 'Der Standort wurde geloescht.'; + } + } } +$stmtLocations = $pdo->prepare(" + SELECT + `id`, + `name`, + `latitude`, + `longitude`, + `elevation`, + `timezone`, + `is_default` + FROM `app_user_locations` + WHERE `user_id` = :user_id + ORDER BY `is_default` DESC, `name` ASC +"); +$stmtLocations->execute([ + ':user_id' => $userId, +]); +$locations = $stmtLocations->fetchAll(); + +$defaultLocation = null; +foreach ($locations as $location) { + if ((int) $location['is_default'] === 1) { + $defaultLocation = $location; + break; + } +} + +$mapLat = isset($_POST['latitude']) && is_numeric($_POST['latitude']) + ? (float) $_POST['latitude'] + : ($defaultLocation ? (float) $defaultLocation['latitude'] : 51.1657); +$mapLon = isset($_POST['longitude']) && is_numeric($_POST['longitude']) + ? (float) $_POST['longitude'] + : ($defaultLocation ? (float) $defaultLocation['longitude'] : 10.4515); +$mapZoom = $defaultLocation ? 10 : 6; + if ($satelliteSearchQuery !== '') { if (ctype_digit($satelliteSearchQuery)) { $stmtSatelliteSearch = $pdo->prepare(" @@ -424,6 +643,13 @@ $loggedIn = true; ?> + +

@@ -436,6 +662,101 @@ $loggedIn = true; +
+
+

Standorte

+ +

Es sind noch keine Standorte gespeichert.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameBreitengradLaengengradHoeheZeitzoneStandard
+ +
+ + + +
+ +
+ + + +
+
+ +
+ +
+

Standort hinzufuegen

+

Suche einen Ort, nutze den Browser-Standort oder klicke direkt in die Karte.

+ +
+ + + + +
+ +
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+
+

Satelliten suchen

@@ -636,7 +957,188 @@ $loggedIn = true;
+ + - - -