0) { return 'HIP ' . $hip; } return 'Unbenannter Stern'; } function runPythonApi(string $scriptPath, string $action, array $arguments): array { $pythonCandidates = ['/usr/bin/python', '/usr/bin/python3', 'python3', 'python']; $escapedArguments = [escapeshellarg($scriptPath), escapeshellarg($action)]; foreach ($arguments as $argument) { $escapedArguments[] = escapeshellarg((string)$argument); } $lastError = 'Python konnte nicht ausgefuehrt werden.'; $debugOutput = []; foreach ($pythonCandidates as $pythonBinary) { $command = $pythonBinary . ' ' . implode(' ', $escapedArguments) . ' 2>&1'; $output = []; $resultCode = 0; exec($command, $output, $resultCode); $joined = trim(implode("\n", $output)); $debugOutput = $output; if ($resultCode !== 0) { $lastError = $joined !== '' ? $joined : ('Fehlercode ' . $resultCode . ' bei ' . $pythonBinary); continue; } $decoded = json_decode($joined, true); if (!is_array($decoded)) { $lastError = $joined !== '' ? 'Python-Ausgabe war kein gültiges JSON.' : 'Python lieferte keine Ausgabe zurück.'; continue; } if (!($decoded['ok'] ?? false)) { return [ 'ok' => false, 'error' => (string)($decoded['error'] ?? 'Unbekannter Python-Fehler'), 'debug' => $joined, ]; } return ['ok' => true, 'data' => $decoded]; } return [ 'ok' => false, 'error' => $lastError, 'debug' => implode("\n", $debugOutput), ]; } $defaultLocation = null; $pdo = null; $pageError = null; $pageLocation = null; $detailMapStars = []; $constellationLines = []; $detailMapCatalogLimit = 8.0; $isAjax = isset($_POST['ajax']) && (string)$_POST['ajax'] === '1'; try { $config = require __DIR__ . '/../config/database.php'; $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', $config['host'], $config['dbname'], $config['charset'] ?? 'utf8mb4' ); $pdo = new PDO( $dsn, $config['user'], $config['pass'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); if ($loggedIn && isset($_SESSION['user_id'])) { $stmtLocation = $pdo->prepare( 'SELECT id, name, latitude, longitude, elevation, timezone FROM app_user_locations WHERE user_id = ? AND is_default = 1 LIMIT 1' ); $stmtLocation->execute([(int)$_SESSION['user_id']]); $defaultLocation = $stmtLocation->fetch() ?: null; } } catch (Throwable $exception) { $pageError = $exception->getMessage(); } if (!empty($defaultLocation) && is_array($defaultLocation)) { $pageLocation = [ 'name' => (string)($defaultLocation['name'] ?? ''), 'latitude' => isset($defaultLocation['latitude']) ? (float)$defaultLocation['latitude'] : null, 'longitude' => isset($defaultLocation['longitude']) ? (float)$defaultLocation['longitude'] : null, 'elevation' => isset($defaultLocation['elevation']) && $defaultLocation['elevation'] !== null ? (float)$defaultLocation['elevation'] : 0.0, 'timezone' => (string)($defaultLocation['timezone'] ?? 'Europe/Berlin'), ]; } $timezoneName = $pageLocation['timezone'] ?? 'Europe/Berlin'; try { $timezone = new DateTimeZone($timezoneName); } catch (Throwable $exception) { $timezoneName = 'Europe/Berlin'; $timezone = new DateTimeZone($timezoneName); } $todayLocal = (new DateTimeImmutable('now', $timezone))->format('Y-m-d'); $selectedDate = isset($_POST['date']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', (string)$_POST['date']) ? (string)$_POST['date'] : $todayLocal; $selectedMag = isset($_POST['mag']) ? (float)$_POST['mag'] : 3.0; $selectedMag = max(1.0, min(6.0, $selectedMag)); $selectedMag = round($selectedMag, 1); if (!$isAjax && $pageError === null && $pdo instanceof PDO && $pageLocation !== null && $pageLocation['latitude'] !== null && $pageLocation['longitude'] !== null) { try { $stmtDetailMap = $pdo->query( "SELECT `hip`, `proper`, `bf`, `con`, `mag`, `ra`, `dec`, `dist` FROM `star_hipparcos` WHERE `mag` IS NOT NULL AND `ra` IS NOT NULL AND `dec` IS NOT NULL AND `mag` <= 8.0 ORDER BY `mag` ASC, `proper` ASC, `bf` ASC, `hip` ASC" ); foreach ($stmtDetailMap->fetchAll() as $row) { $detailMapStars[] = [ 'hip' => isset($row['hip']) ? (int)$row['hip'] : 0, 'label' => buildStarLabel($row), 'constellation' => trim((string)($row['con'] ?? '')), 'mag' => isset($row['mag']) ? (float)$row['mag'] : null, 'ra' => isset($row['ra']) ? (float)$row['ra'] : null, 'dec' => isset($row['dec']) ? (float)$row['dec'] : null, 'distLy' => isset($row['dist']) && $row['dist'] !== null && (float)$row['dist'] > 0.0 ? (float)$row['dist'] * 3.26156 : 1000.0, ]; } $stmtLines = $pdo->query( "SELECT cl.`id` AS line_id, clp.`point_index`, sh.`ra` AS ra_hours, sh.`dec` AS dec_deg FROM `constellation_lines` cl INNER JOIN `constellation_line_points` clp ON clp.`line_id` = cl.`id` INNER JOIN `star_hipparcos` sh ON sh.`hip` = clp.`hip_number` WHERE sh.`ra` IS NOT NULL AND sh.`dec` IS NOT NULL ORDER BY cl.`id`, clp.`point_index`" ); foreach ($stmtLines->fetchAll() as $row) { $lineId = (int)$row['line_id']; $constellationLines[$lineId][] = [ 'ra' => isset($row['ra_hours']) ? (float)$row['ra_hours'] : null, 'dec' => isset($row['dec_deg']) ? (float)$row['dec_deg'] : null, ]; } } catch (Throwable $exception) { $pageError = $exception->getMessage(); $detailMapStars = []; $constellationLines = []; } } if ($isAjax) { header('Content-Type: application/json; charset=utf-8'); if ($pageLocation === null || $pageLocation['latitude'] === null || $pageLocation['longitude'] === null) { echo json_encode([ 'ok' => false, 'error' => 'Kein Standard-Standort gesetzt. Bitte zuerst in den Einstellungen einen Standard-Standort hinterlegen.', ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } if ($pageError !== null || !($pdo instanceof PDO)) { echo json_encode([ 'ok' => false, 'error' => $pageError ?? 'Die Datenbank ist nicht verfuegbar.', ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } try { $stmtStars = $pdo->prepare( "SELECT `hip`, `proper`, `bf`, `con`, `mag`, `ra`, `dec`, `dist` FROM `star_hipparcos` WHERE `mag` IS NOT NULL AND `ra` IS NOT NULL AND `dec` IS NOT NULL AND `mag` <= :max_mag ORDER BY `mag` ASC, `proper` ASC, `bf` ASC, `hip` ASC" ); $stmtStars->execute([':max_mag' => $selectedMag]); $stars = []; foreach ($stmtStars->fetchAll() as $row) { $stars[] = [ 'hip' => isset($row['hip']) ? (int)$row['hip'] : 0, 'label' => buildStarLabel($row), 'constellation' => trim((string)($row['con'] ?? '')), 'mag' => isset($row['mag']) ? (float)$row['mag'] : 99.0, 'ra' => isset($row['ra']) ? (float)$row['ra'] : 0.0, 'dec' => isset($row['dec']) ? (float)$row['dec'] : 0.0, 'distLy' => isset($row['dist']) && $row['dist'] !== null && (float)$row['dist'] > 0.0 ? (float)$row['dist'] * 3.26156 : 1000.0, ]; } $starCount = count($stars); $tempFile = tempnam(sys_get_temp_dir(), 'occult_stars_'); if ($tempFile === false) { throw new RuntimeException('Temporäre Sterndatei konnte nicht angelegt werden.'); } try { file_put_contents($tempFile, json_encode($stars, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR)); $pythonResult = runPythonApi( __DIR__ . '/py/api.py', 'moon_star_occultations', [ (string)$pageLocation['latitude'], (string)$pageLocation['longitude'], (string)$pageLocation['elevation'], $selectedDate, $timezoneName, $tempFile, ] ); if (!$pythonResult['ok']) { echo json_encode([ 'ok' => false, 'error' => $pythonResult['error'] ?? 'Unbekannter Python-Fehler', 'debug' => $pythonResult['debug'] ?? null, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } echo json_encode([ 'ok' => true, 'star_count' => $starCount, 'results' => $pythonResult['data']['results'] ?? [], 'selected_date' => $selectedDate, 'selected_mag' => $selectedMag, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } finally { if (is_file($tempFile)) { @unlink($tempFile); } } } catch (Throwable $exception) { echo json_encode([ 'ok' => false, 'error' => $exception->getMessage(), ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } } require __DIR__ . '/header.php'; if (!empty($currentLocation) && is_array($currentLocation)) { $pageLocation = [ 'name' => (string)($currentLocation['name'] ?? ''), 'latitude' => isset($currentLocation['latitude']) ? (float)$currentLocation['latitude'] : null, 'longitude' => isset($currentLocation['longitude']) ? (float)$currentLocation['longitude'] : null, 'elevation' => isset($currentLocation['elevation']) && $currentLocation['elevation'] !== null ? (float)$currentLocation['elevation'] : 0.0, 'timezone' => (string)($currentLocation['timezone'] ?? 'Europe/Berlin'), ]; } ?>

Kein Standard-Standort gesetzt

Fuer die Berechnung wird der Standard-Standort aus der Datenbank verwendet. Bitte wähle in den Einstellungen einen Standard-Standort aus.

Datenbank nicht verfuegbar

Die Sterndaten konnten nicht geladen werden.

Technischer Hinweis:

Standort ° / °
Berechnung
Die Berechnung laeuft im Hintergrund. Hoehere Grenzgroessen brauchen deutlich laenger.

Bereit zur Berechnung

Die Seite bleibt jetzt während der Berechnung sichtbar. Wähle Datum und Grenzgröße und starte die Auswertung mit dem Button.