diff --git a/impfwarteliste.php b/impfwarteliste.php index a80bf42..7ecb77f 100644 --- a/impfwarteliste.php +++ b/impfwarteliste.php @@ -8,8 +8,11 @@ ' - . '

Fehler in impfwarteliste.php

' - . '

Die Seite ist wegen eines PHP-Fehlers abgebrochen.

' - . '

Meldung: ' . htmlspecialchars((string)$error['message'], ENT_QUOTES, 'UTF-8') . '
' - . 'Datei: ' . htmlspecialchars((string)$error['file'], ENT_QUOTES, 'UTF-8') . '
' - . 'Zeile: ' . (int)$error['line'] . '

' + . '

Es ist ein Fehler aufgetreten

' + . '

Die Seite konnte leider nicht vollständig geladen werden. ' + . 'Bitte versuchen Sie es später noch einmal oder rufen Sie uns an.

' . ''; }); diff --git a/inc/functions.inc.php b/inc/functions.inc.php index 7a3038e..52dd015 100644 --- a/inc/functions.inc.php +++ b/inc/functions.inc.php @@ -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']) . ',

+für die Nutzung des Kontos müssen Sie das Konto per E-Mail authentifizieren. Dazu klicken Sie auf den folgenden Link:
+' . $url . ' +

+Nach der Authentifizierung können Sie das Konto vollumfänglich nutzen.

+Haben Sie kein Konto bei uns angelegt, ignorieren Sie diese E-Mail.

+ +Viele Grüße,
+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; } - - } diff --git a/intern/authmeldung.php b/intern/authmeldung.php index 56e1db9..cb47e0a 100644 --- a/intern/authmeldung.php +++ b/intern/authmeldung.php @@ -30,31 +30,14 @@ if(isset($_GET['send']) ) { $error = "Kein Benutzer gefunden"; } else { - $passwortcode = random_string(); - $statement = $pdo->prepare("UPDATE intern_users SET passwortcode = :passwortcode, passwortcode_time = NOW() WHERE id = :userid"); - $result = $statement->execute(array('passwortcode' => sha1($passwortcode), 'userid' => $user['id'])); - - $empfaenger = $user['email']; - $betreff = "Authentifizierung für deinen Account auf ". $_SERVER['SERVER_NAME']; - - $url_passwortcode = getSiteURL().'authentifizierung.php?userid='.$user['id'].'&code='.$passwortcode; - $text = 'Hallo '.$user['vorname'].',

-für die Nutzung des Kontos müssen Sie das Konto per E-Mail authentifizieren. Dazu klicken Sie auf den folgenden Link:
-'.$url_passwortcode.' -

-Nach der Authentifizierung können Sie das Konto vollumfänglich nutzen.

-Haben Sie keine Konto bei uns angelegt, ignorieren Sie diese E-Mail.

- -Viele Grüße,
-Ihr ' .$organisationsname . ' Team'; - - //echo $text; - - $mailOk = SendMailMessage($pdo, $empfaenger, $betreff ,$text); - - - echo "Ein Link, um Ihr Konto per E-Mail zu authentifizieren, wurde an deine E-Mail-Adresse gesendet."; - $showForm = false; + // Codeerzeugung und Mailtext liegen in sendeAuthentifizierungsMail(), + // damit register.php exakt dieselbe Mail verschickt. + if(sendeAuthentifizierungsMail($pdo, $user, $organisationsname)) { + echo "Ein Link, um Ihr Konto per E-Mail zu authentifizieren, wurde an Ihre E-Mail-Adresse gesendet."; + $showForm = false; + } else { + $error = "Die E-Mail konnte gerade nicht versendet werden. Bitte versuchen Sie es später noch einmal."; + } } } } diff --git a/intern/impfwarteliste.php b/intern/impfwarteliste.php index bb0c762..2f1a039 100644 --- a/intern/impfwarteliste.php +++ b/intern/impfwarteliste.php @@ -5,7 +5,9 @@ require_once(__DIR__ . "/../inc/functions.inc.php"); require_once(__DIR__ . "/../inc/functions.impfen.inc.php"); require_once(__DIR__ . "/../inc/impfworkflow_notifications.inc.php"); -ini_set('display_errors', '1'); +// Fehler protokollieren, aber nicht an Besucher ausgeben. +ini_set('display_errors', '0'); +ini_set('log_errors', '1'); error_reporting(E_ALL); $user = check_intern_user(); diff --git a/intern/login.php b/intern/login.php index 64b3ba1..47dfb93 100644 --- a/intern/login.php +++ b/intern/login.php @@ -47,7 +47,7 @@ if (!empty($_POST['email']) && !empty($_POST['passwort'])) { 'code' => $codeHash ]); - SendMailMessageSilent( + $mailOk = SendMailMessageSilent( $con, $user['email'], 'Ihr Login-Code für Praxis-Creutzburg.de', @@ -55,11 +55,27 @@ if (!empty($_POST['email']) && !empty($_POST['passwort'])) { Geben Sie diesen Code niemals weiter." ); - header('Location: verify_2fa.php'); - exit; + if ($mailOk) { + header('Location: verify_2fa.php'); + exit; + } + + // Ohne zugestellten Code kommt der Benutzer auf verify_2fa.php nicht + // weiter. Statt ihn dort warten zu lassen, den Versuch zuruecknehmen + // und es hier sagen. Die Ursache steht im Server-Log. + $pdo->prepare("DELETE FROM intern_2fa_codes WHERE user_id = :uid") + ->execute(['uid' => $user['id']]); + unset($_SESSION['2fa_userid']); + + $error_msg = "Der Login-Code konnte gerade nicht per E-Mail versendet werden. " + . "Bitte versuchen Sie es in ein paar Minuten erneut oder rufen Sie uns an."; } - $error_msg = "E-Mail oder Passwort war ungültig"; + // Nur setzen, wenn oben nicht schon eine genauere Meldung entstanden ist + // (z. B. weil der Code nicht versendet werden konnte). + if ($error_msg === "") { + $error_msg = "E-Mail oder Passwort war ungültig"; + } } diff --git a/intern/neueanfrage-old1.php b/intern/neueanfrage-old1.php index 9e5d9ad..35a01f6 100644 --- a/intern/neueanfrage-old1.php +++ b/intern/neueanfrage-old1.php @@ -3,7 +3,9 @@ session_start(); require_once(__DIR__ . "/../inc/config.inc.php"); require_once(__DIR__ . "/../inc/functions.inc.php"); -ini_set('display_errors', 1); +// Fehler protokollieren, aber nicht an Besucher ausgeben. +ini_set('display_errors', '0'); +ini_set('log_errors', '1'); error_reporting(E_ALL); include("templates/header.inc.php"); diff --git a/intern/neueanfrage-old2.php b/intern/neueanfrage-old2.php index 9e5d9ad..35a01f6 100644 --- a/intern/neueanfrage-old2.php +++ b/intern/neueanfrage-old2.php @@ -3,7 +3,9 @@ session_start(); require_once(__DIR__ . "/../inc/config.inc.php"); require_once(__DIR__ . "/../inc/functions.inc.php"); -ini_set('display_errors', 1); +// Fehler protokollieren, aber nicht an Besucher ausgeben. +ini_set('display_errors', '0'); +ini_set('log_errors', '1'); error_reporting(E_ALL); include("templates/header.inc.php"); diff --git a/intern/neueanfrage.php b/intern/neueanfrage.php index 35e8c34..d9276b6 100644 --- a/intern/neueanfrage.php +++ b/intern/neueanfrage.php @@ -6,7 +6,9 @@ ob_start(); require_once(__DIR__ . "/../inc/config.inc.php"); require_once(__DIR__ . "/../inc/functions.inc.php"); -ini_set('display_errors', '1'); +// Fehler protokollieren, aber nicht an Besucher ausgeben. +ini_set('display_errors', '0'); +ini_set('log_errors', '1'); error_reporting(E_ALL); diff --git a/intern/register.php b/intern/register.php index fad40c5..0ad6911 100644 --- a/intern/register.php +++ b/intern/register.php @@ -119,14 +119,35 @@ if(isset($_GET['register'])) { $pdo->commit(); - echo 'Du wurdest erfolgreich registriert. Zum Login'; + echo 'Du wurdest erfolgreich registriert. Zum Login
'; $showFormular = false; + // Bisher wurde hier keine Mail verschickt: mailreg blieb 0 und jeder + // neue Benutzer landete nach dem Login auf der Aufforderung, die + // Authentifizierung selbst anzustossen. Den Link gibt es jetzt sofort. + $stmt = $pdo->prepare("SELECT id, vorname, email FROM intern_users WHERE email = :email LIMIT 1"); + $stmt->execute([':email' => $email]); + $neuerUser = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($neuerUser && sendeAuthentifizierungsMail($pdo, $neuerUser, $organisationsname)) { + echo 'Wir haben Ihnen eine E-Mail geschickt. Bitte bestätigen Sie darin ' + . 'Ihre Adresse, damit Sie das Konto vollständig nutzen können.
'; + } else { + echo 'Die Bestätigungs-E-Mail konnte gerade nicht versendet werden. ' + . 'Sie können sie nach dem Login jederzeit erneut anfordern.
'; + } + } catch (Exception $e) { - $pdo->rollBack(); - echo 'Fehler beim Registrieren.
'; - echo ($e->getMessage()); - echo "
"; + // Der Mailversand laeuft nach dem commit(). Ohne diese Pruefung + // wuerde ein Fehler dort in rollBack() ohne offene Transaktion + // laufen und die Seite mit einem Fatal Error abbrechen. + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + // Interne Fehlermeldungen gehoeren ins Log, nicht auf die Seite. + error_log('register.php: Registrierung fehlgeschlagen: ' . $e->getMessage()); + echo 'Bei der Registrierung ist ein Fehler aufgetreten. ' + . 'Bitte versuchen Sie es später noch einmal oder rufen Sie uns an.
'; } } diff --git a/zeiterfassung/api/vacations.php b/zeiterfassung/api/vacations.php index cf256a4..4aefb18 100644 --- a/zeiterfassung/api/vacations.php +++ b/zeiterfassung/api/vacations.php @@ -4,8 +4,10 @@ require_once(__DIR__ . '/../inc/config.inc.php'); require_once(__DIR__ . '/../inc/functions.inc.php'); require_once(__DIR__ . '/../inc/vacation_absence.inc.php'); -ini_set('display_errors', '1'); -ini_set('display_startup_errors', '1'); +// Fehler protokollieren, aber nicht an Besucher ausgeben. +ini_set('display_errors', '0'); +ini_set('log_errors', '1'); +ini_set('display_startup_errors', '0'); error_reporting(E_ALL); if (!function_exists('vacationApiTableHasColumn')) {