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; ?>

Standorte

Es sind noch keine Standorte gespeichert.

Name Breitengrad Längengrad Hoehe Zeitzone Standard
1): ?>
Letzter Standort

Standort hinzufuegen

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

Satelliten suchen

Suchergebnisse

Keine passenden Satelliten gefunden.

Name NORAD
Bereits hinzugefuegt

Kleinplaneten suchen

Suchergebnisse

Keine passenden Kleinplaneten gefunden.

Bezeichnung Nummer
Bereits hinzugefuegt

Meine Satelliten

Du hast noch keine Satelliten ausgewählt.

Name NORAD Favorit Hinzugefuegt
Favorit bleibt gesetzt
1): ?>
Letzter Satellit

Meine Kleinplaneten

Du hast noch keine Kleinplaneten ausgewählt.

Bezeichnung Nummer Favorit Hinzugefuegt