1.3.0: PDF-Zweig SIP-Erreichbarkeit, Token in der URL nur noch fuer den APK-Download [deploy]
All checks were successful
Deploy netdiag / deploy (push) Successful in 14s
All checks were successful
Deploy netdiag / deploy (push) Successful in 14s
PDF-Zweig netdiagPdfSip()
- Eigener Zweig, weil die Aussage sonst untergeht: in einer flachen
Schluessel/Wert-Liste sieht "401 Unauthorized" wie ein Fehler aus, ist aber
der Beweis fuer eine erreichbare Instanz, die nur Zugangsdaten will. Erst
Befund im Klartext, dann eine Zeile je Transportweg.
- Der Grenzhinweis steht mit im Dokument: gemessen ist die Erreichbarkeit,
NICHT die Sprachqualitaet.
- Feldnamen-Falle wieder aufgetreten: 'port' gehoert in beiden Feldtabellen
laengst dem SNMP-Werkzeug ("Switch-Port"). Im Kunden-PDF haette gestanden
"Switch-Port: 5060" - deshalb 'zielPort'.
WLAN-Kanalanalyse: Warnungen nicht mehr abschneiden
- dol_trunc(..., 160) kappte genau die Begruendung ("... In dicht besiedelter
Umgebung meist ein Fehle..."). Eine Warnung ohne ihren Grund ist im
Kundendokument wertlos; MultiCell bricht ohnehin um.
Token in der Adresszeile
- netdiag_api_read_token() nimmt ?jwt= nur noch an, wenn der Endpunkt es
ausdruecklich erlaubt. Einzige Stelle: update.php?download=1.
- Grund: ein Token in der URL steht in jedem Zugriffs- und Proxy-Log und gilt
sieben Tage fuer die GESAMTE Kunden-API.
- Warum die Ausnahme bleibt: die App-Fassungen im Feld bauen die
Download-Adresse mit dem Token darin. Sofort schliessen hiesse, genau die
Geraete vom Update auszusperren, die die neue APK brauchen. Zu entfernen,
sobald Eddy den Rollout bestaetigt (Hinweis steht im Code).
- pdf.php nimmt ab sofort ausschliesslich den Authorization-Header.
Gegen die Testinstanz gemessen: ?jwt= liefert bei orders/customers/protocols/
pdf/update-Version jetzt 401, mit Bearer weiterhin 200.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a0dc0750cb
commit
087f37afa6
7 changed files with 230 additions and 12 deletions
51
ChangeLog.md
51
ChangeLog.md
|
|
@ -1,5 +1,56 @@
|
||||||
# Changelog NetDiag
|
# Changelog NetDiag
|
||||||
|
|
||||||
|
## 1.3.0 — 2026-08-19
|
||||||
|
|
||||||
|
### Neues Werkzeug: SIP-Erreichbarkeit (Telefonie)
|
||||||
|
|
||||||
|
Die App fragt Telefonanlage oder Provider mit einer OPTIONS-Anfrage (RFC 3261) —
|
||||||
|
ohne Anruf, ohne Zugangsdaten, ohne dass irgendwo ein Telefon klingelt. Modulseitig
|
||||||
|
kommt der PDF-Zweig dazu.
|
||||||
|
|
||||||
|
- `netdiagPdfSip()` in `lib/netdiag_pdf.lib.php`: Ziel, Port und Statuszeile in der
|
||||||
|
Kopfzeile, darunter der Befund im Klartext, dann eine Zeile je Transportweg.
|
||||||
|
**Warum ein eigener Zweig:** in einer flachen Schlüssel/Wert-Liste sieht „401
|
||||||
|
Unauthorized" wie ein Fehler aus. Tatsächlich ist es der Beweis, dass die Instanz
|
||||||
|
erreichbar ist und antwortet — sie will nur Zugangsdaten sehen. Diese Unterscheidung
|
||||||
|
ist im Kundendokument der Unterschied zwischen „Anlage tot" und „Zugangsdaten prüfen".
|
||||||
|
- Der Grenzhinweis steht mit im PDF: gemessen ist die **Erreichbarkeit**, NICHT die
|
||||||
|
Sprachqualität. RTP-Jitter ohne aufgebautes Gespräch zu behaupten wäre eine
|
||||||
|
Falschaussage.
|
||||||
|
- `netdiagToolName()`: `sipcheck` → „SIP-Erreichbarkeit".
|
||||||
|
- `netdiagKundenfelder()` um die Felder des Werkzeugs ergänzt (`befund`,
|
||||||
|
`statuszeile`, `antwortWeg`, `anmeldungNoetig`, `versuche`, `unterstuetzteMethoden`,
|
||||||
|
`zielIp`, `zielHerkunft`, `zielPort`, `laufzeitMs`).
|
||||||
|
**Achtung, dabei aufgefallen:** der naheliegende Schlüssel `port` war bereits vom
|
||||||
|
SNMP-Werkzeug als „Switch-Port" belegt. Ein SIP-Port unter diesem Namen stünde im
|
||||||
|
Kundendokument falsch beschriftet — deshalb `zielPort`.
|
||||||
|
|
||||||
|
### WLAN-Kanalanalyse: Warnungen werden nicht mehr abgeschnitten
|
||||||
|
|
||||||
|
`netdiagPdfWifiKanal()` kürzte jede Warnung nach 160 Zeichen (`dol_trunc`). Betroffen
|
||||||
|
war genau die Begründung: „… blockiert damit praktisch 2 der 3 störungsfreien Kanäle.
|
||||||
|
In dicht besiedelter Umgebung meist ein Fehle…". Eine Warnung ohne ihren Grund ist im
|
||||||
|
Kundendokument wertlos; MultiCell bricht ohnehin sauber um.
|
||||||
|
|
||||||
|
### Sicherheit: Token in der Adresszeile nur noch für den APK-Download
|
||||||
|
|
||||||
|
`netdiag_api_read_token()` nimmt `?jwt=` nicht mehr allgemein an, sondern nur noch,
|
||||||
|
wenn der Endpunkt es ausdrücklich erlaubt (`netdiag_api_authenticate($db, true)`).
|
||||||
|
Einzige Stelle: `update.php?download=1`.
|
||||||
|
|
||||||
|
Warum überhaupt: ein Token in der URL landet in Zugriffs- und Proxy-Logs und gilt
|
||||||
|
sieben Tage für die **gesamte** Kunden-API. Vorher hätte damit jeder, der ein Log
|
||||||
|
liest, Aufträge, Kunden und Protokolle abrufen können.
|
||||||
|
|
||||||
|
Warum die eine Ausnahme bleibt: die im Feld installierten App-Fassungen bauen die
|
||||||
|
Download-Adresse mit dem Token darin. Wird der Zweig sofort geschlossen, kommt kein
|
||||||
|
altes Gerät mehr an die neue APK — und die neue APK ist genau die, die den Zweig
|
||||||
|
überflüssig macht. **Zu entfernen, sobald der Rollout bestätigt ist** (Hinweis steht
|
||||||
|
im Code an beiden Stellen).
|
||||||
|
|
||||||
|
`pdf.php` nimmt ab sofort ausschließlich den `Authorization: Bearer`-Header.
|
||||||
|
|
||||||
|
|
||||||
## 1.2.0 — 2026-08-17
|
## 1.2.0 — 2026-08-17
|
||||||
|
|
||||||
### Anmeldung nur noch über AWL-Auth — der eigene JWT-Pfad ist weg
|
### Anmeldung nur noch über AWL-Auth — der eigene JWT-Pfad ist weg
|
||||||
|
|
|
||||||
|
|
@ -198,11 +198,24 @@ function netdiag_api_error($message, $httpstatus = 400)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token aus Request lesen (Authorization-Header oder ?jwt=).
|
* Token aus Request lesen.
|
||||||
*
|
*
|
||||||
|
* Regelfall ist ausschliesslich der `Authorization: Bearer`-Header. Ein Token in
|
||||||
|
* der Adresszeile landet in Zugriffs- und Proxy-Logs und im Verlauf jedes
|
||||||
|
* Zwischensystems — bei einem Langzeit-Token (Standard 7 Tage) ist das ein
|
||||||
|
* Nachschluessel zur gesamten Kunden-API.
|
||||||
|
*
|
||||||
|
* Genau eine Ausnahme, bewusst und befristet: der APK-Download in `update.php`.
|
||||||
|
* Die im Feld installierten Fassungen rufen ihn mit `?jwt=` auf. Wer den Zweig
|
||||||
|
* jetzt schon entfernt, sperrt diese Geraete vom Update aus — und die einzige
|
||||||
|
* Quelle der neuen APK ist genau dieser Endpunkt. Deshalb bleibt er, bis Eddy
|
||||||
|
* den Rollout bestaetigt; er gilt dann nur noch fuer eine einzige, lesende
|
||||||
|
* Datei-Auslieferung statt fuer die ganze API.
|
||||||
|
*
|
||||||
|
* @param bool $allowQuery Query-Parameter `?jwt=` zusaetzlich zulassen
|
||||||
* @return string Token oder leerer String
|
* @return string Token oder leerer String
|
||||||
*/
|
*/
|
||||||
function netdiag_api_read_token()
|
function netdiag_api_read_token($allowQuery = false)
|
||||||
{
|
{
|
||||||
$auth = '';
|
$auth = '';
|
||||||
if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||||
|
|
@ -218,7 +231,7 @@ function netdiag_api_read_token()
|
||||||
if (stripos($auth, 'Bearer ') === 0) {
|
if (stripos($auth, 'Bearer ') === 0) {
|
||||||
return trim(substr($auth, 7));
|
return trim(substr($auth, 7));
|
||||||
}
|
}
|
||||||
if (!empty($_GET['jwt'])) {
|
if ($allowQuery && !empty($_GET['jwt'])) {
|
||||||
return (string) $_GET['jwt'];
|
return (string) $_GET['jwt'];
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
|
@ -234,11 +247,12 @@ function netdiag_api_read_token()
|
||||||
* sobald alle Geräte einmal neu angemeldet sind (siehe ROADMAP_UMSETZUNG L5).
|
* sobald alle Geräte einmal neu angemeldet sind (siehe ROADMAP_UMSETZUNG L5).
|
||||||
*
|
*
|
||||||
* @param DoliDB $db Datenbank-Handler
|
* @param DoliDB $db Datenbank-Handler
|
||||||
|
* @param bool $allowQuery Token auch aus `?jwt=` annehmen (nur APK-Download)
|
||||||
* @return User Geladenes Benutzer-Objekt
|
* @return User Geladenes Benutzer-Objekt
|
||||||
*/
|
*/
|
||||||
function netdiag_api_authenticate($db)
|
function netdiag_api_authenticate($db, $allowQuery = false)
|
||||||
{
|
{
|
||||||
$token = netdiag_api_read_token();
|
$token = netdiag_api_read_token($allowQuery);
|
||||||
if (empty($token)) {
|
if (empty($token)) {
|
||||||
netdiag_api_error('Kein Token übermittelt', 401);
|
netdiag_api_error('Kein Token übermittelt', 401);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@
|
||||||
/**
|
/**
|
||||||
* \file netdiag/api/pdf.php
|
* \file netdiag/api/pdf.php
|
||||||
* \ingroup netdiag
|
* \ingroup netdiag
|
||||||
* \brief API-Endpunkt: Protokoll-PDF streamen (GET ?id=&jwt=).
|
* \brief API-Endpunkt: Protokoll-PDF streamen (GET ?id=).
|
||||||
|
*
|
||||||
|
* Authentifizierung ausschliesslich per `Authorization: Bearer`-Header. Ein
|
||||||
|
* Token in der Adresszeile stuende in jedem Zugriffs- und Proxy-Log; der
|
||||||
|
* Aufrufer holt das PDF deshalb per fetch und verarbeitet es als Blob.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__.'/netdiag_api.lib.php';
|
require_once __DIR__.'/netdiag_api.lib.php';
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,18 @@ netdiag_api_bootstrap();
|
||||||
* @var DoliDB $db
|
* @var DoliDB $db
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$user = netdiag_api_authenticate($db);
|
/*
|
||||||
|
* Einzige Stelle im Modul, die ein Token noch aus der Adresszeile annimmt
|
||||||
|
* (`?jwt=`) — und nur fuer den Datei-Download. Grund: die im Feld installierten
|
||||||
|
* App-Fassungen bauen die Download-Adresse mit dem Token darin. Wird der Zweig
|
||||||
|
* jetzt geschlossen, kommt kein altes Geraet mehr an die neue APK, die genau
|
||||||
|
* diese Abhaengigkeit aufloest. Die Versionsabfrage (ohne ?download=) laeuft
|
||||||
|
* bereits ueber den normalen fetch-Weg der App und braucht ihn nicht.
|
||||||
|
*
|
||||||
|
* Zu entfernen, sobald Eddy den Rollout der Fassung >= 20260819 bestaetigt:
|
||||||
|
* Parameter streichen -> `netdiag_api_authenticate($db)`.
|
||||||
|
*/
|
||||||
|
$user = netdiag_api_authenticate($db, isset($_GET['download']));
|
||||||
|
|
||||||
$registry = 'https://git.data-it-solution.de';
|
$registry = 'https://git.data-it-solution.de';
|
||||||
$owner = 'data-it';
|
$owner = 'data-it';
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class modNetDiag extends DolibarrModules
|
||||||
$this->editor_url = '';
|
$this->editor_url = '';
|
||||||
$this->editor_squarred_logo = '';
|
$this->editor_squarred_logo = '';
|
||||||
|
|
||||||
$this->version = '1.2.0';
|
$this->version = '1.3.0';
|
||||||
|
|
||||||
// Konstanten-Name in llx_const für Modul-Status
|
// Konstanten-Name in llx_const für Modul-Status
|
||||||
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
|
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
|
||||||
|
|
|
||||||
|
|
@ -366,6 +366,22 @@ function netdiagKundenfelder()
|
||||||
'mitNeuerAdresse' => array('Mit neuer IP-Adresse', ''),
|
'mitNeuerAdresse' => array('Mit neuer IP-Adresse', ''),
|
||||||
'andereOffenePorts' => array('Gleiche Adresse, andere offene Ports', ''),
|
'andereOffenePorts' => array('Gleiche Adresse, andere offene Ports', ''),
|
||||||
'unveraendert' => array('Unverändert', ''),
|
'unveraendert' => array('Unverändert', ''),
|
||||||
|
// SIP-Erreichbarkeit (Telefonie). Der Befund ist die eigentliche Aussage:
|
||||||
|
// „401 Anmeldung verlangt" ist ein ERREICHBARER Anschluss, nicht der
|
||||||
|
// Ausfall, als den ihn eine nackte Ampel erscheinen ließe.
|
||||||
|
'befund' => array('Befund', ''),
|
||||||
|
'statuszeile' => array('Antwort der Gegenstelle', ''),
|
||||||
|
'antwortWeg' => array('Antwort über', ''),
|
||||||
|
'anmeldungNoetig' => array('Anmeldung verlangt', ''),
|
||||||
|
'versuche' => array('Versuche je Transportweg', ''),
|
||||||
|
'unterstuetzteMethoden' => array('Unterstützte SIP-Methoden', ''),
|
||||||
|
'zielIp' => array('Adresse des Ziels', ''),
|
||||||
|
'zielHerkunft' => array('Herkunft des Ziels', ''),
|
||||||
|
// NICHT 'port' — der Schlüssel gehört hier bereits dem SNMP-Werkzeug
|
||||||
|
// („Switch-Port"); ein SIP-Port unter diesem Namen stünde falsch beschriftet
|
||||||
|
// im Kundendokument.
|
||||||
|
'zielPort' => array('Port', ''),
|
||||||
|
'laufzeitMs' => array('Laufzeit', 'ms'),
|
||||||
// Netz/DHCP
|
// Netz/DHCP
|
||||||
'server' => array('DHCP-Server', ''),
|
'server' => array('DHCP-Server', ''),
|
||||||
'lease' => array('Lease-Dauer', 's'),
|
'lease' => array('Lease-Dauer', 's'),
|
||||||
|
|
@ -661,6 +677,7 @@ function netdiagToolName($tool)
|
||||||
'wifitrack' => 'WLAN-Empfang',
|
'wifitrack' => 'WLAN-Empfang',
|
||||||
'dnscheck' => 'DNS-Prüfung',
|
'dnscheck' => 'DNS-Prüfung',
|
||||||
'geraetediff' => 'Geräte-Vergleich',
|
'geraetediff' => 'Geräte-Vergleich',
|
||||||
|
'sipcheck' => 'SIP-Erreichbarkeit',
|
||||||
// nicht mehr vorhandene Werkzeuge, aber in Altprotokollen enthalten
|
// nicht mehr vorhandene Werkzeuge, aber in Altprotokollen enthalten
|
||||||
'dhcpcheck' => 'DHCP-Prüfung',
|
'dhcpcheck' => 'DHCP-Prüfung',
|
||||||
'wifiscan' => 'WLAN-Scan',
|
'wifiscan' => 'WLAN-Scan',
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,8 @@ function netdiagGeneratePdf($db, $protocol, $outputlangs)
|
||||||
netdiagPdfDns($pdf, $m->result);
|
netdiagPdfDns($pdf, $m->result);
|
||||||
} elseif ($m->tool === 'geraetediff') {
|
} elseif ($m->tool === 'geraetediff') {
|
||||||
netdiagPdfGeraeteDiff($pdf, $m->result);
|
netdiagPdfGeraeteDiff($pdf, $m->result);
|
||||||
|
} elseif ($m->tool === 'sipcheck') {
|
||||||
|
netdiagPdfSip($pdf, $m->result);
|
||||||
} else {
|
} else {
|
||||||
$pdf->MultiCell(180, 5, netdiagPdfFlattenResult($m->result), 1, 'L');
|
$pdf->MultiCell(180, 5, netdiagPdfFlattenResult($m->result), 1, 'L');
|
||||||
}
|
}
|
||||||
|
|
@ -831,7 +833,15 @@ function netdiagPdfWifiKanal($pdf, $json)
|
||||||
|
|
||||||
if (!empty($data['warnungen']) && is_array($data['warnungen'])) {
|
if (!empty($data['warnungen']) && is_array($data['warnungen'])) {
|
||||||
foreach ($data['warnungen'] as $w) {
|
foreach ($data['warnungen'] as $w) {
|
||||||
$pdf->MultiCell(180, 5, '! '.dol_trunc(netdiagPdfText($w), 160), 1, 'L');
|
/*
|
||||||
|
* Ungekürzt. Vorher stand hier dol_trunc(..., 160) — und genau die
|
||||||
|
* Begründung fiel weg: „…blockiert damit 2 der 3 störungsfreien
|
||||||
|
* Kanäle. In dicht besiedelter Umgebung meist ein Fehle…". Die
|
||||||
|
* Warnung ohne ihren Grund ist im Kundendokument wertlos, und
|
||||||
|
* MultiCell bricht ohnehin sauber um.
|
||||||
|
*/
|
||||||
|
netdiagPdfEnsureSpace($pdf, 10);
|
||||||
|
$pdf->MultiCell(180, 5, '! '.netdiagPdfText(netdiagKundentext((string) $w)), 1, 'L');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -861,3 +871,114 @@ function netdiagPdfWifiKanal($pdf, $json)
|
||||||
$pdf->Cell(25, 5, (string) ($n['rssi'] ?? '').' dBm', 1, 1, 'R');
|
$pdf->Cell(25, 5, (string) ($n['rssi'] ?? '').' dBm', 1, 1, 'R');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SIP-Erreichbarkeit ins PDF schreiben.
|
||||||
|
*
|
||||||
|
* Eigener Zweig, weil die entscheidende Aussage sonst untergeht: „401
|
||||||
|
* Unauthorized" sieht in einer flachen Schlüssel/Wert-Liste wie ein Fehler
|
||||||
|
* aus, ist aber der Beweis für einen erreichbaren Anschluss. Deshalb steht
|
||||||
|
* hier der Klartext-Befund zuerst und in eigener Zeile — er ist das, was der
|
||||||
|
* Kunde und der nächste Techniker lesen.
|
||||||
|
*
|
||||||
|
* @param TCPDF $pdf PDF-Objekt (Cursor steht direkt hinter der Titelzeile)
|
||||||
|
* @param string $json result-JSON der Messung
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function netdiagPdfSip($pdf, $json)
|
||||||
|
{
|
||||||
|
$data = json_decode((string) $json, true);
|
||||||
|
if (!is_array($data)) {
|
||||||
|
$pdf->MultiCell(180, 5, netdiagPdfFlattenResult($json), 1, 'L');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kopfzeile: Ziel, Port, Antwort
|
||||||
|
$sum = array();
|
||||||
|
if (!empty($data['ziel'])) {
|
||||||
|
$teil = 'Ziel: '.$data['ziel'];
|
||||||
|
if (!empty($data['zielIp']) && $data['zielIp'] !== $data['ziel']) {
|
||||||
|
$teil .= ' ('.$data['zielIp'].')';
|
||||||
|
}
|
||||||
|
$sum[] = $teil;
|
||||||
|
}
|
||||||
|
if (!empty($data['zielPort'])) {
|
||||||
|
$sum[] = 'Port '.$data['zielPort'];
|
||||||
|
}
|
||||||
|
if (!empty($data['statuszeile'])) {
|
||||||
|
$sum[] = 'Antwort: '.$data['statuszeile'];
|
||||||
|
} else {
|
||||||
|
$sum[] = 'Antwort: keine';
|
||||||
|
}
|
||||||
|
if (!empty($data['antwortWeg'])) {
|
||||||
|
$sum[] = 'über '.strtoupper((string) $data['antwortWeg']);
|
||||||
|
}
|
||||||
|
if (!empty($sum)) {
|
||||||
|
$pdf->MultiCell(180, 5, netdiagPdfText(implode(' | ', $sum)), 1, 'L');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Der Befund im Klartext — die eigentliche Aussage der Messung
|
||||||
|
if (!empty($data['befund'])) {
|
||||||
|
netdiagPdfEnsureSpace($pdf, 10);
|
||||||
|
$pdf->MultiCell(180, 5, netdiagPdfText(netdiagKundentext((string) $data['befund'])), 1, 'L');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Je Transportweg eine Zeile: erst damit ist belegbar, ob UDP still blieb
|
||||||
|
// und nur TCP antwortete (Firewall) oder ob gar nichts kam.
|
||||||
|
$versuche = (isset($data['versuche']) && is_array($data['versuche'])) ? $data['versuche'] : array();
|
||||||
|
if (!empty($versuche)) {
|
||||||
|
netdiagPdfEnsureSpace($pdf, 10);
|
||||||
|
$pdf->SetFont('', 'B', 8);
|
||||||
|
$pdf->Cell(180, 5, 'Versuche je Transportweg', 1, 1, 'L');
|
||||||
|
$pdf->SetFont('', '', 8);
|
||||||
|
foreach ($versuche as $v) {
|
||||||
|
if (!is_array($v)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$zeile = (string) ($v['transport'] ?? '?');
|
||||||
|
if (!empty($v['antwort'])) {
|
||||||
|
$zeile .= ': '.$v['antwort'];
|
||||||
|
} elseif (!empty($v['hinweis'])) {
|
||||||
|
$zeile .= ': '.$v['hinweis'];
|
||||||
|
} else {
|
||||||
|
$zeile .= ': keine Antwort';
|
||||||
|
}
|
||||||
|
if (isset($v['laufzeitMs']) && $v['laufzeitMs'] !== null && $v['laufzeitMs'] !== '') {
|
||||||
|
$zeile .= ' ('.$v['laufzeitMs'].' ms)';
|
||||||
|
}
|
||||||
|
netdiagPdfEnsureSpace($pdf, 5, function ($p) {
|
||||||
|
$p->SetFont('', 'B', 8);
|
||||||
|
$p->Cell(180, 5, 'Versuche je Transportweg — Fortsetzung', 1, 1, 'L');
|
||||||
|
$p->SetFont('', '', 8);
|
||||||
|
});
|
||||||
|
$pdf->MultiCell(180, 5, netdiagPdfText(netdiagKundentext($zeile)), 1, 'L');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gegenstelle und beherrschte Methoden — Beleg dafür, WAS dort antwortet
|
||||||
|
$rest = array();
|
||||||
|
if (!empty($data['gegenstelle'])) {
|
||||||
|
$rest[] = 'Gegenstelle: '.$data['gegenstelle'];
|
||||||
|
}
|
||||||
|
if (!empty($data['unterstuetzteMethoden'])) {
|
||||||
|
$rest[] = 'Unterstützte Methoden: '.$data['unterstuetzteMethoden'];
|
||||||
|
}
|
||||||
|
if (!empty($data['zielHerkunft'])) {
|
||||||
|
$rest[] = 'Ziel: '.$data['zielHerkunft'];
|
||||||
|
}
|
||||||
|
if (!empty($rest)) {
|
||||||
|
netdiagPdfEnsureSpace($pdf, 8);
|
||||||
|
$pdf->MultiCell(180, 5, netdiagPdfText(netdiagKundentext(implode(' | ', $rest))), 1, 'L');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grenze der Aussage zum Schluss — im Kundendokument unverzichtbar:
|
||||||
|
// gemessen ist die Erreichbarkeit, NICHT die Sprachqualität.
|
||||||
|
foreach (array('hinweis', 'verfahren') as $feld) {
|
||||||
|
if (!empty($data[$feld])) {
|
||||||
|
netdiagPdfEnsureSpace($pdf, 8);
|
||||||
|
$pdf->SetFont('', 'I', 7);
|
||||||
|
$pdf->MultiCell(180, 4, netdiagPdfText(netdiagKundentext((string) $data[$feld])), 1, 'L');
|
||||||
|
$pdf->SetFont('', '', 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue