Fehlerausgabe, stiller Mailversand und fehlende Registrierungs-Mail

Drei zusammenhaengende Punkte aus der Analyse des Login-Problems.

1. PHP-Fehler wurden an Besucher ausgegeben

display_errors war in impfwarteliste.php (oeffentlich), intern/
impfwarteliste.php, intern/neueanfrage.php, den beiden neueanfrage-old
Sicherungen und zeiterfassung/api/vacations.php fest eingeschaltet.
Die oeffentliche Impfwarteliste zeigte Patienten bei einem Fatal Error
sogar Meldung, Dateipfad und Zeilennummer. Ueberall auf log_errors
umgestellt: E_ALL wird weiterhin vollstaendig erfasst, landet aber im
Server-Log statt auf der Seite. Der Shutdown-Handler der Impfwarteliste
protokolliert die Details und zeigt nur noch einen neutralen Hinweis.
Auch register.php gab die rohe Exception-Meldung aus.

2. SendMailMessageSilent() verschluckte jeden Fehler

Der catch-Block war leer. Ein SMTP-Ausfall war dadurch von aussen nicht
von einem falschen Code zu unterscheiden - der Benutzer landete auf
verify_2fa.php und wartete auf eine Mail, die nie kam. Die Funktion
protokolliert jetzt und liefert einen bool zurueck. login.php wertet
das aus, nimmt bei Fehlschlag den 2FA-Datensatz und die Session-Vormerkung
zurueck und sagt es auf der Login-Seite, statt weiterzuleiten.
Nebenbei entfernt: ein uebrig gebliebenes echo, das den Mailserver-Namen
mitten in die Seite schrieb, sowie ein zweites mysqli_fetch_assoc() auf
demselben Result, das nur NULL liefern konnte.

3. register.php verschickte keine Bestaetigungsmail

mailreg blieb 0, jeder neue Benutzer landete nach dem Login auf der
Aufforderung, die Authentifizierung selbst anzustossen. Die Mail geht
jetzt direkt nach der Registrierung raus. Erzeugung und Text liegen in
der neuen Funktion sendeAuthentifizierungsMail(), die authmeldung.php
ebenfalls benutzt - dort wurde der Rueckgabewert des Versands bisher
einer Variablen zugewiesen und nie ausgewertet, die Seite meldete
Erfolg auch bei fehlgeschlagenem Versand.

Der Versand laeuft nach dem commit(), deshalb prueft der catch-Block in
register.php jetzt inTransaction(), bevor er rollBack() aufruft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 20:53:10 +02:00
co-authored by Claude Opus 5
parent 3b08be899c
commit e5f6482811
10 changed files with 156 additions and 56 deletions
+73 -10
View File
@@ -2916,17 +2916,75 @@ function loadAktuelleUrlaubsInfo(PDO $pdo): ?array
}
/**
* Erzeugt einen Authentifizierungscode fuer ein intern_users-Konto und schickt
* dem Benutzer den Bestaetigungslink.
*
* Wird von register.php (direkt nach der Anmeldung) und von authmeldung.php
* (manuelle Anforderung) benutzt, damit beide denselben Text und dieselbe
* Code-Erzeugung verwenden.
*
* passwortcode_time wird mit NOW() gesetzt, also mit der Uhr des DB-Servers -
* authentifizierung.php prueft die Gueltigkeit ebenfalls dort.
*
* @return bool true, wenn die Mail uebergeben werden konnte
*/
function sendeAuthentifizierungsMail(PDO $pdo, array $user, string $organisationsname): bool
{
$passwortcode = random_string();
$stmt = $pdo->prepare("
UPDATE intern_users
SET passwortcode = :passwortcode, passwortcode_time = NOW()
WHERE id = :userid
");
$stmt->execute([
'passwortcode' => sha1($passwortcode),
'userid' => $user['id']
]);
$url = getSiteURL() . 'authentifizierung.php?userid=' . urlencode((string)$user['id'])
. '&code=' . urlencode($passwortcode);
$betreff = 'Authentifizierung für Ihren Account bei ' . $organisationsname;
$text = 'Hallo ' . htmlentities((string)$user['vorname']) . ',<br><br>
für die Nutzung des Kontos müssen Sie das Konto per E-Mail authentifizieren. Dazu klicken Sie auf den folgenden Link:<br>
' . $url . '
<br><br>
Nach der Authentifizierung können Sie das Konto vollumfänglich nutzen.<br><br>
Haben Sie kein Konto bei uns angelegt, ignorieren Sie diese E-Mail.<br><br>
Viele Grüße,<br>
Ihr ' . $organisationsname . ' Team';
return SendMailMessage($pdo, (string)$user['email'], $betreff, $text);
}
/**
* Verschickt eine Mail, ohne die aufrufende Seite abzubrechen.
* "Silent" heisst: keine Ausgabe und keine Exception nach aussen - der Fehler
* landet aber im Server-Log, und der Rueckgabewert sagt, ob es geklappt hat.
* Frueher wurde jeder Fehler ersatzlos verschluckt; ein stiller SMTP-Ausfall
* war dadurch von aussen nicht von einem falschen Code zu unterscheiden.
*
* @return bool true, wenn die Mail uebergeben werden konnte
*/
function SendMailMessageSilent($con, $empfaenger, $betreff, $body){
// LOGIN CONFIG AUSLESEN
$queryconfig = mysqli_query($con, "Select * FROM config");
$rowconfig = mysqli_fetch_assoc($queryconfig);
if($queryconfig->num_rows == 1){
$row = mysqli_fetch_assoc($queryconfig);
$userid = $row["mailserver"];
echo $userid;
if($queryconfig === false){
error_log("SendMailMessageSilent: config-Tabelle nicht lesbar: " . mysqli_error($con));
return false;
}
$rowconfig = mysqli_fetch_assoc($queryconfig);
if($rowconfig === null){
error_log("SendMailMessageSilent: kein Datensatz in der Tabelle config");
return false;
}
$mailserver = $rowconfig["mailserver"];
$mailUsername = $rowconfig["mailUsername"];
$mailPassword = $rowconfig["mailPassword"];
@@ -2968,11 +3026,16 @@ function SendMailMessageSilent($con, $empfaenger, $betreff, $body){
//$mail->Encoding = 'base64';
$mail->send();
return true;
} catch (Exception $e) {
// Nicht nach aussen werfen, aber auch nicht verschweigen.
error_log(sprintf(
'SendMailMessageSilent: Versand an %s fehlgeschlagen: %s',
(string)$empfaenger,
$mail->ErrorInfo !== '' ? $mail->ErrorInfo : $e->getMessage()
));
return false;
}
}