orderBy('name') ->get(); return view('network.segments.index', compact('segments')); } public function create(): View { return view('network.segments.create'); } public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'subnet' => ['required', 'string', 'max:50'], 'vlan_id' => ['nullable', 'integer', 'min:1', 'max:4094'], 'active' => ['boolean'], 'description' => ['nullable', 'string', 'max:500'], ]); $validated['active'] = $request->boolean('active', true); $validated['created_by'] = auth()->id(); NetworkSegment::create($validated); return redirect()->route('network.segments.index') ->with('success', "Segment \"{$validated['name']}\" angelegt."); } public function show(NetworkSegment $segment): View { $scans = $segment->scans()->latest()->paginate(20); $latestScan = $segment->scans()->latest()->first(); return view('network.segments.show', compact('segment', 'scans', 'latestScan')); } public function edit(NetworkSegment $segment): View { return view('network.segments.edit', compact('segment')); } public function update(Request $request, NetworkSegment $segment): RedirectResponse { $validated = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'subnet' => ['required', 'string', 'max:50'], 'vlan_id' => ['nullable', 'integer', 'min:1', 'max:4094'], 'active' => ['boolean'], 'description' => ['nullable', 'string', 'max:500'], ]); $validated['active'] = $request->boolean('active', true); $segment->update($validated); return redirect()->route('network.segments.index') ->with('success', "Segment \"{$segment->name}\" aktualisiert."); } public function destroy(NetworkSegment $segment): RedirectResponse { $name = $segment->name; $segment->delete(); return redirect()->route('network.segments.index') ->with('success', "Segment \"{$name}\" gelöscht."); } public function triggerScan(NetworkSegment $segment): RedirectResponse { if (!$segment->active) { return back()->with('error', 'Segment ist inaktiv.'); } // Scan im Hintergrund starten (non-blocking) $projectPath = base_path(); $phpBinary = PHP_BINARY; $cmd = "cd {$projectPath} && {$phpBinary} artisan network:scan {$segment->id} --force > /dev/null 2>&1 &"; exec($cmd); return redirect()->route('network.segments.show', $segment) ->with('success', "Scan für \"{$segment->name}\" wurde gestartet. Ergebnisse erscheinen in Kürze."); } // --- IP-Notiz speichern (Upsert per Segment + IP) --- public function saveIpNote(Request $request, NetworkSegment $segment): JsonResponse { $request->validate([ 'ip_address' => ['required', 'ip'], 'note' => ['nullable', 'string', 'max:500'], ]); NetworkIpNote::updateOrCreate( ['segment_id' => $segment->id, 'ip_address' => $request->ip_address], [ 'note' => $request->note, 'updated_by' => auth()->id(), 'created_by' => auth()->id(), ] ); return response()->json(['ok' => true]); } // --- Export: Excel (OpenSpout – kein ext-gd, PHP 8.5 kompatibel) --- public function exportXlsx(NetworkSegment $segment) { $hosts = $this->getLatestScanHosts($segment); $notes = NetworkIpNote::where('segment_id', $segment->id) ->pluck('note', 'ip_address'); $filename = 'Segment_' . preg_replace('/[^a-zA-Z0-9_-]/', '_', $segment->name) . '_' . now()->format('Ymd_Hi') . '.xlsx'; $tempFile = tempnam(sys_get_temp_dir(), 'net_export_') . '.xlsx'; $writer = new \OpenSpout\Writer\XLSX\Writer(); $writer->openToFile($tempFile); $writer->addRow(\OpenSpout\Common\Entity\Row::fromValues([ 'IP-Adresse', 'Status', 'Hostname', 'MAC-Adresse', 'Hersteller', 'Ping (ms)', 'Bemerkung', ])); foreach ($hosts as $host) { $writer->addRow(\OpenSpout\Common\Entity\Row::fromValues([ $host->ip_address, $host->status, $host->hostname ?? '', $host->mac_address ?? '', $host->mac_vendor ?? '', $host->ping_ms !== null ? (string) $host->ping_ms : '', $notes[$host->ip_address] ?? '', ])); } $writer->close(); return response()->download($tempFile, $filename, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ])->deleteFileAfterSend(true); } // --- Export: PDF (Browser-Print-View – kein PHP-PDF-Package nötig) --- public function exportPdf(NetworkSegment $segment) { $hosts = $this->getLatestScanHosts($segment); $notes = NetworkIpNote::where('segment_id', $segment->id) ->pluck('note', 'ip_address'); return view('network.segments.export-pdf', compact('segment', 'hosts', 'notes')); } private function getLatestScanHosts(NetworkSegment $segment) { $latestScan = $segment->scans()->latest()->first(); if (!$latestScan) { return collect(); } return $latestScan->hosts()->orderByRaw('INET_ATON(ip_address)')->get(); } }