= 0 ? '+' : '-'; $abs = abs($val); $exp = (int)floor(log10($abs)) + 1; $mantissa = (int)round($abs / pow(10, $exp) * 1e5); if ($mantissa >= 100000) { $mantissa = 10000; $exp++; } $expSign = $exp >= 0 ? '+' : '-'; return sprintf('%s%05d%s%d', $sign, $mantissa, $expSign, abs($exp)); } function tleMmDot(float $val): string { $sign = $val >= 0 ? ' ' : '-'; return sprintf('%s.%08d', $sign, (int)round(abs($val) * 1e8)); } function tleEpoch(string $epochStr): string { $dt = new DateTimeImmutable($epochStr, new DateTimeZone('UTC')); $yy = (int)$dt->format('Y') % 100; $jan1 = new DateTimeImmutable($dt->format('Y') . '-01-01 00:00:00', new DateTimeZone('UTC')); $secs = (float)$dt->format('U') - (float)$jan1->format('U'); $day = $secs / 86400.0 + 1.0; return sprintf('%02d%012.8f', $yy, $day); } function tleIntlDesig(?string $objectId): string { if (!$objectId) { return str_repeat(' ', 8); } if (preg_match('/^(\d{4})-(\d+)([A-Z]*)$/i', trim($objectId), $m)) { $yy = substr($m[1], 2, 2); $launch = str_pad($m[2], 3, '0', STR_PAD_LEFT); $piece = str_pad(strtoupper($m[3]), 3, ' ', STR_PAD_RIGHT); return substr(str_pad($yy . $launch . $piece, 8, ' '), 0, 8); } return str_pad(substr($objectId, 0, 8), 8); } function buildLine1(array $sat, array $tle): string { $norad = (int)$sat['norad_cat_id']; $class = in_array($sat['classification_type'] ?? '', ['U', 'C', 'S'], true) ? $sat['classification_type'] : 'U'; $line = sprintf( '1 %05d%1s %-8s %14s %10s %8s %8s %1d %4d', $norad, $class, tleIntlDesig($sat['object_id'] ?? null), tleEpoch((string)$tle['epoch']), tleMmDot((float)($tle['mean_motion_dot'] ?? 0)), tleExp((float)($tle['mean_motion_ddot'] ?? 0)), tleExp((float)($tle['bstar'] ?? 0)), (int)($tle['ephemeris_type'] ?? 0), (int)($tle['element_set_no'] ?? 0) ); $line = str_pad($line, 68); return $line . tleChecksum($line); } function buildLine2(array $sat, array $tle): string { $norad = (int)$sat['norad_cat_id']; $ecc = (float)($tle['eccentricity'] ?? 0); $eccStr = substr(sprintf('%.7f', $ecc), 2); $line = sprintf( '2 %05d %8.4f %8.4f %7s %8.4f %8.4f %11.8f%5d', $norad, (float)($tle['inclination'] ?? 0), (float)($tle['ra_of_asc_node'] ?? 0), $eccStr, (float)($tle['arg_of_pericenter'] ?? 0), (float)($tle['mean_anomaly'] ?? 0), (float)($tle['mean_motion'] ?? 0), (int)($tle['rev_at_epoch'] ?? 0) ); $line = str_pad($line, 68); return $line . tleChecksum($line); } $userId = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0; if ($userId <= 0) { http_response_code(401); echo json_encode(['error' => 'Nicht angemeldet.']); exit; } $requestedIds = array_values(array_filter( array_map('intval', explode(',', (string)($_GET['ids'] ?? ''))), static fn(int $id): bool => $id > 0 )); $cfg = require __DIR__ . '/../../config/database.php'; try { $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', $cfg['host'], $cfg['dbname'], $cfg['charset'] ?? 'utf8mb4' ); $pdo = new PDO($dsn, $cfg['user'], $cfg['pass'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); } catch (PDOException $e) { http_response_code(500); echo json_encode(['error' => 'DB-Verbindung fehlgeschlagen.']); exit; } $sql = " SELECT s.id, s.norad_cat_id, s.object_name, s.object_id, s.classification_type, us.is_favorite, t.epoch, t.mean_motion, t.eccentricity, t.inclination, t.ra_of_asc_node, t.arg_of_pericenter, t.mean_anomaly, t.ephemeris_type, t.element_set_no, t.rev_at_epoch, t.bstar, t.mean_motion_dot, t.mean_motion_ddot FROM app_user_satellites us INNER JOIN sat_satellites s ON s.id = us.satellite_id INNER JOIN sat_tle_current t ON t.satellite_id = s.id WHERE us.user_id = :user_id AND t.epoch IS NOT NULL AND t.mean_motion IS NOT NULL "; $params = [':user_id' => $userId]; if ($requestedIds !== []) { $idPlaceholders = []; foreach ($requestedIds as $index => $noradId) { $placeholder = ':norad_' . $index; $idPlaceholders[] = $placeholder; $params[$placeholder] = $noradId; } $sql .= ' AND s.norad_cat_id IN (' . implode(', ', $idPlaceholders) . ')'; } $sql .= ' ORDER BY us.is_favorite DESC, s.object_name ASC'; try { $stmt = $pdo->prepare($sql); $stmt->execute($params); $rows = $stmt->fetchAll(); } catch (PDOException $e) { http_response_code(500); echo json_encode(['error' => 'Abfrage fehlgeschlagen.']); exit; } $result = []; foreach ($rows as $row) { $result[] = [ 'id' => (int)$row['id'], 'norad_cat_id' => (int)$row['norad_cat_id'], 'object_name' => (string)$row['object_name'], 'object_id' => $row['object_id'] !== null ? (string)$row['object_id'] : null, 'classification_type' => $row['classification_type'] !== null ? (string)$row['classification_type'] : null, 'is_favorite' => (int)($row['is_favorite'] ?? 0) === 1, 'epoch' => (string)$row['epoch'], 'mean_motion' => (float)$row['mean_motion'], 'eccentricity' => (float)$row['eccentricity'], 'inclination' => (float)$row['inclination'], 'ra_of_asc_node' => (float)$row['ra_of_asc_node'], 'arg_of_pericenter' => (float)$row['arg_of_pericenter'], 'mean_anomaly' => (float)$row['mean_anomaly'], 'ephemeris_type' => (int)$row['ephemeris_type'], 'element_set_no' => (int)$row['element_set_no'], 'rev_at_epoch' => (int)$row['rev_at_epoch'], 'bstar' => (float)$row['bstar'], 'mean_motion_dot' => (float)$row['mean_motion_dot'], 'mean_motion_ddot' => (float)$row['mean_motion_ddot'], 'tle_line1' => buildLine1($row, $row), 'tle_line2' => buildLine2($row, $row), ]; } echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);