Compare commits

...

4 commits

Author SHA1 Message Date
8f23d417a3 Trigger: Modul-Deploy [deploy]
All checks were successful
Deploy netdiag / deploy (push) Successful in 14s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 06:41:17 +02:00
2c5f7cf11b Feldtabelle fuer das Werkzeug "DNS-Pruefung"
gefragteServer und antworten in die Kunden-Whitelist, dnscheck in die
Werkzeugliste. Ohne diese drei Zeilen stuende im Kundendokument nur die
Ampel - die einzelnen Serverzeilen sind das eigentliche Ergebnis.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 23:24:47 +02:00
0f37cae9e5 Drei Falschaussagen im Kundendokument, alle aus Altdaten
"0 DHCP-Server (!)" in Rot: In der Produktionsdatenbank stehen drei
ausgelieferte Messungen des entfernten Werkzeugs dhcpcheck mit Ergebnis
{"count":0,"server":[],"hinweis":""} und Status 2. Bei Kabelverbindung gibt
Android die DHCP-Angaben aber grundsaetzlich nicht heraus (nur DhcpInfo, nur
WLAN, deprecated) - gemessen wurde also nichts, "0 gefunden" war der
Rueckgabewert fuer "nicht ermittelbar". netdiagAltlastKorrektur() zeigt diese
Messungen jetzt als "nicht messbar" mit Erklaerung, in PDF und
Technikeransicht. Rohdaten bleiben unangetastet, korrigiert wird nur die
Darstellung - und die wird bei jedem Abruf neu erzeugt. Die Ergebniszahlen
werden dabei unterdrueckt: "Gefundene Geraete: 0" widerspraeche der Aussage
direkt darueber.

"Lease-Dauer: 864000 s s": aeltere App-Fassungen haben die Einheit in den Wert
geschrieben, die Feldtabelle haengt sie erneut an (Prod-Messung #42).

Adress- und Lease-Felder mit dem Wert 0 erscheinen jetzt als "nicht
ermittelbar" statt als "0" - das war nie eine Messung, sondern das
"nichts ermittelt" der alten Android-API.

Neu in der Whitelist: dhcpQuelle (system = LinkProperties ab Android 11 fuer
jeden Anschlusstyp, wlan = alter Weg nur fuer WLAN). Damit ist klaerbar, ob
eine fehlende DHCP-Angabe an der Leitung lag oder an der Android-Version.

Geprueft gegen die lokale Testinstanz mit einer Kopie der echten
Prod-Messungen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 23:11:07 +02:00
b2ab430ae7 Internet-Kette im PDF + Pfeile wurden als "?" gedruckt
netdiagPdfKette() fuer das neue App-Werkzeug: Fehlerglied als eigene
hervorgehobene Zeile, darunter die vier Stufen einzeln, dann Systemurteil
und Hinweis. Ohne eigenen Zweig stuenden die Stufen als |-Kette in einer
Zelle und das Fehlerglied - die eigentliche Aussage - mittendrin.

Dabei ein Fehler gefunden, der jedes Protokoll betrifft: pdf_getPDFFont()
liefert Helvetica, einen Core-Font mit WinAnsi-Kodierung. Alles ausserhalb
dieses Zeichenvorrats setzt TCPDF wortlos als "?" (KB #1025). Aufgefallen
an "www.google.de -> 142.250.185.67", das im Kundendokument als
"www.google.de ? 142.250.185.67" ankam. netdiagPdfText() ersetzt die
betroffenen Zeichen jetzt in ALLEN PDF-Zweigen, also auch fuer Altdaten.
Bewusst keine Unicode-Schrift: dejavusans wuerde Schriftbild und Dateigroesse
aller Protokolle aendern. Gedankenstrich, Mittelpunkt und Anfuehrungszeichen
sind in WinAnsi enthalten und bleiben unangetastet (nachgeprueft).

Feld-Whitelist um fehlerglied, stufen, systemUrteil, validated und
captivePortal erweitert. Die letzten beiden kommen aus dem LinkInfo-Objekt
und erscheinen damit auch beim IP-Test an der Dose.

Geprueft an vier Faellen gegen die lokale Testinstanz, zwei davon die echten
Emulator-Messungen dieser Nacht (Gutfall und Flugmodus).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 22:59:49 +02:00
5 changed files with 300 additions and 14 deletions

View file

@ -1,5 +1,73 @@
# Changelog NetDiag # Changelog NetDiag
## 1.1.5 — 2026-08-16
### Feldtabelle für das neue Werkzeug „DNS-Prüfung"
Die App fragt jeden DNS-Server des Netzes einzeln und namentlich (eigener
UDP-Client auf Port 53). Damit die Aussage im Kundendokument ankommt, sind
`gefragteServer` und `antworten` in der Whitelist ergänzt und `dnscheck` in
der Werkzeugliste eingetragen — ohne diese drei Zeilen stünde dort nur die
Ampel. Die einzelnen Serverzeilen („192.168.1.1: antwortet, kennt den Namen
nicht") sind das eigentliche Ergebnis.
## 1.1.4 — 2026-08-16
### Drei Falschaussagen im Kundendokument, alle aus Altdaten
- **„0 DHCP-Server (!)" in Rot.** In der Produktionsdatenbank stehen drei
ausgelieferte Messungen des entfernten Werkzeugs `dhcpcheck` mit Ergebnis
`{"count":0,"server":[],"hinweis":""}` und Status 2. Bei einer Kabelverbindung
gibt Android die DHCP-Angaben aber grundsätzlich nicht heraus (nur `DhcpInfo`,
nur WLAN, deprecated) — gemessen wurde also nichts, „0 gefunden" war der
Rückgabewert für „nicht ermittelbar". `netdiagAltlastKorrektur()` zeigt diese
Messungen jetzt als „nicht messbar" mit Erklärung, in PDF **und**
Technikeransicht. Die gespeicherten Rohdaten bleiben unangetastet (Beleg);
korrigiert wird nur die Darstellung, und die wird bei jedem Abruf neu erzeugt.
Die Ergebniszahlen werden bei so korrigierten Messungen unterdrückt —
„Gefundene Geräte: 0" widerspräche der Aussage direkt darüber.
- **„Lease-Dauer: 864000 s s".** Ältere App-Fassungen haben die Einheit in den
Wert geschrieben, die Feldtabelle hängt sie erneut an. Nachgewiesen an
Prod-Messung #42. Die Einheit wird jetzt nur noch angehängt, wenn sie nicht
schon am Wert steht.
- **Adress- und Lease-Felder mit dem Wert 0** (`server`, `dhcpServer`,
`gateway`, `ipv4`, `lease` …) sind keine Messung, sondern das „nichts
ermittelt" der alten Android-API. Sie erscheinen jetzt als „nicht ermittelbar"
statt als „0".
Neues Feld in der Whitelist: `dhcpQuelle``system` (LinkProperties, ab
Android 11, gilt für jeden Anschlusstyp) oder `wlan` (alter Weg, nur WLAN, dafür
mit Lease-Dauer). Damit ist im Nachhinein klärbar, ob eine fehlende DHCP-Angabe
an der Leitung lag oder an der Android-Version.
## 1.1.3 — 2026-08-16
### Internet-Kette im PDF + ein Zeichenfehler, der jedes Protokoll betraf
- **`netdiagPdfKette()`** für das neue App-Werkzeug „Internet-Kette": Fehlerglied
als eigene hervorgehobene Zeile, darunter die vier geprüften Stufen einzeln,
dann Systemurteil und Hinweis. Ohne eigenen Zweig stünden die Stufen als
`|`-Kette in einer Zelle und das Fehlerglied — die eigentliche Aussage —
mittendrin.
- **`netdiagPdfText()`: Pfeile wurden als „?" gedruckt.** `pdf_getPDFFont()`
liefert hier Helvetica, einen Core-Font mit WinAnsi-Kodierung; alles außerhalb
dieses Zeichenvorrats setzt TCPDF wortlos als „?" (bekannt aus KB #1025).
Aufgefallen an „www.google.de → 142.250.185.67", das im Kundendokument als
„www.google.de ? 142.250.185.67" ankam — der Pfeil ist dort kein Schmuck,
er trennt Frage und Antwort. Die Ersetzung greift jetzt in **allen**
PDF-Zweigen, also auch für Altdaten und künftige Werkzeuge.
Bewusst keine Unicode-Schrift: `dejavusans` würde Schriftbild und Dateigröße
aller Protokolle ändern. Gedankenstrich, Mittelpunkt, Auslassungspunkte und
Anführungszeichen sind in WinAnsi enthalten und bleiben unangetastet
(im erzeugten Dokument nachgeprüft).
- Feld-Whitelist um `fehlerglied`, `stufen`, `systemUrteil`, `validated` und
`captivePortal` erweitert, Werkzeugname `internetkette` → „Internet-Kette".
`validated`/`captivePortal` kommen aus dem LinkInfo-Objekt und erscheinen
damit auch beim IP-Test an der Dose.
Geprüft an vier Fällen gegen die lokale Testinstanz, zwei davon sind die echten
Emulator-Messungen dieser Nacht (Gutfall und Flugmodus).
## 1.1.2 — 2026-08-16 ## 1.1.2 — 2026-08-16
### Geräte-Monitor bekommt einen eigenen PDF-Zweig ### Geräte-Monitor bekommt einen eigenen PDF-Zweig

View file

@ -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.1.2'; $this->version = '1.1.5';
// 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);

View file

@ -345,6 +345,19 @@ function netdiagKundenfelder()
'aussetzer' => array('Aussetzer', ''), 'aussetzer' => array('Aussetzer', ''),
'geraete' => array('Je Gerät', ''), 'geraete' => array('Je Gerät', ''),
'ausfaelle' => array('Einzelne Ausfälle', ''), 'ausfaelle' => array('Einzelne Ausfälle', ''),
// Internet-Kette (Anschluss → Gateway → Namensauflösung → HTTPS).
// 'fehlerglied' ist die eigentliche Aussage des Werkzeugs — ohne diesen
// Eintrag stünde im Kundendokument nur die Ampel.
'fehlerglied' => array('Fehlerglied', ''),
'stufen' => array('Geprüfte Stufen', ''),
'systemUrteil' => array('Urteil des Betriebssystems', ''),
// Kommen aus dem LinkInfo-Objekt und damit auch im IP-Test (Dose) vor
'validated' => array('Internetverbindung bestätigt', ''),
'captivePortal' => array('Anmeldeseite erkannt', ''),
// DNS-Prüfung: je ein Paket an je einen Server. `antworten` ist die
// eigentliche Aussage — welcher Server antwortet und welcher nicht.
'gefragteServer' => array('Befragte DNS-Server', ''),
'antworten' => array('Antworten der Server', ''),
// Netz/DHCP // Netz/DHCP
'server' => array('DHCP-Server', ''), 'server' => array('DHCP-Server', ''),
'lease' => array('Lease-Dauer', 's'), 'lease' => array('Lease-Dauer', 's'),
@ -385,6 +398,9 @@ function netdiagKundenfelder()
'ipv4' => array('IP-Adresse', ''), 'ipv4' => array('IP-Adresse', ''),
'prefixLength' => array('Präfixlänge', ''), 'prefixLength' => array('Präfixlänge', ''),
'dhcpServer' => array('DHCP-Server', ''), 'dhcpServer' => array('DHCP-Server', ''),
// 'system' = vom Betriebssystem gemeldet (gilt für jeden Anschlusstyp),
// 'wlan' = alter WLAN-Weg. Macht einen fehlenden Wert einordenbar.
'dhcpQuelle' => array('Quelle der DHCP-Angabe', ''),
'leaseSec' => array('Lease-Dauer', 's'), 'leaseSec' => array('Lease-Dauer', 's'),
'linkSpeedMbps' => array('Verbindungsgeschwindigkeit', 'Mbit/s'), 'linkSpeedMbps' => array('Verbindungsgeschwindigkeit', 'Mbit/s'),
'rxLinkSpeedMbps' => array('Empfangsgeschwindigkeit', 'Mbit/s'), 'rxLinkSpeedMbps' => array('Empfangsgeschwindigkeit', 'Mbit/s'),
@ -422,6 +438,51 @@ function netdiagKundenfelder()
); );
} }
/**
* Bekannte Falschaussagen aus Altmessungen bei der Anzeige geraderücken.
*
* Betrifft das entfernte Werkzeug `dhcpcheck`. In der Produktionsdatenbank
* stehen drei ausgelieferte Messungen mit dem Label „0 DHCP-Server (!)",
* Ergebnis `{"count":0,"server":[],"hinweis":""}` und **Status 2 (rot)** eine
* Aussage über das Kundennetz, welche die Messung nie hergab: bei einer
* Kabelverbindung gibt Android die DHCP-Lease grundsätzlich nicht heraus (sie
* steckt nur im deprecated `DhcpInfo` und nur für WLAN). Gemessen wurde also
* nichts; „0 gefunden" ist der Rückgabewert für „nicht ermittelbar".
*
* Korrigiert wird bei der **Anzeige**, nicht in der Datenbank: die gespeicherte
* Messung bleibt unangetastet (Rohdaten sind Beleg), aber jedes neu erzeugte
* Kundendokument zeigt statt der roten Ampel ein ehrliches „nicht messbar".
*
* @param string $tool Werkzeug-ID der Messung
* @param int $status gespeicherter Status
* @param string $label gespeichertes Label
* @param string $json gespeichertes Ergebnis-JSON
* @return array{status:int,label:string,hinweis:string} korrigierte Anzeige
*/
function netdiagAltlastKorrektur($tool, $status, $label, $json)
{
$out = array('status' => (int) $status, 'label' => (string) $label, 'hinweis' => '');
if ($tool !== 'dhcpcheck') {
return $out;
}
$data = json_decode((string) $json, true);
if (!is_array($data)) {
return $out;
}
$leer = (isset($data['count']) && (int) $data['count'] === 0)
&& (!isset($data['server']) || $data['server'] === array() || $data['server'] === '');
if (!$leer) {
return $out;
}
$out['status'] = 3; // nicht messbar
$out['label'] = 'DHCP-Server nicht ermittelbar';
$out['hinweis'] = 'Diese Messung stammt aus einer früheren App-Fassung. Bei einer '
.'Kabelverbindung gibt Android die DHCP-Angaben nicht heraus — es wurde also nichts '
.'gemessen. Die frühere Darstellung („0 DHCP-Server") las sich wie ein Befund über '
.'das Kundennetz und war keiner.';
return $out;
}
/** /**
* Sekundenwert lesbar machen (aus „8123456" wird „94 Tage 0 Std"). * Sekundenwert lesbar machen (aus „8123456" wird „94 Tage 0 Std").
* *
@ -490,11 +551,36 @@ function netdiagFeldFuerKunde($key, $val)
return null; // nicht ermittelt — lieber weglassen als „: " drucken return null; // nicht ermittelt — lieber weglassen als „: " drucken
} }
/*
* Adressfelder mit dem Wert 0 bzw. 0.0.0.0 sind KEINE Messung, sondern der
* Rückgabewert „nichts ermittelt" der alten Android-API. In ausgelieferten
* Protokollen steht deshalb „DHCP-Server: 0" — eine Angabe, die es so im
* Kundennetz nie gab, und bei einer Kabelverbindung schlicht der Umstand,
* dass Android die Lease dort gar nicht herausgibt (nur WLAN, deprecated).
* Rückwirkend wirksam: Protokoll-PDFs werden bei jedem Abruf neu erzeugt.
* Lease-Dauer 0 fällt in dieselbe Kategorie.
*/
$adressfelder = array('server', 'dhcpServer', 'gateway', 'dns', 'ipv4', 'ip');
if (in_array($key, $adressfelder, true) && ($val === 0 || $val === '0' || $val === '0.0.0.0')) {
return $label.': nicht ermittelbar';
}
if (in_array($key, array('lease', 'leaseSec'), true) && ($val === 0 || $val === '0')) {
return $label.': nicht ermittelbar';
}
// Sekundenwerte lesbar machen statt sechsstellige Zahlen zu drucken // Sekundenwerte lesbar machen statt sechsstellige Zahlen zu drucken
if ($einheit === 's' && is_numeric($val) && $val >= 3600) { if ($einheit === 's' && is_numeric($val) && $val >= 3600) {
return $label.': '.netdiagDauerLesbar($val); return $label.': '.netdiagDauerLesbar($val);
} }
$text = netdiagKundentext((string) $val); $text = netdiagKundentext((string) $val);
/*
* Einheit nicht doppelt anhängen. Ältere App-Fassungen haben sie in den
* Wert geschrieben („864000 s"); im Kundendokument stand dadurch
* „Lease-Dauer: 864000 s s". Nachgewiesen an der Prod-Messung #42.
*/
if ($einheit !== '' && preg_match('/\s'.preg_quote($einheit, '/').'$/u', $text)) {
return $label.': '.$text;
}
return $label.': '.$text.($einheit !== '' ? ' '.$einheit : ''); return $label.': '.$text.($einheit !== '' ? ' '.$einheit : '');
} }
@ -560,10 +646,12 @@ function netdiagToolName($tool)
'traceroute' => 'Traceroute', 'traceroute' => 'Traceroute',
'stresstest' => 'Dauer-/Stresstest', 'stresstest' => 'Dauer-/Stresstest',
'iperf' => 'Durchsatz-Test', 'iperf' => 'Durchsatz-Test',
'internetkette' => 'Internet-Kette',
'wifikanal' => 'WLAN-Kanalanalyse', 'wifikanal' => 'WLAN-Kanalanalyse',
'monitor' => 'Geräte-Monitor', 'monitor' => 'Geräte-Monitor',
'iptest' => 'IP-Test (Dose)', 'iptest' => 'IP-Test (Dose)',
'wifitrack' => 'WLAN-Empfang', 'wifitrack' => 'WLAN-Empfang',
'dnscheck' => 'DNS-Prüfung',
// 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',

View file

@ -161,7 +161,11 @@ function netdiagGeneratePdf($db, $protocol, $outputlangs)
// stünde im PDF doppelt "OK OK". // stünde im PDF doppelt "OK OK".
$statusmarks = array(0 => '', 1 => '! ', 2 => 'X ', 3 => '? '); $statusmarks = array(0 => '', 1 => '! ', 2 => 'X ', 3 => '? ');
foreach ($measurements as $m) { foreach ($measurements as $m) {
$st = (int) $m->measure_status; // Bekannte Falschaussagen aus Altmessungen geraderücken (siehe
// netdiagAltlastKorrektur() — betrifft das entfernte Werkzeug dhcpcheck,
// dessen „0 DHCP-Server (!)" in Rot in ausgelieferten Protokollen steht).
$korr = netdiagAltlastKorrektur($m->tool, $m->measure_status, $m->label, $m->result);
$st = (int) $korr['status'];
if ($st < 0 || $st > 3) { if ($st < 0 || $st > 3) {
$st = 1; // unbekannter Wert -> als Warnung behandeln, nie als OK $st = 1; // unbekannter Wert -> als Warnung behandeln, nie als OK
} }
@ -182,24 +186,40 @@ function netdiagGeneratePdf($db, $protocol, $outputlangs)
netdiagPdfEnsureSpace($pdf, 11); netdiagPdfEnsureSpace($pdf, 11);
$pdf->SetFont('', 'B', 9); $pdf->SetFont('', 'B', 9);
// Klarname statt interner ID — „ipscan" sagt dem Kunden nichts // Klarname statt interner ID — „ipscan" sagt dem Kunden nichts
$title = netdiagToolName($m->tool).($m->label ? ' — '.$m->label : ''); $title = netdiagToolName($m->tool).($korr['label'] ? ' — '.$korr['label'] : '');
$pdf->Cell(150, 6, dol_trunc($title, 80), 1, 0, 'L'); $pdf->Cell(150, 6, dol_trunc($title, 80), 1, 0, 'L');
$pdf->Cell(30, 6, $statusmarks[$st].$statuslabels[$st], 1, 1, 'C', true); $pdf->Cell(30, 6, $statusmarks[$st].$statuslabels[$st], 1, 1, 'C', true);
$pdf->SetFont('', '', 8); $pdf->SetFont('', '', 8);
// Messparameter: ohne sie steht das Ergebnis ohne Bezug da — man sieht // Messparameter: ohne sie steht das Ergebnis ohne Bezug da — man sieht
// nicht, gegen welches Ziel gemessen wurde (Prod-Messung #126). // nicht, gegen welches Ziel gemessen wurde (Prod-Messung #126).
if ($korr['hinweis'] !== '') {
$pdf->SetFont('', 'I', 7);
$pdf->MultiCell(180, 4, netdiagPdfText($korr['hinweis']), 1, 'L');
$pdf->SetFont('', '', 8);
}
$params = netdiagFormatParams($m->params); $params = netdiagFormatParams($m->params);
if ($params !== '') { if ($params !== '') {
$pdf->SetFont('', 'I', 7); $pdf->SetFont('', 'I', 7);
$pdf->MultiCell(180, 4, $params, 1, 'L'); $pdf->MultiCell(180, 4, netdiagPdfText($params), 1, 'L');
$pdf->SetFont('', '', 8); $pdf->SetFont('', '', 8);
} }
/*
* Bei einer als Altlast korrigierten Messung KEINE Zahlen mehr drucken:
* „Gefundene Geräte: 0 | DHCP-Server: keine" widerspricht der Aussage
* „nicht messbar" direkt darüber und liest sich wieder wie ein Befund.
* Der Erklärtext steht bereits hinter der Titelzeile.
*/
if ($korr['hinweis'] !== '') {
continue;
}
if ($m->tool === 'stresstest') { if ($m->tool === 'stresstest') {
netdiagPdfStressTest($pdf, $m->result); netdiagPdfStressTest($pdf, $m->result);
} elseif ($m->tool === 'wifikanal') { } elseif ($m->tool === 'wifikanal') {
netdiagPdfWifiKanal($pdf, $m->result); netdiagPdfWifiKanal($pdf, $m->result);
} elseif ($m->tool === 'monitor') { } elseif ($m->tool === 'monitor') {
netdiagPdfMonitor($pdf, $m->result); netdiagPdfMonitor($pdf, $m->result);
} elseif ($m->tool === 'internetkette') {
netdiagPdfKette($pdf, $m->result);
} else { } else {
$pdf->MultiCell(180, 5, netdiagPdfFlattenResult($m->result), 1, 'L'); $pdf->MultiCell(180, 5, netdiagPdfFlattenResult($m->result), 1, 'L');
} }
@ -222,6 +242,48 @@ function netdiagGeneratePdf($db, $protocol, $outputlangs)
return 1; return 1;
} }
/**
* Zeichen ersetzen, die der PDF-Standardzeichensatz nicht darstellen kann.
*
* `pdf_getPDFFont()` liefert in dieser Dolibarr-Installation Helvetica einen
* Core-Font mit WinAnsi-Kodierung, kein Unicode. Alles außerhalb dieses Vorrats
* druckt TCPDF als ?", ohne zu warnen (bekannt aus KB #1025, dort mit dem
* Ankreuzkästchen ).
*
* Aufgefallen am Pfeil in der Internet-Kette: aus
* „Namensauflösung: www.google.de 142.250.185.67" wurde im Kundendokument
* „www.google.de ? 142.250.185.67" — der Pfeil ist dort kein Schmuck, er
* trennt Frage und Antwort.
*
* Bewusst eine Ersetzung statt einer Unicode-Schrift: `dejavusans` würde jedes
* Zeichen können, aber Schriftbild und Dateigröße aller Protokolle ändern.
* Gedankenstrich, Mittelpunkt, Auslassungspunkte und Anführungszeichen sind in
* WinAnsi enthalten und bleiben unangetastet (im Dokument nachgeprüft).
*
* @param string $s Text aus der App oder aus Altdaten
* @return string druckbarer Text
*/
function netdiagPdfText($s)
{
return strtr((string) $s, array(
'→' => '->',
'←' => '<-',
'↔' => '<->',
'⇒' => '=>',
'✓' => 'ja',
'✔' => 'ja',
'✗' => 'nein',
'✘' => 'nein',
'≤' => '<=',
'≥' => '>=',
'≠' => '!=',
'☐' => '[ ]',
'☑' => '[x]',
'⚠' => '!',
'≈' => 'ca. ',
));
}
/** /**
* Mess-Ergebnis (JSON) als einzeiligen Text für PDF-Ausgabe. * Mess-Ergebnis (JSON) als einzeiligen Text für PDF-Ausgabe.
* *
@ -235,7 +297,7 @@ function netdiagPdfFlattenResult($json)
} }
$data = json_decode($json, true); $data = json_decode($json, true);
if (!is_array($data)) { if (!is_array($data)) {
return netdiagKundentext((string) $json); return netdiagPdfText(netdiagKundentext((string) $json));
} }
$parts = array(); $parts = array();
foreach ($data as $key => $val) { foreach ($data as $key => $val) {
@ -244,7 +306,7 @@ function netdiagPdfFlattenResult($json)
$parts[] = $feld; $parts[] = $feld;
} }
} }
return empty($parts) ? '-' : implode(' | ', $parts); return empty($parts) ? '-' : netdiagPdfText(implode(' | ', $parts));
} }
/** /**
@ -369,7 +431,69 @@ function netdiagPdfStressTest($pdf, $json)
$pdf->Cell(180, 5, 'Ausfälle ('.count($ausfaelle).')', 1, 1, 'L'); $pdf->Cell(180, 5, 'Ausfälle ('.count($ausfaelle).')', 1, 1, 'L');
$pdf->SetFont('', '', 8); $pdf->SetFont('', '', 8);
foreach ($ausfaelle as $line) { foreach ($ausfaelle as $line) {
$pdf->Cell(180, 5, dol_trunc((string) $line, 120), 1, 1, 'L'); $pdf->Cell(180, 5, dol_trunc(netdiagPdfText($line), 120), 1, 1, 'L');
}
}
/**
* Internet-Kette ins PDF schreiben: Fehlerglied zuerst, dann die Stufen.
*
* Ohne eigenen Zweig stünden die vier Stufen als `|`-Kette in einer Zelle und
* das Fehlerglied die eigentliche Aussage mittendrin. Beim Kunden wird
* genau diese eine Zeile gelesen: „woran liegt es".
*
* @param TCPDF $pdf PDF-Objekt (Cursor steht direkt hinter der Titelzeile)
* @param string $json result-JSON der Messung
* @return void
*/
function netdiagPdfKette($pdf, $json)
{
$data = json_decode((string) $json, true);
if (!is_array($data)) {
$pdf->MultiCell(180, 5, netdiagPdfFlattenResult($json), 1, 'L');
return;
}
// Fehlerglied als eigene, hervorgehobene Zeile
$glied = isset($data['fehlerglied']) ? trim((string) $data['fehlerglied']) : '';
if ($glied !== '') {
$pdf->SetFont('', 'B', 8);
$pdf->Cell(180, 5, $glied === 'keines'
? 'Kein Glied der Kette hat versagt.'
: 'Fehlerglied: '.$glied, 1, 1, 'L');
$pdf->SetFont('', '', 8);
}
$stufen = (isset($data['stufen']) && is_array($data['stufen'])) ? $data['stufen'] : array();
if (!empty($stufen)) {
netdiagPdfEnsureSpace($pdf, 10);
$pdf->SetFont('', 'B', 8);
$pdf->Cell(180, 5, 'Geprüfte Stufen', 1, 1, 'L');
$pdf->SetFont('', '', 8);
foreach ($stufen as $line) {
netdiagPdfEnsureSpace($pdf, 5, function ($p) {
$p->SetFont('', 'B', 8);
$p->Cell(180, 5, 'Geprüfte Stufen — Fortsetzung', 1, 1, 'L');
$p->SetFont('', '', 8);
});
// MultiCell statt Cell: die Stufenzeilen enthalten Fehlertexte des
// Systems („Unable to resolve host …"), die auch mal lang werden.
// Abschneiden würde ausgerechnet die Begründung kappen.
$pdf->MultiCell(180, 5, netdiagPdfText(netdiagKundentext((string) $line)), 1, 'L');
}
}
if (!empty($data['systemUrteil'])) {
netdiagPdfEnsureSpace($pdf, 8);
$pdf->SetFont('', 'I', 7);
$pdf->MultiCell(180, 4, netdiagPdfText(netdiagKundentext((string) $data['systemUrteil'])), 1, 'L');
$pdf->SetFont('', '', 8);
}
if (!empty($data['hinweis'])) {
netdiagPdfEnsureSpace($pdf, 8);
$pdf->SetFont('', 'I', 7);
$pdf->MultiCell(180, 4, netdiagPdfText(netdiagKundentext((string) $data['hinweis'])), 1, 'L');
$pdf->SetFont('', '', 8);
} }
} }
@ -401,7 +525,7 @@ function netdiagPdfMonitor($pdf, $json)
return; return;
} }
if (!empty($data['fehler']) || !empty($data['error'])) { if (!empty($data['fehler']) || !empty($data['error'])) {
$pdf->MultiCell(180, 5, netdiagKundentext((string) ($data['fehler'] ?? $data['error'])), 1, 'L'); $pdf->MultiCell(180, 5, netdiagPdfText(netdiagKundentext((string) ($data['fehler'] ?? $data['error']))), 1, 'L');
return; return;
} }
@ -448,7 +572,7 @@ function netdiagPdfMonitor($pdf, $json)
$p->Cell(180, 5, 'Überwachte Geräte ('.count($geraete).') — Fortsetzung', 1, 1, 'L'); $p->Cell(180, 5, 'Überwachte Geräte ('.count($geraete).') — Fortsetzung', 1, 1, 'L');
$p->SetFont('', '', 8); $p->SetFont('', '', 8);
}); });
$pdf->Cell(180, 5, dol_trunc((string) $line, 120), 1, 1, 'L'); $pdf->Cell(180, 5, dol_trunc(netdiagPdfText($line), 120), 1, 1, 'L');
} }
} }
@ -483,7 +607,7 @@ function netdiagPdfMonitor($pdf, $json)
$p->Cell(180, 5, 'Einzelne Ausfälle ('.count($ausfaelle).') — Fortsetzung', 1, 1, 'L'); $p->Cell(180, 5, 'Einzelne Ausfälle ('.count($ausfaelle).') — Fortsetzung', 1, 1, 'L');
$p->SetFont('', '', 8); $p->SetFont('', '', 8);
}); });
$pdf->Cell(180, 5, dol_trunc((string) $line, 120), 1, 1, 'L'); $pdf->Cell(180, 5, dol_trunc(netdiagPdfText($line), 120), 1, 1, 'L');
$i++; $i++;
} }
$rest = count($ausfaelle) - $max; $rest = count($ausfaelle) - $max;
@ -499,7 +623,7 @@ function netdiagPdfMonitor($pdf, $json)
if (!empty($data['hinweis'])) { if (!empty($data['hinweis'])) {
netdiagPdfEnsureSpace($pdf, 10); netdiagPdfEnsureSpace($pdf, 10);
$pdf->SetFont('', 'I', 7); $pdf->SetFont('', 'I', 7);
$pdf->MultiCell(180, 4, netdiagKundentext((string) $data['hinweis']), 1, 'L'); $pdf->MultiCell(180, 4, netdiagPdfText(netdiagKundentext((string) $data['hinweis'])), 1, 'L');
$pdf->SetFont('', '', 8); $pdf->SetFont('', '', 8);
} }
} }
@ -558,7 +682,7 @@ 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((string) $w, 160), 1, 'L'); $pdf->MultiCell(180, 5, '! '.dol_trunc(netdiagPdfText($w), 160), 1, 'L');
} }
} }

View file

@ -252,7 +252,10 @@ print '<th>'.$langs->trans("Tool").'</th><th>'.$langs->trans("Label").'</th>';
print '<th>'.$langs->trans("Result").'</th><th class="center">'.$langs->trans("MeasureStatus").'</th>'; print '<th>'.$langs->trans("Result").'</th><th class="center">'.$langs->trans("MeasureStatus").'</th>';
print '</tr>'; print '</tr>';
foreach ($measurements as $m) { foreach ($measurements as $m) {
$st = (int) $m->measure_status; // Dieselbe Korrektur wie im PDF, damit Technikeransicht und Kundendokument
// nicht auseinanderlaufen (netdiagAltlastKorrektur(), Werkzeug dhcpcheck).
$korr = netdiagAltlastKorrektur($m->tool, $m->measure_status, $m->label, $m->result);
$st = (int) $korr['status'];
// Unbekannte Werte nie als OK durchgehen lassen (Array-Zugriff waere sonst leer) // Unbekannte Werte nie als OK durchgehen lassen (Array-Zugriff waere sonst leer)
if ($st < 0 || $st > 3) { if ($st < 0 || $st > 3) {
$st = 1; $st = 1;
@ -261,7 +264,10 @@ foreach ($measurements as $m) {
print '<td class="nowraponall">'.dol_print_date($m->date_measure, 'dayhour').'</td>'; print '<td class="nowraponall">'.dol_print_date($m->date_measure, 'dayhour').'</td>';
print '<td>'.dol_escape_htmltag($m->category).'</td>'; print '<td>'.dol_escape_htmltag($m->category).'</td>';
print '<td>'.dol_escape_htmltag(netdiagToolName($m->tool)).'</td>'; print '<td>'.dol_escape_htmltag(netdiagToolName($m->tool)).'</td>';
print '<td>'.dol_escape_htmltag($m->label); print '<td>'.dol_escape_htmltag($korr['label']);
if ($korr['hinweis'] !== '') {
print '<br><span class="opacitymedium small">'.dol_escape_htmltag($korr['hinweis']).'</span>';
}
// Messparameter darunter: sonst ist nicht erkennbar, wogegen gemessen wurde // Messparameter darunter: sonst ist nicht erkennbar, wogegen gemessen wurde
$params = netdiagFormatParams($m->params); $params = netdiagFormatParams($m->params);
if ($params !== '') { if ($params !== '') {