PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); $userId = (int) $_SESSION['user_id']; $errors = []; $successMessage = ''; $satelliteSearchResults = []; $minorplanetSearchResults = []; $satelliteSearchQuery = trim($_GET['sat_q'] ?? ''); $minorplanetSearchQuery = trim($_GET['mp_q'] ?? ''); $pageTitle = 'Favoriten - AstroTools'; $headerIntroPre = 'Merkliste'; $headerIntroTitle = 'Favoriten'; $headerIntroSub = 'Satelliten und Kleinplaneten zentral verwalten.'; 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(); try { $stmtCurrent = $pdo->prepare(" SELECT `is_favorite` FROM `{$tableName}` WHERE `user_id` = :user_id AND `{$idColumn}` = :entity_id LIMIT 1 "); $stmtCurrent->execute([ ':user_id' => $userId, ':entity_id' => $entityId, ]); $current = $stmtCurrent->fetchColumn(); if ($current === false) { $pdo->rollBack(); return false; } $newValue = (int) $current === 1 ? 0 : 1; if ($newValue === 1) { $stmtReset = $pdo->prepare(" UPDATE `{$tableName}` SET `is_favorite` = 0 WHERE `user_id` = :user_id "); $stmtReset->execute([ ':user_id' => $userId, ]); } $stmtSet = $pdo->prepare(" UPDATE `{$tableName}` SET `is_favorite` = :is_favorite WHERE `user_id` = :user_id AND `{$idColumn}` = :entity_id "); $stmtSet->execute([ ':is_favorite' => $newValue, ':user_id' => $userId, ':entity_id' => $entityId, ]); $pdo->commit(); return true; } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } throw $e; } } function countUserRows(PDO $pdo, string $tableName, int $userId): int { $stmtCount = $pdo->prepare(" SELECT COUNT(*) FROM `{$tableName}` WHERE `user_id` = :user_id "); $stmtCount->execute([ ':user_id' => $userId, ]); return (int) $stmtCount->fetchColumn(); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; if ($action === 'add_satellite') { $satelliteId = (int) ($_POST['satellite_id'] ?? 0); if ($satelliteId <= 0) { $errors[] = 'Ungültiger Satellit.'; } if (empty($errors)) { $stmtCheck = $pdo->prepare(" SELECT `id` FROM `sat_satellites` WHERE `id` = :id LIMIT 1 "); $stmtCheck->execute([ ':id' => $satelliteId, ]); if (!$stmtCheck->fetch()) { $errors[] = 'Der Satellit wurde nicht gefunden.'; } } if (empty($errors)) { $stmtInsert = $pdo->prepare(" INSERT INTO `app_user_satellites` ( `user_id`, `satellite_id`, `is_favorite`, `created_at` ) VALUES ( :user_id, :satellite_id, 0, NOW() ) ON DUPLICATE KEY UPDATE `satellite_id` = VALUES(`satellite_id`) "); $stmtInsert->execute([ ':user_id' => $userId, ':satellite_id' => $satelliteId, ]); $successMessage = 'Der Satellit wurde hinzugefuegt.'; } } if ($action === 'remove_satellite') { $satelliteId = (int) ($_POST['satellite_id'] ?? 0); if ($satelliteId <= 0) { $errors[] = 'Ungültiger Satellit.'; } if (empty($errors)) { $stmtSatellite = $pdo->prepare(" SELECT `satellite_id`, `is_favorite` FROM `app_user_satellites` WHERE `user_id` = :user_id AND `satellite_id` = :satellite_id LIMIT 1 "); $stmtSatellite->execute([ ':user_id' => $userId, ':satellite_id' => $satelliteId, ]); $satelliteRow = $stmtSatellite->fetch(); if (!$satelliteRow) { $errors[] = 'Der Satellit ist nicht in deiner Liste vorhanden.'; } } if (empty($errors)) { $satelliteCount = countUserRows($pdo, 'app_user_satellites', $userId); if ($satelliteCount <= 1) { $errors[] = 'Der letzte Satellit kann nicht gelöscht werden.'; } } if (empty($errors)) { $pdo->beginTransaction(); try { $stmtDelete = $pdo->prepare(" DELETE FROM `app_user_satellites` WHERE `user_id` = :user_id AND `satellite_id` = :satellite_id "); $stmtDelete->execute([ ':user_id' => $userId, ':satellite_id' => $satelliteId, ]); if ((int) ($satelliteRow['is_favorite'] ?? 0) === 1) { $stmtNextFavorite = $pdo->prepare(" SELECT `satellite_id` FROM `app_user_satellites` WHERE `user_id` = :user_id ORDER BY `created_at` ASC, `satellite_id` ASC LIMIT 1 "); $stmtNextFavorite->execute([ ':user_id' => $userId, ]); $nextSatelliteId = $stmtNextFavorite->fetchColumn(); if ($nextSatelliteId !== false) { $stmtResetFavorites = $pdo->prepare(" UPDATE `app_user_satellites` SET `is_favorite` = 0 WHERE `user_id` = :user_id "); $stmtResetFavorites->execute([ ':user_id' => $userId, ]); $stmtSetFavorite = $pdo->prepare(" UPDATE `app_user_satellites` SET `is_favorite` = 1 WHERE `user_id` = :user_id AND `satellite_id` = :satellite_id "); $stmtSetFavorite->execute([ ':user_id' => $userId, ':satellite_id' => (int) $nextSatelliteId, ]); } } $pdo->commit(); $successMessage = 'Der Satellit wurde entfernt.'; } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } $errors[] = 'Der Satellit konnte nicht entfernt werden.'; } } } if ($action === 'toggle_satellite_favorite') { $satelliteId = (int) ($_POST['satellite_id'] ?? 0); if ($satelliteId <= 0) { $errors[] = 'Ungültiger Satellit.'; } if (empty($errors)) { $stmtCurrentSatellite = $pdo->prepare(" SELECT `is_favorite` FROM `app_user_satellites` WHERE `user_id` = :user_id AND `satellite_id` = :satellite_id LIMIT 1 "); $stmtCurrentSatellite->execute([ ':user_id' => $userId, ':satellite_id' => $satelliteId, ]); $currentSatelliteFavorite = $stmtCurrentSatellite->fetchColumn(); if ($currentSatelliteFavorite === false) { $errors[] = 'Der Satellit ist nicht in deiner Liste vorhanden.'; } } if (empty($errors)) { $satelliteCount = countUserRows($pdo, 'app_user_satellites', $userId); if ($satelliteCount <= 1 && (int) $currentSatelliteFavorite === 1) { $errors[] = 'Beim letzten Satelliten kann der Favorit nicht entfernt werden.'; } } if (empty($errors)) { if (!setExclusiveFavorite($pdo, 'app_user_satellites', 'satellite_id', $userId, $satelliteId)) { $errors[] = 'Der Satellit ist nicht in deiner Liste vorhanden.'; } else { $successMessage = 'Der Satelliten-Favorit wurde aktualisiert.'; } } } if ($action === 'add_minorplanet') { $minorplanetId = (int) ($_POST['minorplanet_id'] ?? 0); if ($minorplanetId <= 0) { $errors[] = 'Ungültiger Kleinplanet.'; } if (empty($errors)) { $stmtCheck = $pdo->prepare(" SELECT `id` FROM `minorplanets_mpc` WHERE `id` = :id LIMIT 1 "); $stmtCheck->execute([ ':id' => $minorplanetId, ]); if (!$stmtCheck->fetch()) { $errors[] = 'Der Kleinplanet wurde nicht gefunden.'; } } if (empty($errors)) { $stmtInsert = $pdo->prepare(" INSERT INTO `app_user_minorplanets` ( `user_id`, `minorplanet_id`, `is_favorite`, `created_at` ) VALUES ( :user_id, :minorplanet_id, 0, NOW() ) ON DUPLICATE KEY UPDATE `minorplanet_id` = VALUES(`minorplanet_id`) "); $stmtInsert->execute([ ':user_id' => $userId, ':minorplanet_id' => $minorplanetId, ]); $successMessage = 'Der Kleinplanet wurde hinzugefuegt.'; } } if ($action === 'remove_minorplanet') { $minorplanetId = (int) ($_POST['minorplanet_id'] ?? 0); if ($minorplanetId <= 0) { $errors[] = 'Ungültiger Kleinplanet.'; } if (empty($errors)) { $stmtDelete = $pdo->prepare(" DELETE FROM `app_user_minorplanets` WHERE `user_id` = :user_id AND `minorplanet_id` = :minorplanet_id "); $stmtDelete->execute([ ':user_id' => $userId, ':minorplanet_id' => $minorplanetId, ]); $successMessage = 'Der Kleinplanet wurde entfernt.'; } } if ($action === 'toggle_minorplanet_favorite') { $minorplanetId = (int) ($_POST['minorplanet_id'] ?? 0); if ($minorplanetId <= 0) { $errors[] = 'Ungültiger Kleinplanet.'; } if (empty($errors)) { if (!setExclusiveFavorite($pdo, 'app_user_minorplanets', 'minorplanet_id', $userId, $minorplanetId)) { $errors[] = 'Der Kleinplanet ist nicht in deiner Liste vorhanden.'; } else { $successMessage = 'Der Kleinplaneten-Favorit wurde aktualisiert.'; } } } 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 für den Standort eingeben.'; } if ($latitude === '' || !is_numeric($latitude)) { $errors[] = 'Bitte einen gültigen 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 gültigen Längengrad eingeben.'; } else { $lon = (float) $longitude; if ($lon < -180 || $lon > 180) { $errors[] = 'Der Längengrad muss zwischen -180 und 180 liegen.'; } } if ($elevation !== '' && !is_numeric($elevation)) { $errors[] = 'Die Hoehe muss numerisch sein.'; } if (!validTimezone($timezone)) { $errors[] = 'Bitte eine gültige 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[] = 'Ungültiger 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[] = 'Ungültiger Standort.'; } if (empty($errors)) { $stmtLocation = $pdo->prepare(" SELECT `id`, `is_default` FROM `app_user_locations` WHERE `id` = :id AND `user_id` = :user_id LIMIT 1 "); $stmtLocation->execute([ ':id' => $locationId, ':user_id' => $userId, ]); $locationRow = $stmtLocation->fetch(); if (!$locationRow) { $errors[] = 'Der Standort wurde nicht gefunden.'; } } if (empty($errors)) { $locationCount = countUserRows($pdo, 'app_user_locations', $userId); if ($locationCount <= 1) { $errors[] = 'Der letzte Standort kann nicht gelöscht werden.'; } } if (empty($errors)) { $pdo->beginTransaction(); try { $stmtDelete = $pdo->prepare(" DELETE FROM `app_user_locations` WHERE `id` = :id AND `user_id` = :user_id "); $stmtDelete->execute([ ':id' => $locationId, ':user_id' => $userId, ]); if ((int) ($locationRow['is_default'] ?? 0) === 1) { $stmtNextDefault = $pdo->prepare(" SELECT `id` FROM `app_user_locations` WHERE `user_id` = :user_id ORDER BY `name` ASC, `id` ASC LIMIT 1 "); $stmtNextDefault->execute([ ':user_id' => $userId, ]); $nextLocationId = $stmtNextDefault->fetchColumn(); if ($nextLocationId !== false) { $stmtResetDefaults = $pdo->prepare(" UPDATE `app_user_locations` SET `is_default` = 0 WHERE `user_id` = :user_id "); $stmtResetDefaults->execute([ ':user_id' => $userId, ]); $stmtSetDefault = $pdo->prepare(" UPDATE `app_user_locations` SET `is_default` = 1 WHERE `user_id` = :user_id AND `id` = :id "); $stmtSetDefault->execute([ ':user_id' => $userId, ':id' => (int) $nextLocationId, ]); } } $pdo->commit(); $successMessage = 'Der Standort wurde gelöscht.'; } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } $errors[] = 'Der Standort konnte nicht gelöscht werden.'; } } } } $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(" SELECT s.`id`, s.`norad_cat_id`, s.`object_name`, CASE WHEN aus.`satellite_id` IS NULL THEN 0 ELSE 1 END AS `already_added` FROM `sat_satellites` s LEFT JOIN `app_user_satellites` aus ON aus.`satellite_id` = s.`id` AND aus.`user_id` = :user_id WHERE s.`norad_cat_id` = :norad_cat_id ORDER BY s.`object_name` ASC LIMIT 50 "); $stmtSatelliteSearch->execute([ ':user_id' => $userId, ':norad_cat_id' => (int) $satelliteSearchQuery, ]); } else { $stmtSatelliteSearch = $pdo->prepare(" SELECT s.`id`, s.`norad_cat_id`, s.`object_name`, CASE WHEN aus.`satellite_id` IS NULL THEN 0 ELSE 1 END AS `already_added` FROM `sat_satellites` s LEFT JOIN `app_user_satellites` aus ON aus.`satellite_id` = s.`id` AND aus.`user_id` = :user_id WHERE s.`object_name` LIKE :query ORDER BY s.`object_name` ASC LIMIT 50 "); $stmtSatelliteSearch->execute([ ':user_id' => $userId, ':query' => '%' . $satelliteSearchQuery . '%', ]); } $satelliteSearchResults = $stmtSatelliteSearch->fetchAll(); } if ($minorplanetSearchQuery !== '') { if (ctype_digit($minorplanetSearchQuery)) { $stmtMinorplanetSearch = $pdo->prepare(" SELECT mp.`id`, mp.`mp_number`, mp.`designation_text`, mp.`desig_packed`, CASE WHEN aum.`minorplanet_id` IS NULL THEN 0 ELSE 1 END AS `already_added` FROM `minorplanets_mpc` mp LEFT JOIN `app_user_minorplanets` aum ON aum.`minorplanet_id` = mp.`id` AND aum.`user_id` = :user_id WHERE mp.`mp_number` = :mp_number ORDER BY mp.`mp_number` ASC, mp.`designation_text` ASC LIMIT 50 "); $stmtMinorplanetSearch->execute([ ':user_id' => $userId, ':mp_number' => (int) $minorplanetSearchQuery, ]); } else { $stmtMinorplanetSearch = $pdo->prepare(" SELECT mp.`id`, mp.`mp_number`, mp.`designation_text`, mp.`desig_packed`, CASE WHEN aum.`minorplanet_id` IS NULL THEN 0 ELSE 1 END AS `already_added` FROM `minorplanets_mpc` mp LEFT JOIN `app_user_minorplanets` aum ON aum.`minorplanet_id` = mp.`id` AND aum.`user_id` = :user_id WHERE mp.`designation_text` LIKE :query OR mp.`desig_packed` LIKE :query ORDER BY mp.`mp_number` IS NULL ASC, mp.`mp_number` ASC, mp.`designation_text` ASC LIMIT 50 "); $stmtMinorplanetSearch->execute([ ':user_id' => $userId, ':query' => '%' . $minorplanetSearchQuery . '%', ]); } $minorplanetSearchResults = $stmtMinorplanetSearch->fetchAll(); } $stmtTrackedSatellites = $pdo->prepare(" SELECT s.`id`, s.`norad_cat_id`, s.`object_name`, aus.`is_favorite`, aus.`created_at` FROM `app_user_satellites` aus INNER JOIN `sat_satellites` s ON s.`id` = aus.`satellite_id` WHERE aus.`user_id` = :user_id ORDER BY aus.`is_favorite` DESC, s.`object_name` ASC "); $stmtTrackedSatellites->execute([ ':user_id' => $userId, ]); $trackedSatellites = $stmtTrackedSatellites->fetchAll(); $stmtTrackedMinorplanets = $pdo->prepare(" SELECT mp.`id`, mp.`mp_number`, mp.`designation_text`, mp.`desig_packed`, aum.`is_favorite`, aum.`created_at` FROM `app_user_minorplanets` aum INNER JOIN `minorplanets_mpc` mp ON mp.`id` = aum.`minorplanet_id` WHERE aum.`user_id` = :user_id ORDER BY aum.`is_favorite` DESC, mp.`mp_number` IS NULL ASC, mp.`mp_number` ASC, mp.`designation_text` ASC "); $stmtTrackedMinorplanets->execute([ ':user_id' => $userId, ]); $trackedMinorplanets = $stmtTrackedMinorplanets->fetchAll(); $loggedIn = true; ?>
= h($successMessage) ?>
Es sind noch keine Standorte gespeichert.
| Name | Breitengrad | Längengrad | Hoehe | Zeitzone | Standard | |
|---|---|---|---|---|---|---|
| = h($location['name']) ?> | = h((string) $location['latitude']) ?> | = h((string) $location['longitude']) ?> | = h($location['elevation'] !== null ? (string) $location['elevation'] . ' m' : '-') ?> | = h($location['timezone']) ?> | = (int) $location['is_default'] === 1 ? '*' : '-' ?> | 1): ?> Letzter Standort |
Suche einen Ort, nutze den Browser-Standort oder klicke direkt in die Karte.
Keine passenden Satelliten gefunden.
| Name | NORAD | |
|---|---|---|
| = h($satellite['object_name']) ?> | = h((string) $satellite['norad_cat_id']) ?> | Bereits hinzugefuegt |
Keine passenden Kleinplaneten gefunden.
| Bezeichnung | Nummer | |
|---|---|---|
| = h($minorplanet['designation_text'] ?: $minorplanet['desig_packed']) ?> | = h($minorplanet['mp_number'] !== null ? (string) $minorplanet['mp_number'] : '—') ?> | Bereits hinzugefuegt |
Du hast noch keine Satelliten ausgewählt.
| Name | NORAD | Favorit | Hinzugefuegt | |
|---|---|---|---|---|
| = h($satellite['object_name']) ?> | = h((string) $satellite['norad_cat_id']) ?> | = (int) $satellite['is_favorite'] === 1 ? '*' : '-' ?> | = h($satellite['created_at']) ?> | Favorit bleibt gesetzt 1): ?> Letzter Satellit |
Du hast noch keine Kleinplaneten ausgewählt.
| Bezeichnung | Nummer | Favorit | Hinzugefuegt | |
|---|---|---|---|---|
| = h($minorplanet['designation_text'] ?: $minorplanet['desig_packed']) ?> | = h($minorplanet['mp_number'] !== null ? (string) $minorplanet['mp_number'] : '-') ?> | = (int) $minorplanet['is_favorite'] === 1 ? '*' : '-' ?> | = h($minorplanet['created_at']) ?> |