false, 'message' => 'Method tidak didukung']); exit; } $db = getDB(); $type = $_POST['type'] ?? ''; // 'penduduk' | 'ibadah' if (!in_array($type, ['penduduk', 'ibadah'])) { echo json_encode(['success' => false, 'message' => 'Tipe import tidak valid']); exit; } if (empty($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) { echo json_encode(['success' => false, 'message' => 'File tidak valid atau tidak ada']); exit; } // Baca isi file $content = file_get_contents($_FILES['file']['tmp_name']); if ($content === false) { echo json_encode(['success' => false, 'message' => 'Gagal membaca file']); exit; } // Normalize line endings & parse CSV $content = str_replace("\r\n", "\n", $content); $content = str_replace("\r", "\n", $content); $lines = array_filter(explode("\n", $content), 'strlen'); $lines = array_values($lines); if (empty($lines)) { echo json_encode(['success' => false, 'message' => 'File kosong']); exit; } // Parse CSV baris per baris function parseCSVLine(string $line): array { $cols = []; $cur = ''; $inQ = false; for ($i = 0; $i < strlen($line); $i++) { $ch = $line[$i]; if ($ch === '"') { $inQ = !$inQ; } elseif ($ch === ',' && !$inQ) { $cols[] = trim($cur, " \t\""); $cur = ''; } else { $cur .= $ch; } } $cols[] = trim($cur, " \t\""); return $cols; } // Deteksi header row $firstLine = strtolower($lines[0]); $hasHeader = str_contains($firstLine, 'nama') || str_contains($firstLine, 'lat') || str_contains($firstLine, 'kk_nama'); $dataLines = $hasHeader ? array_slice($lines, 1) : $lines; $imported = 0; $failed = 0; $skipped = 0; $errors = []; // ── Import Penduduk Miskin ───────────────────────────────────── if ($type === 'penduduk') { $stmt = $db->prepare(" INSERT INTO penduduk_miskin (kk_nama, nik, jumlah_anggota, alamat, kelurahan, kecamatan, lat, lng, rumah_ibadah_id, jarak_ke_ibadah, status_bantuan, jenis_bantuan, tanggal_bantuan, nominal_bantuan) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?) "); foreach ($dataLines as $lineNum => $line) { if (!trim($line)) continue; $row = parseCSVLine($line); // kk_nama (0), nik (1), jumlah_anggota (2), alamat (3), kelurahan (4), // kecamatan (5), lat (6), lng (7), status_bantuan (8), jenis_bantuan (9), // tanggal_bantuan (10), nominal_bantuan (11) if (count($row) < 8 || empty($row[0]) || empty($row[6]) || empty($row[7])) { $failed++; $errors[] = "Baris " . ($lineNum + ($hasHeader ? 2 : 1)) . ": kolom tidak lengkap atau koordinat kosong"; if (count($errors) > 10) { $errors[] = '... dan lebih banyak error'; break; } continue; } $lat = (float)$row[6]; $lng = (float)$row[7]; if ($lat === 0.0 && $lng === 0.0) { $skipped++; continue; } $status = in_array($row[8] ?? '', ['sudah','belum','menunggu']) ? $row[8] : 'belum'; $tanggal_bantuan = !empty($row[10]) ? sanitize($row[10]) : null; $nominal_bantuan = isset($row[11]) && $row[11] !== '' ? (float)str_replace(['.', ','], ['', '.'], $row[11]) : null; $nearest = findNearestIbadah($lat, $lng); $ibadahId = $nearest ? (int)$nearest['id'] : null; $jarakIbadah = $nearest ? (float)$nearest['jarak'] : null; try { $stmt->execute([ sanitize($row[0]), sanitize($row[1] ?? ''), max(1, (int)($row[2] ?? 1)), sanitize($row[3] ?? ''), sanitize($row[4] ?? ''), sanitize($row[5] ?? ''), $lat, $lng, $ibadahId, $jarakIbadah, $status, sanitize($row[9] ?? ''), $tanggal_bantuan, $nominal_bantuan, ]); $imported++; } catch (PDOException $e) { $failed++; $errors[] = "Baris " . ($lineNum + ($hasHeader ? 2 : 1)) . ": " . $e->getMessage(); } } } // ── Import Rumah Ibadah ─────────────────────────────────────── if ($type === 'ibadah') { $validJenis = ['Masjid','Musholla','Gereja','Katolik','Pura','Vihara','Klenteng','Lainnya']; $stmt = $db->prepare(" INSERT INTO rumah_ibadah (nama, jenis, kontak, alamat, kelurahan, kecamatan, lat, lng, radius) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "); foreach ($dataLines as $lineNum => $line) { if (!trim($line)) continue; $row = parseCSVLine($line); // nama (0), jenis (1), kontak (2), alamat (3), kelurahan (4), // kecamatan (5), lat (6), lng (7), radius (8) if (count($row) < 8 || empty($row[0]) || empty($row[6]) || empty($row[7])) { $failed++; $errors[] = "Baris " . ($lineNum + ($hasHeader ? 2 : 1)) . ": kolom tidak lengkap"; if (count($errors) > 10) { $errors[] = '... dan lebih banyak error'; break; } continue; } $lat = (float)$row[6]; $lng = (float)$row[7]; if ($lat === 0.0 && $lng === 0.0) { $skipped++; continue; } $jenis = in_array($row[1] ?? '', $validJenis) ? $row[1] : 'Lainnya'; $radius = max(100, min(5000, (int)($row[8] ?? RADIUS_DEFAULT))); try { $stmt->execute([ sanitize($row[0]), $jenis, sanitize($row[2] ?? ''), sanitize($row[3] ?? ''), sanitize($row[4] ?? ''), sanitize($row[5] ?? ''), $lat, $lng, $radius, ]); $imported++; } catch (PDOException $e) { $failed++; $errors[] = "Baris " . ($lineNum + ($hasHeader ? 2 : 1)) . ": " . $e->getMessage(); } } } echo json_encode([ 'success' => true, 'imported' => $imported, 'failed' => $failed, 'skipped' => $skipped, 'errors' => array_slice($errors, 0, 15), 'message' => "Import selesai: $imported berhasil, $failed gagal, $skipped dilewati", ], JSON_UNESCAPED_UNICODE);