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 gueltiges JSON.' : 'Python lieferte keine Ausgabe zurueck.'; 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 waehle 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 waehrend der Berechnung sichtbar. Waehle Datum und Grenzgroesse und starte die Auswertung mit dem Button.