PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); function normalizeHeader(string $value): string { $value = trim($value); $value = strtolower($value); $map = [ ' - ' => '_', '-' => '_', ' ' => '_', '(' => '', ')' => '', '.' => '', '/' => '_', ]; $value = strtr($value, $map); $value = preg_replace('/[^a-z0-9_]+/', '', $value); $value = preg_replace('/_+/', '_', $value); return trim((string)$value, '_'); } function nullIfEmpty(mixed $value): mixed { if ($value === null) { return null; } if (is_string($value)) { $value = trim($value); return $value === '' ? null : $value; } return $value; } function toNullableString(mixed $value): ?string { $value = nullIfEmpty($value); return $value === null ? null : (string)$value; } function toNullableFloat(mixed $value): ?float { $value = nullIfEmpty($value); if ($value === null) { return null; } $value = str_replace(',', '.', (string)$value); return is_numeric($value) ? (float)$value : null; } function hmsToDegrees(?string $ra): ?float { $ra = toNullableString($ra); if ($ra === null) { return null; } if (!preg_match('/^\s*(\d{1,2}):(\d{1,2}):(\d{1,2}(?:\.\d+)?)\s*$/', $ra, $m)) { return null; } $hours = (float)$m[1]; $minutes = (float)$m[2]; $seconds = (float)$m[3]; $hoursDecimal = $hours + ($minutes / 60.0) + ($seconds / 3600.0); return $hoursDecimal * 15.0; } function dmsToDegrees(?string $dec): ?float { $dec = toNullableString($dec); if ($dec === null) { return null; } if (!preg_match('/^\s*([+\-]?)(\d{1,2}):(\d{1,2}):(\d{1,2}(?:\.\d+)?)\s*$/', $dec, $m)) { return null; } $sign = ($m[1] === '-') ? -1.0 : 1.0; $degrees = (float)$m[2]; $minutes = (float)$m[3]; $seconds = (float)$m[4]; $value = $degrees + ($minutes / 60.0) + ($seconds / 3600.0); return $sign * $value; } if (!is_file($csvFile)) { exit("CSV-Datei nicht gefunden: {$csvFile}\n"); } $handle = fopen($csvFile, 'r'); if ($handle === false) { exit("CSV-Datei konnte nicht geöffnet werden: {$csvFile}\n"); } $header = fgetcsv($handle, 0, ';', '"', ''); if ($header === false) { fclose($handle); exit("CSV-Datei ist leer oder ungültig.\n"); } $header = array_map( static fn($value) => normalizeHeader((string)$value), $header ); $sql = " INSERT INTO `dso_objects` ( `catalog_group`, `name`, `messier`, `ngc`, `ic`, `object_type_abrev`, `object_type`, `ra`, `dec`, `ra_deg`, `dec_deg`, `constellation`, `major_axis`, `minor_axis`, `position_angle`, `b_mag`, `v_mag`, `j_mag`, `h_mag`, `k_mag`, `surface_brightness`, `hubble_type`, `cstar_u_mag`, `cstar_b_mag`, `cstar_v_mag`, `cstar_names`, `identifiers`, `common_names`, `ned_notes`, `openngc_notes`, `image`, `created_at`, `updated_at` ) VALUES ( :catalog_group, :name, :messier, :ngc, :ic, :object_type_abrev, :object_type, :ra, :dec, :ra_deg, :dec_deg, :constellation, :major_axis, :minor_axis, :position_angle, :b_mag, :v_mag, :j_mag, :h_mag, :k_mag, :surface_brightness, :hubble_type, :cstar_u_mag, :cstar_b_mag, :cstar_v_mag, :cstar_names, :identifiers, :common_names, :ned_notes, :openngc_notes, :image, NOW(), NOW() ) ON DUPLICATE KEY UPDATE `catalog_group` = VALUES(`catalog_group`), `messier` = VALUES(`messier`), `ngc` = VALUES(`ngc`), `ic` = VALUES(`ic`), `object_type_abrev` = VALUES(`object_type_abrev`), `object_type` = VALUES(`object_type`), `ra` = VALUES(`ra`), `dec` = VALUES(`dec`), `ra_deg` = VALUES(`ra_deg`), `dec_deg` = VALUES(`dec_deg`), `constellation` = VALUES(`constellation`), `major_axis` = VALUES(`major_axis`), `minor_axis` = VALUES(`minor_axis`), `position_angle` = VALUES(`position_angle`), `b_mag` = VALUES(`b_mag`), `v_mag` = VALUES(`v_mag`), `j_mag` = VALUES(`j_mag`), `h_mag` = VALUES(`h_mag`), `k_mag` = VALUES(`k_mag`), `surface_brightness` = VALUES(`surface_brightness`), `hubble_type` = VALUES(`hubble_type`), `cstar_u_mag` = VALUES(`cstar_u_mag`), `cstar_b_mag` = VALUES(`cstar_b_mag`), `cstar_v_mag` = VALUES(`cstar_v_mag`), `cstar_names` = VALUES(`cstar_names`), `identifiers` = VALUES(`identifiers`), `common_names` = VALUES(`common_names`), `ned_notes` = VALUES(`ned_notes`), `openngc_notes` = VALUES(`openngc_notes`), `image` = VALUES(`image`), `updated_at` = NOW() "; $stmt = $pdo->prepare($sql); $rowCount = 0; $imported = 0; $skipped = 0; $pdo->beginTransaction(); try { while (($row = fgetcsv($handle, 0, ';', '"', '')) !== false) { $rowCount++; if ($row === [null] || $row === false) { continue; } if (count($row) !== count($header)) { $skipped++; continue; } $data = array_combine($header, $row); if ($data === false) { $skipped++; continue; } $name = toNullableString($data['name'] ?? null); if ($name === null) { $skipped++; continue; } $ra = toNullableString($data['ra'] ?? null); $dec = toNullableString($data['dec'] ?? null); $stmt->execute([ ':catalog_group' => toNullableString($data['ic_ngc'] ?? null), ':name' => $name, ':messier' => toNullableString($data['messier'] ?? null), ':ngc' => toNullableString($data['ngc'] ?? null), ':ic' => toNullableString($data['ic'] ?? null), ':object_type_abrev' => toNullableString($data['object_type_abrev'] ?? null), ':object_type' => toNullableString($data['object_type'] ?? null), ':ra' => $ra, ':dec' => $dec, ':ra_deg' => hmsToDegrees($ra), ':dec_deg' => dmsToDegrees($dec), ':constellation' => toNullableString($data['constellation'] ?? null), ':major_axis' => toNullableFloat($data['major_axis'] ?? null), ':minor_axis' => toNullableFloat($data['minor_axis'] ?? null), ':position_angle' => toNullableFloat($data['position_angle'] ?? null), ':b_mag' => toNullableFloat($data['b_mag'] ?? null), ':v_mag' => toNullableFloat($data['v_mag'] ?? null), ':j_mag' => toNullableFloat($data['j_mag'] ?? null), ':h_mag' => toNullableFloat($data['h_mag'] ?? null), ':k_mag' => toNullableFloat($data['k_mag'] ?? null), ':surface_brightness' => toNullableFloat($data['surface_brigthness'] ?? null), ':hubble_type' => toNullableString($data['hubble_only_galaxies'] ?? null), ':cstar_u_mag' => toNullableFloat($data['cstar_u_mag_only_planetary_nebulae'] ?? null), ':cstar_b_mag' => toNullableFloat($data['cstar_b_mag_only_planetary_nebulae'] ?? null), ':cstar_v_mag' => toNullableFloat($data['cstar_v_mag_only_planetary_nebulae'] ?? null), ':cstar_names' => toNullableString($data['cstar_names_only_planetary_nebulae'] ?? null), ':identifiers' => toNullableString($data['identifiers'] ?? null), ':common_names' => toNullableString($data['common_names'] ?? null), ':ned_notes' => toNullableString($data['ned_notes'] ?? null), ':openngc_notes' => toNullableString($data['openngc_notes'] ?? null), ':image' => toNullableString($data['image'] ?? null), ]); $imported++; } $pdo->commit(); } catch (Throwable $e) { $pdo->rollBack(); fclose($handle); exit("Fehler beim Import: " . $e->getMessage() . "\n"); } fclose($handle); echo "Deep-Sky-Import abgeschlossen\n"; echo "Verarbeitete Zeilen: {$rowCount}\n"; echo "Importiert/Aktualisiert: {$imported}\n"; echo "Übersprungen: {$skipped}\n";