Quelltext des aktuellen Standes
<?php
$this->layout('layouts/main', [
'page_title' => $page_title,
'current_route' => $current_route,
'full_width' => true,
'extra_css' => ['/assets/css/ssl.css?v=' . filemtime(dirname(__DIR__, 2) . '/public/assets/css/ssl.css')],
'extra_js' => ['/assets/js/ssl.js?v=' . filemtime(dirname(__DIR__, 2) . '/public/assets/js/ssl.js')],
]);
$entries = $entries ?? [];
$stats = $stats ?? ['total' => 0, 'ok' => 0, 'soon' => 0, 'critical' => 0, 'problem' => 0];
$allTags = $all_tags ?? [];
$activeTag = $active_tag ?? '';
$users = $users ?? [];
$transports = $transports ?? ['tls'];
$canManage = $can_manage ?? false;
$view = $this;
$gradeChip = function (?string $g) use ($view): string {
if (!$g) {
return '<span class="ssl-grade ssl-grade-na">–</span>';
}
$cls = in_array($g, ['A', 'B', 'C', 'F'], true) ? $g : 'na';
return '<span class="ssl-grade ssl-grade-' . $cls . '">' . $view->e($g) . '</span>';
};
$isInsecure = function (array $e): bool {
$t = $e['trust_valid'] ?? null;
$h = $e['hostname_match'] ?? null;
return ($t !== null && (int)$t === 0) || ($h !== null && (int)$h === 0);
};
$transportLabel = ['tls' => 'TLS', 'smtp' => 'SMTP', 'imap' => 'IMAP', 'pop3' => 'POP3'];
?>
<div class="ssl-wrap">
<div class="content-header">
<div>
<h1><?= $this->te('SSL-Zertifikate') ?></h1>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
<li class="breadcrumb-item active"><?= $this->te('SSL-Zertifikate') ?></li>
</ol>
</div>
<div class="content-header-actions">
<button class="btn btn-default btn-sm" id="sslCheckAllBtn" title="<?= $this->te('Alle Zertifikate neu prüfen') ?>"><?= $this->te('↻ Alle prüfen') ?></button>
<?php if ($canManage): ?>
<button type="button" class="btn btn-primary" data-ssl-add-open>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18" aria-hidden="true" focusable="false"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
<?= $this->te('Zertifikat hinzufügen') ?>
</button>
<?php endif; ?>
</div>
</div>
<div class="page-body">
<!-- KPI Small Boxes -->
<div class="kpi-row">
<div class="kpi-col">
<a href="/ssl">
<div class="small-box bg-info">
<div class="inner"><h3><?= (int)$stats['total'] ?></h3><p><?= $this->te('Überwacht') ?></p></div>
<div class="icon"><i class="fas fa-lock"></i></div>
</div>
</a>
</div>
<div class="kpi-col">
<div class="small-box bg-success">
<div class="inner"><h3><?= (int)$stats['ok'] ?></h3><p>OK</p></div>
<div class="icon"><i class="fas fa-check-circle"></i></div>
</div>
</div>
<div class="kpi-col">
<div class="small-box bg-warning">
<div class="inner"><h3><?= (int)$stats['soon'] ?></h3><p><?= $this->te('≤ 30 Tage') ?></p></div>
<div class="icon"><i class="fas fa-clock"></i></div>
</div>
</div>
<div class="kpi-col">
<div class="small-box bg-danger">
<div class="inner"><h3><?= (int)$stats['critical'] ?></h3><p><?= $this->te('≤ 14 Tage') ?></p></div>
<div class="icon"><i class="fas fa-exclamation-triangle"></i></div>
</div>
</div>
<div class="kpi-col">
<div class="small-box bg-secondary">
<div class="inner"><h3><?= (int)$stats['problem'] ?></h3><p><?= $this->te('Fehler / Unsicher') ?></p></div>
<div class="icon"><i class="fas fa-times-circle"></i></div>
</div>
</div>
</div>
<!-- Suchleiste -->
<div class="ssl-searchbar card card-outline card-primary">
<div class="filter-card-body">
<div class="ssl-search-field">
<svg class="ssl-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<label for="sslSearch" class="sr-only"><?= $this->te('Zertifikate durchsuchen') ?></label>
<input type="search" id="sslSearch" class="form-control ssl-search-input" placeholder="<?= $this->te('Host, Bezeichnung, Aussteller, Owner oder Tag suchen…') ?>" autocomplete="off">
</div>
</div>
</div>
<!-- Tag-Filter -->
<?php if (!empty($allTags)): ?>
<div class="ssl-toolbar">
<div class="ssl-tags">
<a href="/ssl" class="ssl-tag-chip <?= $activeTag === '' ? 'active' : '' ?>"><?= $this->te('Alle') ?></a>
<?php foreach ($allTags as $t): ?>
<a href="/ssl?tag=<?= urlencode($t) ?>" class="ssl-tag-chip <?= $activeTag === $t ? 'active' : '' ?>"><?= $view->e($t) ?></a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<div class="table-wrapper">
<?php if (empty($entries)): ?>
<div class="empty-state"><p><?= $this->te('Noch keine Domains überwacht. Füge oben eine Domain hinzu.') ?></p></div>
<?php else: ?>
<table class="data-table" id="sslTable">
<thead>
<tr>
<th scope="col"><?= $this->te('Grade') ?></th>
<th scope="col"><?= $this->te('Bezeichnung / Host') ?></th>
<th scope="col"><?= $this->te('Status') ?></th>
<th scope="col"><?= $this->te('Ablauf') ?></th>
<th scope="col"><?= $this->te('Sicherheit') ?></th>
<th scope="col"><?= $this->te('Aussteller') ?></th>
<th scope="col"><?= $this->te('Owner') ?></th>
<th scope="col"><?= $this->te('Letzte Prüfung') ?></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<?php foreach ($entries as $e):
$days = $e['cert_days_left'];
$hasError = !empty($e['check_error']);
$insecure = $isInsecure($e);
if ($hasError) {
$badgeClass = 'status-pill--neutral'; $badgeLabel = 'Fehler';
} elseif ($insecure) {
$badgeClass = 'status-pill--danger'; $badgeLabel = 'Unsicher';
} elseif ($days === null) {
$badgeClass = 'status-pill--neutral'; $badgeLabel = 'Nicht geprüft';
} elseif ($days <= 14) {
$badgeClass = 'status-pill--danger'; $badgeLabel = 'Kritisch';
} elseif ($days <= 30) {
$badgeClass = 'status-pill--warning'; $badgeLabel = 'Bald';
} else {
$badgeClass = 'status-pill--success'; $badgeLabel = 'OK';
}
$searchText = mb_strtolower(trim(implode(' ', array_filter([
$e['label'] ?? '',
$e['host'] ?? '',
(string)($e['port'] ?? ''),
$e['cert_issuer_cn'] ?? '',
$e['owner_name'] ?? '',
$e['tags'] ?? '',
$transportLabel[$e['transport'] ?? 'tls'] ?? '',
]))));
?>
<tr id="sslRow<?= (int)$e['id'] ?>" class="clickable" data-href="/ssl/entries/<?= (int)$e['id'] ?>" data-search="<?= $view->e($searchText) ?>">
<td><?= $gradeChip($e['grade'] ?? null) ?></td>
<td>
<div class="ssl-host-name"><?= $view->e($e['label']) ?></div>
<div class="ssl-host-sub">
<?= $view->e($e['host']) ?>:<?= (int)$e['port'] ?>
<?php if (($e['transport'] ?? 'tls') !== 'tls'): ?>
· <?= $view->e($transportLabel[$e['transport']] ?? strtoupper($e['transport'])) ?>
<?php endif; ?>
<?php if (!empty($e['cert_is_wildcard'])): ?>
<span class="status-pill status-pill--purple"><?= $this->te('Wildcard') ?></span>
<?php endif; ?>
</div>
</td>
<td><span class="status-pill <?= $badgeClass ?>"><?= $badgeLabel ?></span></td>
<td>
<?php if ($e['cert_valid_to']): ?>
<div style="<?= $days !== null && $days <= 30 ? 'color:var(--red-700);font-weight:600;' : '' ?>"><?= date('d.m.Y', strtotime($e['cert_valid_to'])) ?></div>
<?php if ($days !== null): ?><div class="ssl-host-sub"><?= (int)$days ?> Tage</div><?php endif; ?>
<?php else: ?>
<span class="ssl-muted">—</span>
<?php endif; ?>
</td>
<td>
<div class="pill-row">
<?php if (($e['trust_valid'] ?? null) !== null): ?>
<span class="status-pill <?= (int)$e['trust_valid'] === 1 ? 'status-pill--success' : 'status-pill--danger' ?>" title="<?= $this->te('Vertrauenskette') ?>"><?= (int)$e['trust_valid'] === 1 ? '✓ Trust' : '✗ Trust' ?></span>
<?php endif; ?>
<?php if (($e['hostname_match'] ?? null) !== null): ?>
<span class="status-pill <?= (int)$e['hostname_match'] === 1 ? 'status-pill--success' : 'status-pill--danger' ?>" title="<?= $this->te('Hostname-Übereinstimmung') ?>"><?= (int)$e['hostname_match'] === 1 ? '✓ Host' : '✗ Host' ?></span>
<?php endif; ?>
<?php if (!empty($e['tls_version'])): ?>
<span class="status-pill status-pill--neutral"><?= $view->e($e['tls_version']) ?></span>
<?php endif; ?>
</div>
</td>
<td style="font-size:0.8rem;"><?= $view->e($e['cert_issuer_cn'] ?: '—') ?></td>
<td style="font-size:0.8rem;"><?= $view->e($e['owner_name'] ?: '—') ?></td>
<td class="ssl-muted" style="font-size:0.78rem;white-space:nowrap;">
<?= $e['last_checked_at'] ? date('d.m.Y H:i', strtotime($e['last_checked_at'])) : 'Nie' ?>
</td>
<td style="white-space:nowrap;">
<button class="btn btn-default btn-xs ssl-check-btn" data-id="<?= (int)$e['id'] ?>" title="<?= $this->te('Jetzt prüfen') ?>">↻</button>
<?php if ($canManage): ?>
<button class="btn btn-danger btn-xs ssl-delete-btn" data-id="<?= (int)$e['id'] ?>" data-host="<?= $view->e($e['host']) ?>" title="<?= $this->te('Entfernen') ?>">×</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="empty-state" id="sslNoResults" hidden><p><?= $this->te('Keine Zertifikate gefunden.') ?></p></div>
<?php endif; ?>
</div>
</div>
</div>
<?php if ($canManage): ?>
<!-- Modal: Zertifikat hinzufügen -->
<div id="sslAddModal" class="modal-overlay" role="dialog" aria-modal="true" aria-labelledby="sslAddModalTitle" style="display:none;">
<div class="modal-card">
<div class="modal-header">
<h2 id="sslAddModalTitle"><?= $this->te('Zertifikat hinzufügen') ?></h2>
<button type="button" class="modal-close" data-ssl-modal-close aria-label="<?= $this->te('Dialog schließen') ?>">×</button>
</div>
<form class="ssl-add-form" id="sslAddForm">
<div class="modal-body">
<div class="form-group">
<label for="ssl-add-host"><?= $this->te('Host / URL') ?> <span style="color:var(--red-500);">*</span></label>
<input type="text" id="ssl-add-host" name="host" class="form-control" placeholder="<?= $this->te('domain.de oder https://domain.de') ?>" autocomplete="off" required>
</div>
<div class="ssl-form-row">
<div class="form-group ssl-form-col-port">
<label for="ssl-add-port"><?= $this->te('Port') ?></label>
<input type="number" id="ssl-add-port" name="port" class="form-control" value="443" min="1" max="65535">
</div>
<div class="form-group ssl-form-col">
<label for="ssl-add-transport"><?= $this->te('Transport') ?></label>
<select id="ssl-add-transport" name="transport" class="form-control">
<?php foreach ($transports as $tr): ?>
<option value="<?= $view->e($tr) ?>"><?= $view->e($transportLabel[$tr] ?? strtoupper($tr)) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-group">
<label for="ssl-add-label"><?= $this->te('Bezeichnung') ?> <span class="form-hint"><?= $this->te('(optional)') ?></span></label>
<input type="text" id="ssl-add-label" name="label" class="form-control" placeholder="<?= $this->te('Optionaler Anzeigename') ?>">
</div>
<div class="ssl-form-row">
<div class="form-group ssl-form-col">
<label for="ssl-add-owner"><?= $this->te('Verantwortlich') ?></label>
<select id="ssl-add-owner" name="owner_user_id" class="form-control">
<option value=""><?= $this->te('— Owner —') ?></option>
<?php foreach ($users as $u): ?>
<option value="<?= (int)$u['id'] ?>"><?= $view->e($u['display_name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group ssl-form-col-warn">
<label for="ssl-add-warn"><?= $this->te('Warn-Tage') ?></label>
<input type="number" id="ssl-add-warn" name="warn_days" class="form-control" placeholder="<?= $this->te('Standard') ?>" min="1" title="<?= $this->te('Eigene Warnschwelle in Tagen (optional)') ?>">
</div>
</div>
<div class="form-group">
<label for="ssl-add-tags"><?= $this->te('Tags') ?> <span class="form-hint"><?= $this->te('(durch Komma getrennt)') ?></span></label>
<input type="text" id="ssl-add-tags" name="tags" class="form-control" placeholder="<?= $this->te('z. B. intern, web') ?>">
</div>
<div id="sslAddMsg" class="ssl-add-msg"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-ssl-modal-close><?= $this->te('Abbrechen') ?></button>
<button type="submit" class="btn btn-primary" id="sslAddBtn"><?= $this->te('Hinzufügen') ?></button>
</div>
</form>
</div>
</div>
<?php endif; ?>