226 lines
6.7 KiB
PHP
226 lines
6.7 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
session_start();
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Cache-Control: no-store');
|
|
|
|
function tleChecksum(string $line): int {
|
|
$sum = 0;
|
|
for ($i = 0; $i < 68; $i++) {
|
|
$c = $line[$i];
|
|
if (ctype_digit($c)) {
|
|
$sum += (int)$c;
|
|
} elseif ($c === '-') {
|
|
$sum += 1;
|
|
}
|
|
}
|
|
return $sum % 10;
|
|
}
|
|
|
|
function tleExp(float $val): string {
|
|
if (abs($val) < 1e-99) {
|
|
return ' 00000-0';
|
|
}
|
|
|
|
$sign = $val >= 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);
|