Quelltext des aktuellen Standes
<?php
// Erwartet: $tableCves (array), $sevClass/$sevLabel (Closures aus index.php)
// Optional: $bsiByCveMap (CVE-ID => Advisory) für das 🇩🇪 BSI-Badge.
// Optional: $sortUrl (Closure), $sortCol, $sortDir für sortierbare Spalten.
$bsiByCveMap = $bsiByCveMap ?? [];
$sortUrlFn = $sortUrl ?? null;
$curCol = $sortCol ?? '';
$curDir = $sortDir ?? 'desc';
// Sortierbare Kopfzelle; ohne $sortUrl reiner Text (robust bei Wiederverwendung).
$th = function (string $label, string $col, string $style = '') use ($sortUrlFn, $curCol, $curDir): string {
$e = static fn($s) => htmlspecialchars((string)$s, ENT_QUOTES);
if ($sortUrlFn === null) {
return '<th style="' . $e($style) . '">' . $e($label) . '</th>';
}
$active = $curCol === $col;
$arrow = $active
? ($curDir === 'asc' ? ' ▲' : ' ▼')
: ' <span style="color:var(--gray-300);">⇵</span>';
return '<th style="' . $e($style) . '">'
. '<a href="' . $e($sortUrlFn($col)) . '"'
. ' style="display:inline-flex;align-items:center;gap:.15rem;color:inherit;text-decoration:none;white-space:nowrap;cursor:pointer;' . ($active ? 'font-weight:700;' : '') . '"'
. ' title="Nach ' . $e($label) . ' sortieren"'
. ' onclick="event.stopPropagation();">' . $e($label) . $arrow . '</a></th>';
};
?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<?= $th('Schweregrad', 'severity', 'width:110px;') ?>
<?= $th('CVSS', 'cvss', 'width:70px;') ?>
<?= $th('CVE-ID', 'cve_id', 'width:140px;') ?>
<th scope="col"><?= $this->te('Beschreibung') ?></th>
<?= $th('Veröffentlicht', 'published', 'width:100px;') ?>
<th scope="col" style="width:24px;"></th>
</tr>
</thead>
<tbody>
<?php foreach ($tableCves as $cve):
$sev = strtoupper($cve['severity'] ?? 'NONE');
$score = $cve['cvss_score'] !== null ? number_format((float)$cve['cvss_score'], 1) : '–';
$pubDate = !empty($cve['published']) ? date('d.m.Y', strtotime($cve['published'])) : '–';
$affected = json_decode($cve['affected'] ?? '[]', true) ?: [];
$rowId = $this->e($cve['cve_id']);
?>
<tr data-cve="<?= $rowId ?>" class="clickable" title="<?= $this->te('Details anzeigen') ?>">
<td><span class="status-pill <?= $sevClass($sev) ?>"><?= $sevLabel($sev) ?></span></td>
<td style="font-weight:700;color:<?= match($sev) {
'CRITICAL' => '#dc2626', 'HIGH' => '#ea580c', 'MEDIUM' => '#d97706', default => '#6b7280' } ?>;">
<?= $this->e($score) ?>
</td>
<td style="font-size:.8rem;font-weight:600;color:var(--gray-700);white-space:nowrap;">
<?= $this->e($cve['cve_id']) ?>
<?php $bsiAdv = $bsiByCveMap[strtoupper($cve['cve_id'])] ?? null; ?>
<?php if ($bsiAdv): ?>
<a href="<?= $this->e($bsiAdv['url'] ?: '/cve?q=' . urlencode($cve['cve_id'])) ?>"
<?= !empty($bsiAdv['url']) ? 'target="_blank" rel="noopener"' : '' ?>
class="cve-bsi-badge"
title="BSI CERT-Bund-Warnung: <?= $this->e($bsiAdv['title'] ?? '') ?>"
onclick="event.stopPropagation();"><?= $this->te('🇩🇪 BSI') ?></a>
<?php endif; ?>
</td>
<td style="color:var(--gray-700);max-width:460px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"
title="<?= $this->e($cve['description'] ?? '') ?>">
<?= $this->e(mb_strimwidth($cve['description'] ?? '', 0, 120, '…')) ?>
</td>
<td style="white-space:nowrap;color:var(--gray-500);font-size:.8rem;"><?= $pubDate ?></td>
<td style="color:var(--gray-400);font-size:.8rem;">▼</td>
</tr>
<tr id="cve-det-<?= $rowId ?>" class="cve-detail-row">
<td class="cve-detail-cell" colspan="6">
<div class="cve-detail-inner">
<p style="margin:0 0 .5rem;"><?= nl2br($this->e($cve['description'] ?? '')) ?></p>
<div style="display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;font-size:.8rem;color:var(--gray-500);margin-bottom:.5rem;">
<?php if (!empty($cve['cvss_vector'])): ?>
<span><strong style="color:var(--gray-700);"><?= $this->te('Vektor:') ?></strong> <?= $this->e($cve['cvss_vector']) ?></span>
<?php endif; ?>
<?php if (!empty($cve['published'])): ?>
<span><strong style="color:var(--gray-700);"><?= $this->te('Veröffentlicht:') ?></strong>
<?= date('d.m.Y H:i', strtotime($cve['published'])) ?> UTC</span>
<?php endif; ?>
</div>
<?php if (!empty($affected)): ?>
<div style="margin-bottom:.5rem;">
<strong style="font-size:.78rem;color:var(--gray-700);"><?= $this->te('Betroffen:') ?></strong>
<?php foreach ($affected as $prod): ?>
<span class="cve-affected-chip"><?= $this->e($prod) ?></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
<a href="https://nvd.nist.gov/vuln/detail/<?= urlencode($cve['cve_id']) ?>"
target="_blank" rel="noopener"
style="font-size:.8rem;color:var(--color-primary);text-decoration:none;"
onclick="event.stopPropagation();">
<?= $this->te('↗ Vollständigen NVD-Eintrag öffnen') ?>
</a>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>