Kein Zugriff"; include "footer.php"; exit; } function csv_upload_dir(): string { return APP_ROOT . '/var/uploads'; } /** * @return array{0: ?string, 1: ?string} [Pfad, Fehlermeldung] */ function csv_prepare_upload(array $file): array { if (($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) { return [null, 'Fehler beim Hochladen der Datei.']; } if (($file['size'] ?? 0) <= 0 || $file['size'] > 5 * 1024 * 1024) { return [null, 'Die CSV-Datei ist leer oder größer als 5 MB.']; } $originalName = (string)($file['name'] ?? ''); $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION)); if ($extension !== 'csv') { return [null, 'Es sind nur CSV-Dateien erlaubt.']; } $tmpName = (string)($file['tmp_name'] ?? ''); if (!is_uploaded_file($tmpName)) { return [null, 'Die hochgeladene Datei konnte nicht verifiziert werden.']; } if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = $finfo ? finfo_file($finfo, $tmpName) : false; if ($finfo) { finfo_close($finfo); } $allowedMimeTypes = [ 'text/plain', 'text/csv', 'text/x-csv', 'application/csv', 'application/vnd.ms-excel', 'application/octet-stream', ]; if (is_string($mime) && !in_array($mime, $allowedMimeTypes, true)) { return [null, 'Der Dateityp wurde nicht als CSV erkannt.']; } } $uploadDir = csv_upload_dir(); if (!is_dir($uploadDir)) { @mkdir($uploadDir, 0700, true); } if (!is_dir($uploadDir) || !is_writable($uploadDir)) { return [null, 'Der Upload-Ordner ist nicht beschreibbar.']; } $targetFile = $uploadDir . '/paypal_' . date('Ymd_His') . '_' . bin2hex(random_bytes(8)) . '.csv'; if (!move_uploaded_file($tmpName, $targetFile)) { return [null, 'Die CSV-Datei konnte nicht gespeichert werden.']; } return [$targetFile, null]; } function csv_status_label(string $status): string { return match ($status) { 'matched' => 'Wird importiert', 'duplicate' => 'Bereits vorhanden', 'unmatched' => 'Mitglied nicht gefunden', 'invalid' => 'Ungültige Zeile', 'imported' => 'Importiert', default => $status, }; } $meldung = null; $fehler = null; $vorschauBatchId = null; if ($_SERVER["REQUEST_METHOD"] === "POST") { $aktion = $_POST['aktion'] ?? 'hochladen'; if ($aktion === 'hochladen' && isset($_FILES["csv_file"])) { [$csvFile, $uploadError] = csv_prepare_upload($_FILES["csv_file"]); if ($uploadError !== null) { $fehler = $uploadError; } else { try { $checksum = hash_file('sha256', $csvFile); $rows = imports_parse_csv($csvFile); $pdo->beginTransaction(); $batchId = imports_create_batch( $pdo, $tenantId, basename((string)$_FILES["csv_file"]["name"]), (string)$checksum, $saasUser['user_id'] ?? null ); foreach ($rows as $row) { $amountCents = imports_normalize_amount($row['amount_raw']); $timestamp = $row['date_raw'] !== '' ? strtotime($row['date_raw']) : false; if ($amountCents === null || $timestamp === false) { imports_store_row($pdo, $batchId, $row['row_number'], null, $row['raw_name'], $amountCents ?? 0, date('Y-m-d H:i:s', $timestamp ?: time()), 'invalid', $row['raw']); continue; } $bookedAt = date('Y-m-d H:i:s', $timestamp); $participant = imports_find_participant($pdo, $tenantId, $row['raw_name']); if ($participant === null) { imports_store_row($pdo, $batchId, $row['row_number'], null, $row['raw_name'], $amountCents, $bookedAt, 'unmatched', $row['raw']); continue; } if (imports_is_duplicate($pdo, $tenantId, $participant['participant_id'], $amountCents, date('Y-m-d', $timestamp))) { imports_store_row($pdo, $batchId, $row['row_number'], $participant['participant_id'], $row['raw_name'], $amountCents, $bookedAt, 'duplicate', $row['raw']); continue; } imports_store_row($pdo, $batchId, $row['row_number'], $participant['participant_id'], $row['raw_name'], $amountCents, $bookedAt, 'matched', $row['raw']); } $pdo->commit(); $vorschauBatchId = $batchId; } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } $fehler = 'Die CSV-Datei konnte nicht verarbeitet werden.'; } finally { @unlink($csvFile); } } } elseif ($aktion === 'importieren') { $batchId = (int)($_POST['batch_id'] ?? 0); try { $ergebnis = imports_commit_batch($pdo, $tenantId, $batchId); app_audit_log($pdo, $tenantId, $saasUser['user_id'] ?? null, 'csv_import.committed', 'payment_import_batch', $batchId, ['imported' => $ergebnis['imported']]); $meldung = $ergebnis['imported'] . ' Einzahlungen wurden importiert.'; } catch (Throwable $e) { $fehler = $e->getMessage(); $vorschauBatchId = $batchId; } } } $vorschau = $vorschauBatchId !== null ? imports_fetch_batch($pdo, $tenantId, $vorschauBatchId) : null; ?> CSV Verarbeitung

CSV-Import

Vorschau:

Status:

Zeile Name (CSV) Zugeordnetes Mitglied Betrag Datum Status
€
">

" method="post" enctype="multipart/form-data">