first commit
This commit is contained in:
@@ -0,0 +1,597 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
error_reporting(E_ALL);
|
||||
session_start();
|
||||
|
||||
$loggedIn = isset($_SESSION['user_id']);
|
||||
$pageTitle = 'Krater-Import - AstroTools';
|
||||
$bodyClass = 'admin-page';
|
||||
|
||||
function h(string $value): string
|
||||
{
|
||||
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
function normalizeImportValue(?string $value): ?string
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
if ($value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = str_replace(["\xC2\xA0", "\u{00A0}"], ' ', $value);
|
||||
|
||||
if (function_exists('mb_check_encoding') && !mb_check_encoding($value, 'UTF-8')) {
|
||||
$converted = @mb_convert_encoding($value, 'UTF-8', 'Windows-1252,ISO-8859-1,UTF-8');
|
||||
if (is_string($converted) && $converted !== '') {
|
||||
$value = $converted;
|
||||
}
|
||||
}
|
||||
|
||||
return trim($value);
|
||||
}
|
||||
|
||||
function parseNullableFloat(?string $value): ?float
|
||||
{
|
||||
$value = normalizeImportValue($value);
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = str_replace(',', '.', $value);
|
||||
return is_numeric($value) ? (float)$value : null;
|
||||
}
|
||||
|
||||
function parseNullableInt(?string $value): ?int
|
||||
{
|
||||
$value = normalizeImportValue($value);
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return preg_match('/^-?\d+$/', $value) ? (int)$value : null;
|
||||
}
|
||||
|
||||
function parseNullableDate(?string $value): ?string
|
||||
{
|
||||
$value = normalizeImportValue($value);
|
||||
if ($value === null || stripos($value, 'not') !== false || $value === '?') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$formats = ['d/m/Y H:i:s', 'd/m/Y', 'Y-m-d H:i:s', 'Y-m-d'];
|
||||
foreach ($formats as $format) {
|
||||
$dt = DateTimeImmutable::createFromFormat($format, $value);
|
||||
if ($dt instanceof DateTimeImmutable) {
|
||||
return $dt->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function translateCatalogValue(string $field, ?string $value): ?string
|
||||
{
|
||||
$value = normalizeImportValue($value);
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static $maps = [
|
||||
'iau_type' => [
|
||||
'Crater' => 'Krater',
|
||||
],
|
||||
'type' => [
|
||||
'Crater' => 'Krater',
|
||||
],
|
||||
'subtype' => [
|
||||
'Not determined' => 'Nicht bestimmt',
|
||||
],
|
||||
'process' => [
|
||||
'Meteoritic impact' => 'Meteoriteneinschlag',
|
||||
],
|
||||
'period' => [
|
||||
'Formation period not found' => 'Entstehungszeit nicht bekannt',
|
||||
'Pre-Nectarian (From -4.55 billions years to -3.92 billions years)' => 'Prä-Nektarisch (von -4,55 bis -3,92 Milliarden Jahre)',
|
||||
'Nectarian (From -3.92 billions years to -3.85 billions years)' => 'Nektarisch (von -3,92 bis -3,85 Milliarden Jahre)',
|
||||
'Imbrian (From -3.85 billions years to -3.2 billions years) ?' => 'Imbrisch (von -3,85 bis -3,2 Milliarden Jahre)?',
|
||||
],
|
||||
'geology' => [
|
||||
'No details' => 'Keine Details',
|
||||
],
|
||||
'country' => [
|
||||
'Germany' => 'Deutschland',
|
||||
'Norway' => 'Norwegen',
|
||||
'U. S. A.' => 'USA',
|
||||
'Not appliable' => 'Nicht anwendbar',
|
||||
],
|
||||
'nationality' => [
|
||||
'German' => 'Deutsch',
|
||||
'Norwegian' => 'Norwegisch',
|
||||
'American' => 'Amerikanisch',
|
||||
'Not appliable' => 'Nicht anwendbar',
|
||||
],
|
||||
'face' => [
|
||||
'Nearside' => 'Vorderseite',
|
||||
'Farside' => 'Rückseite',
|
||||
'Librations zone' => 'Librationszone',
|
||||
],
|
||||
'quadrant' => [
|
||||
'North-East' => 'Nordost',
|
||||
'South-East' => 'Südost',
|
||||
'North-West' => 'Nordwest',
|
||||
'South-West' => 'Südwest',
|
||||
],
|
||||
'interest_c' => [
|
||||
'Low interest or difficult formation' => 'Geringes Interesse oder schwer beobachtbar',
|
||||
'Pretty interesting formation' => 'Ziemlich interessante Formation',
|
||||
'Not observable' => 'Nicht beobachtbar',
|
||||
],
|
||||
'moonday_s' => [
|
||||
'Not observable' => 'Nicht beobachtbar',
|
||||
'3 days after New Moon' => '3 Tage nach Neumond',
|
||||
'2 days after New Moon' => '2 Tage nach Neumond',
|
||||
],
|
||||
'moonday_m' => [
|
||||
'Not observable' => 'Nicht beobachtbar',
|
||||
'2 days after Full Moon' => '2 Tage nach Vollmond',
|
||||
'1 day after Full Moon' => '1 Tag nach Vollmond',
|
||||
],
|
||||
'diam_inst' => [
|
||||
'Not observable' => 'Nicht beobachtbar',
|
||||
'Naked eye' => 'Mit bloßem Auge',
|
||||
],
|
||||
'th_instru' => [
|
||||
'Not observable' => 'Nicht beobachtbar',
|
||||
'50 mm refractor' => '50-mm-Refraktor',
|
||||
'10x binoculars' => '10x-Fernglas',
|
||||
],
|
||||
'pr_instru' => [
|
||||
'Not observable' => 'Nicht beobachtbar',
|
||||
'100 mm refractor' => '100-mm-Refraktor',
|
||||
'10x binoculars' => '10x-Fernglas',
|
||||
],
|
||||
];
|
||||
|
||||
return $maps[$field][$value] ?? $value;
|
||||
}
|
||||
|
||||
function createMoonCraterTableSql(): string
|
||||
{
|
||||
return "CREATE TABLE moon_craters (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
lun VARCHAR(64) DEFAULT NULL,
|
||||
name_type VARCHAR(255) DEFAULT NULL,
|
||||
iau_type VARCHAR(100) DEFAULT NULL,
|
||||
iau_type_de VARCHAR(100) DEFAULT NULL,
|
||||
type VARCHAR(100) DEFAULT NULL,
|
||||
type_de VARCHAR(100) DEFAULT NULL,
|
||||
subtype VARCHAR(150) DEFAULT NULL,
|
||||
subtype_de VARCHAR(150) DEFAULT NULL,
|
||||
process VARCHAR(150) DEFAULT NULL,
|
||||
process_de VARCHAR(150) DEFAULT NULL,
|
||||
period VARCHAR(255) DEFAULT NULL,
|
||||
period_de VARCHAR(255) DEFAULT NULL,
|
||||
period_source TEXT DEFAULT NULL,
|
||||
geology VARCHAR(255) DEFAULT NULL,
|
||||
geology_de VARCHAR(255) DEFAULT NULL,
|
||||
name_detail VARCHAR(255) DEFAULT NULL,
|
||||
name_origin VARCHAR(255) DEFAULT NULL,
|
||||
iau_approval_date DATE DEFAULT NULL,
|
||||
langrenus VARCHAR(255) DEFAULT NULL,
|
||||
hevelius VARCHAR(255) DEFAULT NULL,
|
||||
riccioli VARCHAR(255) DEFAULT NULL,
|
||||
work VARCHAR(255) DEFAULT NULL,
|
||||
country VARCHAR(255) DEFAULT NULL,
|
||||
country_de VARCHAR(255) DEFAULT NULL,
|
||||
nationality VARCHAR(255) DEFAULT NULL,
|
||||
nationality_de VARCHAR(255) DEFAULT NULL,
|
||||
century_n VARCHAR(50) DEFAULT NULL,
|
||||
century_c VARCHAR(50) DEFAULT NULL,
|
||||
birth_place VARCHAR(255) DEFAULT NULL,
|
||||
birth_date VARCHAR(100) DEFAULT NULL,
|
||||
death_place VARCHAR(255) DEFAULT NULL,
|
||||
death_date VARCHAR(100) DEFAULT NULL,
|
||||
facts TEXT DEFAULT NULL,
|
||||
longi_n DECIMAL(10,6) DEFAULT NULL,
|
||||
longi_n_360 DECIMAL(10,6) DEFAULT NULL,
|
||||
longi_c VARCHAR(255) DEFAULT NULL,
|
||||
lati_n DECIMAL(10,6) DEFAULT NULL,
|
||||
lati_c VARCHAR(255) DEFAULT NULL,
|
||||
face VARCHAR(100) DEFAULT NULL,
|
||||
face_de VARCHAR(100) DEFAULT NULL,
|
||||
quadrant VARCHAR(100) DEFAULT NULL,
|
||||
quadrant_de VARCHAR(100) DEFAULT NULL,
|
||||
area VARCHAR(255) DEFAULT NULL,
|
||||
length_km DECIMAL(10,3) DEFAULT NULL,
|
||||
wide_km DECIMAL(10,3) DEFAULT NULL,
|
||||
length_arcsec DECIMAL(10,3) DEFAULT NULL,
|
||||
height_m VARCHAR(255) DEFAULT NULL,
|
||||
rapport VARCHAR(255) DEFAULT NULL,
|
||||
general_1 TEXT DEFAULT NULL,
|
||||
general_2 TEXT DEFAULT NULL,
|
||||
slopes TEXT DEFAULT NULL,
|
||||
walls TEXT DEFAULT NULL,
|
||||
floor TEXT DEFAULT NULL,
|
||||
interest_n INT DEFAULT NULL,
|
||||
interest_c VARCHAR(255) DEFAULT NULL,
|
||||
interest_c_de VARCHAR(255) DEFAULT NULL,
|
||||
lunation VARCHAR(100) DEFAULT NULL,
|
||||
moonday_s VARCHAR(255) DEFAULT NULL,
|
||||
moonday_s_de VARCHAR(255) DEFAULT NULL,
|
||||
moonday_m VARCHAR(255) DEFAULT NULL,
|
||||
moonday_m_de VARCHAR(255) DEFAULT NULL,
|
||||
diam_inst VARCHAR(255) DEFAULT NULL,
|
||||
diam_inst_de VARCHAR(255) DEFAULT NULL,
|
||||
th_instru VARCHAR(255) DEFAULT NULL,
|
||||
th_instru_de VARCHAR(255) DEFAULT NULL,
|
||||
pr_instru VARCHAR(255) DEFAULT NULL,
|
||||
pr_instru_de VARCHAR(255) DEFAULT NULL,
|
||||
source_row_json JSON DEFAULT NULL,
|
||||
imported_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uniq_lun (lun),
|
||||
KEY idx_name (name),
|
||||
KEY idx_type (type),
|
||||
KEY idx_face (face),
|
||||
KEY idx_quadrant (quadrant),
|
||||
KEY idx_longi_n_360 (longi_n_360),
|
||||
KEY idx_lati_n (lati_n)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
|
||||
}
|
||||
|
||||
function ensureMoonCraterTable(PDO $pdo): void
|
||||
{
|
||||
$tableExists = (bool)$pdo->query("SHOW TABLES LIKE 'moon_craters'")->fetchColumn();
|
||||
|
||||
if (!$tableExists) {
|
||||
$pdo->exec(createMoonCraterTableSql());
|
||||
return;
|
||||
}
|
||||
|
||||
$columns = [];
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM moon_craters");
|
||||
foreach ($stmt->fetchAll() as $row) {
|
||||
$columns[] = (string)($row['Field'] ?? '');
|
||||
}
|
||||
|
||||
$requiredColumns = ['name', 'lun', 'iau_type', 'type', 'longi_n_360', 'lati_n'];
|
||||
$missingColumns = array_values(array_diff($requiredColumns, $columns));
|
||||
|
||||
if ($missingColumns === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$backupTable = 'moon_craters_backup_' . date('Ymd_His');
|
||||
$pdo->exec("RENAME TABLE moon_craters TO `" . $backupTable . "`");
|
||||
$pdo->exec(createMoonCraterTableSql());
|
||||
}
|
||||
|
||||
$report = null;
|
||||
$defaultCsv = 'C:\Users\ich\Downloads\01_IAU_NAMED_EN.csv';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$csvPath = trim((string)($_POST['csv_path'] ?? $defaultCsv));
|
||||
$truncateFirst = isset($_POST['truncate_first']) && (string)$_POST['truncate_first'] === '1';
|
||||
$uploadedLabel = null;
|
||||
|
||||
try {
|
||||
if (
|
||||
isset($_FILES['csv_upload']) &&
|
||||
is_array($_FILES['csv_upload']) &&
|
||||
(int)($_FILES['csv_upload']['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE
|
||||
) {
|
||||
$uploadError = (int)($_FILES['csv_upload']['error'] ?? UPLOAD_ERR_OK);
|
||||
if ($uploadError !== UPLOAD_ERR_OK) {
|
||||
throw new RuntimeException('Datei-Upload fehlgeschlagen. Fehlercode: ' . $uploadError);
|
||||
}
|
||||
|
||||
$tmpName = (string)($_FILES['csv_upload']['tmp_name'] ?? '');
|
||||
if ($tmpName === '' || !is_uploaded_file($tmpName)) {
|
||||
throw new RuntimeException('Die hochgeladene Datei ist ungueltig.');
|
||||
}
|
||||
|
||||
$csvPath = $tmpName;
|
||||
$uploadedLabel = (string)($_FILES['csv_upload']['name'] ?? 'hochgeladene Datei');
|
||||
}
|
||||
|
||||
if (!is_file($csvPath)) {
|
||||
throw new RuntimeException('CSV-Datei nicht gefunden: ' . $csvPath);
|
||||
}
|
||||
|
||||
$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,
|
||||
]
|
||||
);
|
||||
|
||||
ensureMoonCraterTable($pdo);
|
||||
|
||||
if ($truncateFirst) {
|
||||
$pdo->exec('TRUNCATE TABLE moon_craters');
|
||||
}
|
||||
|
||||
$handle = fopen($csvPath, 'rb');
|
||||
if ($handle === false) {
|
||||
throw new RuntimeException('CSV-Datei konnte nicht geöffnet werden.');
|
||||
}
|
||||
|
||||
$headers = fgetcsv($handle, 0, ';', '"', '\\');
|
||||
if (!is_array($headers)) {
|
||||
throw new RuntimeException('CSV-Kopfzeile konnte nicht gelesen werden.');
|
||||
}
|
||||
|
||||
$headers = array_map(static fn($value) => strtoupper((string)$value), $headers);
|
||||
|
||||
$insertSql = "INSERT INTO moon_craters (
|
||||
name, lun, name_type, iau_type, iau_type_de, type, type_de, subtype, subtype_de,
|
||||
process, process_de, period, period_de, period_source, geology, geology_de,
|
||||
name_detail, name_origin, iau_approval_date, langrenus, hevelius, riccioli, work,
|
||||
country, country_de, nationality, nationality_de, century_n, century_c, birth_place,
|
||||
birth_date, death_place, death_date, facts, longi_n, longi_n_360, longi_c, lati_n,
|
||||
lati_c, face, face_de, quadrant, quadrant_de, area, length_km, wide_km, length_arcsec,
|
||||
height_m, rapport, general_1, general_2, slopes, walls, floor, interest_n, interest_c,
|
||||
interest_c_de, lunation, moonday_s, moonday_s_de, moonday_m, moonday_m_de, diam_inst,
|
||||
diam_inst_de, th_instru, th_instru_de, pr_instru, pr_instru_de, source_row_json
|
||||
) VALUES (
|
||||
:name, :lun, :name_type, :iau_type, :iau_type_de, :type, :type_de, :subtype, :subtype_de,
|
||||
:process, :process_de, :period, :period_de, :period_source, :geology, :geology_de,
|
||||
:name_detail, :name_origin, :iau_approval_date, :langrenus, :hevelius, :riccioli, :work,
|
||||
:country, :country_de, :nationality, :nationality_de, :century_n, :century_c, :birth_place,
|
||||
:birth_date, :death_place, :death_date, :facts, :longi_n, :longi_n_360, :longi_c, :lati_n,
|
||||
:lati_c, :face, :face_de, :quadrant, :quadrant_de, :area, :length_km, :wide_km, :length_arcsec,
|
||||
:height_m, :rapport, :general_1, :general_2, :slopes, :walls, :floor, :interest_n, :interest_c,
|
||||
:interest_c_de, :lunation, :moonday_s, :moonday_s_de, :moonday_m, :moonday_m_de, :diam_inst,
|
||||
:diam_inst_de, :th_instru, :th_instru_de, :pr_instru, :pr_instru_de, :source_row_json
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
name_type = VALUES(name_type),
|
||||
iau_type = VALUES(iau_type),
|
||||
iau_type_de = VALUES(iau_type_de),
|
||||
type = VALUES(type),
|
||||
type_de = VALUES(type_de),
|
||||
subtype = VALUES(subtype),
|
||||
subtype_de = VALUES(subtype_de),
|
||||
process = VALUES(process),
|
||||
process_de = VALUES(process_de),
|
||||
period = VALUES(period),
|
||||
period_de = VALUES(period_de),
|
||||
period_source = VALUES(period_source),
|
||||
geology = VALUES(geology),
|
||||
geology_de = VALUES(geology_de),
|
||||
name_detail = VALUES(name_detail),
|
||||
name_origin = VALUES(name_origin),
|
||||
iau_approval_date = VALUES(iau_approval_date),
|
||||
langrenus = VALUES(langrenus),
|
||||
hevelius = VALUES(hevelius),
|
||||
riccioli = VALUES(riccioli),
|
||||
work = VALUES(work),
|
||||
country = VALUES(country),
|
||||
country_de = VALUES(country_de),
|
||||
nationality = VALUES(nationality),
|
||||
nationality_de = VALUES(nationality_de),
|
||||
century_n = VALUES(century_n),
|
||||
century_c = VALUES(century_c),
|
||||
birth_place = VALUES(birth_place),
|
||||
birth_date = VALUES(birth_date),
|
||||
death_place = VALUES(death_place),
|
||||
death_date = VALUES(death_date),
|
||||
facts = VALUES(facts),
|
||||
longi_n = VALUES(longi_n),
|
||||
longi_n_360 = VALUES(longi_n_360),
|
||||
longi_c = VALUES(longi_c),
|
||||
lati_n = VALUES(lati_n),
|
||||
lati_c = VALUES(lati_c),
|
||||
face = VALUES(face),
|
||||
face_de = VALUES(face_de),
|
||||
quadrant = VALUES(quadrant),
|
||||
quadrant_de = VALUES(quadrant_de),
|
||||
area = VALUES(area),
|
||||
length_km = VALUES(length_km),
|
||||
wide_km = VALUES(wide_km),
|
||||
length_arcsec = VALUES(length_arcsec),
|
||||
height_m = VALUES(height_m),
|
||||
rapport = VALUES(rapport),
|
||||
general_1 = VALUES(general_1),
|
||||
general_2 = VALUES(general_2),
|
||||
slopes = VALUES(slopes),
|
||||
walls = VALUES(walls),
|
||||
floor = VALUES(floor),
|
||||
interest_n = VALUES(interest_n),
|
||||
interest_c = VALUES(interest_c),
|
||||
interest_c_de = VALUES(interest_c_de),
|
||||
lunation = VALUES(lunation),
|
||||
moonday_s = VALUES(moonday_s),
|
||||
moonday_s_de = VALUES(moonday_s_de),
|
||||
moonday_m = VALUES(moonday_m),
|
||||
moonday_m_de = VALUES(moonday_m_de),
|
||||
diam_inst = VALUES(diam_inst),
|
||||
diam_inst_de = VALUES(diam_inst_de),
|
||||
th_instru = VALUES(th_instru),
|
||||
th_instru_de = VALUES(th_instru_de),
|
||||
pr_instru = VALUES(pr_instru),
|
||||
pr_instru_de = VALUES(pr_instru_de),
|
||||
source_row_json = VALUES(source_row_json)";
|
||||
|
||||
$stmt = $pdo->prepare($insertSql);
|
||||
$imported = 0;
|
||||
$skipped = 0;
|
||||
|
||||
while (($row = fgetcsv($handle, 0, ';', '"', '\\')) !== false) {
|
||||
if ($row === [null] || $row === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$assoc = [];
|
||||
foreach ($headers as $index => $header) {
|
||||
$assoc[$header] = $row[$index] ?? null;
|
||||
}
|
||||
|
||||
$name = normalizeImportValue($assoc['NAME'] ?? null);
|
||||
if ($name === null) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'name' => $name,
|
||||
'lun' => normalizeImportValue($assoc['LUN'] ?? null),
|
||||
'name_type' => normalizeImportValue($assoc['NAME_TYPE'] ?? null),
|
||||
'iau_type' => normalizeImportValue($assoc['IAU_TYPE'] ?? null),
|
||||
'iau_type_de' => translateCatalogValue('iau_type', $assoc['IAU_TYPE'] ?? null),
|
||||
'type' => normalizeImportValue($assoc['TYPE'] ?? null),
|
||||
'type_de' => translateCatalogValue('type', $assoc['TYPE'] ?? null),
|
||||
'subtype' => normalizeImportValue($assoc['SUBTYPE'] ?? null),
|
||||
'subtype_de' => translateCatalogValue('subtype', $assoc['SUBTYPE'] ?? null),
|
||||
'process' => normalizeImportValue($assoc['PROCESS'] ?? null),
|
||||
'process_de' => translateCatalogValue('process', $assoc['PROCESS'] ?? null),
|
||||
'period' => normalizeImportValue($assoc['PERIOD'] ?? null),
|
||||
'period_de' => translateCatalogValue('period', $assoc['PERIOD'] ?? null),
|
||||
'period_source' => normalizeImportValue($assoc['PERIOD_SOURCE'] ?? null),
|
||||
'geology' => normalizeImportValue($assoc['GEOLOGY'] ?? null),
|
||||
'geology_de' => translateCatalogValue('geology', $assoc['GEOLOGY'] ?? null),
|
||||
'name_detail' => normalizeImportValue($assoc['NAME_DETAIL'] ?? null),
|
||||
'name_origin' => normalizeImportValue($assoc['NAME_ORIGIN'] ?? null),
|
||||
'iau_approval_date' => parseNullableDate($assoc['IAU_APPROVAL'] ?? null),
|
||||
'langrenus' => normalizeImportValue($assoc['LANGRENUS'] ?? null),
|
||||
'hevelius' => normalizeImportValue($assoc['HEVELIUS'] ?? null),
|
||||
'riccioli' => normalizeImportValue($assoc['RICCIOLI'] ?? null),
|
||||
'work' => normalizeImportValue($assoc['WORK'] ?? null),
|
||||
'country' => normalizeImportValue($assoc['COUNTRY'] ?? null),
|
||||
'country_de' => translateCatalogValue('country', $assoc['COUNTRY'] ?? null),
|
||||
'nationality' => normalizeImportValue($assoc['NATIONLITY'] ?? null),
|
||||
'nationality_de' => translateCatalogValue('nationality', $assoc['NATIONLITY'] ?? null),
|
||||
'century_n' => normalizeImportValue($assoc['CENTURY_N'] ?? null),
|
||||
'century_c' => normalizeImportValue($assoc['CENTURY_C'] ?? null),
|
||||
'birth_place' => normalizeImportValue($assoc['BIRTH_PLACE'] ?? null),
|
||||
'birth_date' => normalizeImportValue($assoc['BIRTH_DATE'] ?? null),
|
||||
'death_place' => normalizeImportValue($assoc['DEATH_PLACE'] ?? null),
|
||||
'death_date' => normalizeImportValue($assoc['DEATH_DATE'] ?? null),
|
||||
'facts' => normalizeImportValue($assoc['FACTS'] ?? null),
|
||||
'longi_n' => parseNullableFloat($assoc['LONGI_N'] ?? null),
|
||||
'longi_n_360' => parseNullableFloat($assoc['LONGI_N_360'] ?? null),
|
||||
'longi_c' => normalizeImportValue($assoc['LONGI_C'] ?? null),
|
||||
'lati_n' => parseNullableFloat($assoc['LATI_N'] ?? null),
|
||||
'lati_c' => normalizeImportValue($assoc['LATI_C'] ?? null),
|
||||
'face' => normalizeImportValue($assoc['FACE'] ?? null),
|
||||
'face_de' => translateCatalogValue('face', $assoc['FACE'] ?? null),
|
||||
'quadrant' => normalizeImportValue($assoc['QUADRANT'] ?? null),
|
||||
'quadrant_de' => translateCatalogValue('quadrant', $assoc['QUADRANT'] ?? null),
|
||||
'area' => normalizeImportValue($assoc['AREA'] ?? null),
|
||||
'length_km' => parseNullableFloat($assoc['LENGTH_KM'] ?? null),
|
||||
'wide_km' => parseNullableFloat($assoc['WIDE_KM'] ?? null),
|
||||
'length_arcsec' => parseNullableFloat($assoc['LENGTH_ARCSEC'] ?? null),
|
||||
'height_m' => normalizeImportValue($assoc['HEIGHT_M'] ?? null),
|
||||
'rapport' => normalizeImportValue($assoc['RAPPORT'] ?? null),
|
||||
'general_1' => normalizeImportValue($assoc['GENERAL_1'] ?? null),
|
||||
'general_2' => normalizeImportValue($assoc['GENERAL_2'] ?? null),
|
||||
'slopes' => normalizeImportValue($assoc['SLOPES'] ?? null),
|
||||
'walls' => normalizeImportValue($assoc['WALLS'] ?? null),
|
||||
'floor' => normalizeImportValue($assoc['FLOOR'] ?? null),
|
||||
'interest_n' => parseNullableInt($assoc['INTEREST_N'] ?? null),
|
||||
'interest_c' => normalizeImportValue($assoc['INTEREST_C'] ?? null),
|
||||
'interest_c_de' => translateCatalogValue('interest_c', $assoc['INTEREST_C'] ?? null),
|
||||
'lunation' => normalizeImportValue($assoc['LUNATION'] ?? null),
|
||||
'moonday_s' => normalizeImportValue($assoc['MOONDAY_S'] ?? null),
|
||||
'moonday_s_de' => translateCatalogValue('moonday_s', $assoc['MOONDAY_S'] ?? null),
|
||||
'moonday_m' => normalizeImportValue($assoc['MOONDAY_M'] ?? null),
|
||||
'moonday_m_de' => translateCatalogValue('moonday_m', $assoc['MOONDAY_M'] ?? null),
|
||||
'diam_inst' => normalizeImportValue($assoc['DIAM_INST'] ?? null),
|
||||
'diam_inst_de' => translateCatalogValue('diam_inst', $assoc['DIAM_INST'] ?? null),
|
||||
'th_instru' => normalizeImportValue($assoc['TH_INSTRU'] ?? null),
|
||||
'th_instru_de' => translateCatalogValue('th_instru', $assoc['TH_INSTRU'] ?? null),
|
||||
'pr_instru' => normalizeImportValue($assoc['PR_INSTRU'] ?? null),
|
||||
'pr_instru_de' => translateCatalogValue('pr_instru', $assoc['PR_INSTRU'] ?? null),
|
||||
'source_row_json' => json_encode($assoc, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
];
|
||||
|
||||
$stmt->execute($payload);
|
||||
$imported++;
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
$report = [
|
||||
'ok' => true,
|
||||
'csv_path' => $csvPath,
|
||||
'csv_label' => $uploadedLabel ?? $csvPath,
|
||||
'imported' => $imported,
|
||||
'skipped' => $skipped,
|
||||
'truncate_first' => $truncateFirst,
|
||||
];
|
||||
} catch (Throwable $exception) {
|
||||
$report = [
|
||||
'ok' => false,
|
||||
'error' => $exception->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
require __DIR__ . '/../../public/header.php';
|
||||
?>
|
||||
|
||||
<div class="container" style="max-width: 980px;">
|
||||
<section class="card" style="margin-top: 1.25rem;">
|
||||
<h1>Krater-Import</h1>
|
||||
<p class="hint">Importiert die IAU-Kraterdaten aus der CSV in die Tabelle <code>moon_craters</code>. Die Tabelle wird bei Bedarf automatisch angelegt.</p>
|
||||
|
||||
<?php if (is_array($report)): ?>
|
||||
<?php if ($report['ok'] ?? false): ?>
|
||||
<div class="msg-success">
|
||||
Import erfolgreich.<br>
|
||||
Datei: <?= h((string)($report['csv_label'] ?? $report['csv_path'])) ?><br>
|
||||
Importiert/Aktualisiert: <?= h((string)$report['imported']) ?><br>
|
||||
Uebersprungen: <?= h((string)$report['skipped']) ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="msg-error">
|
||||
Import fehlgeschlagen: <?= h((string)($report['error'] ?? 'Unbekannter Fehler')) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="form-stack" style="margin-top: 1rem;">
|
||||
<div class="form-group">
|
||||
<label for="csv_upload">CSV-Datei auswaehlen</label>
|
||||
<input type="file" id="csv_upload" name="csv_upload" accept=".csv,text/csv">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="csv_path">Oder Server-Pfad zur CSV-Datei</label>
|
||||
<input type="text" id="csv_path" name="csv_path" value="<?= h((string)($_POST['csv_path'] ?? $defaultCsv)) ?>">
|
||||
</div>
|
||||
|
||||
<label class="form-checkbox">
|
||||
<input type="checkbox" name="truncate_first" value="1"<?= isset($_POST['truncate_first']) ? ' checked' : '' ?>>
|
||||
Tabelle vor dem Import leeren
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">Import starten</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<?php require __DIR__ . '/../../public/footer.php'; ?>
|
||||
Reference in New Issue
Block a user