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>
449 lines
16 KiB
PHP
449 lines
16 KiB
PHP
<?php
|
|
// Ausgabe puffern: check_intern_user() setzt Cookies und leitet per header() um,
|
|
// obwohl das Header-Template weiter unten schon Ausgabe erzeugt hat.
|
|
ob_start();
|
|
|
|
require_once(__DIR__ . "/../inc/config.inc.php");
|
|
require_once(__DIR__ . "/../inc/functions.inc.php");
|
|
|
|
// Fehler protokollieren, aber nicht an Besucher ausgeben.
|
|
ini_set('display_errors', '0');
|
|
ini_set('log_errors', '1');
|
|
error_reporting(E_ALL);
|
|
|
|
|
|
/* ---------------------------
|
|
Page start
|
|
----------------------------*/
|
|
|
|
include(__DIR__ . "/templates/header.inc.php");
|
|
|
|
echo "</header>";
|
|
echo "<div class='jumbotron'><div class='container'>";
|
|
|
|
$user = check_intern_user(); // intern session user
|
|
|
|
if (!$user) {
|
|
header("Location: login.php");
|
|
exit;
|
|
}
|
|
|
|
|
|
|
|
echo "<h1>Neue Anfrage</h1>";
|
|
echo "<p>Hallo " . e((string)($user['vorname'] ?? '')) . ",<br></p>";
|
|
|
|
// Preconditions
|
|
if (!check_mailreg()) {
|
|
echo "<br><br>";
|
|
echo "Es fehlt die Authentifizierung Ihres Kontos per E-Mail! Bitte authentifizieren Sie Ihre E-Mail-Adresse.<br>";
|
|
echo "<form action='authmeldung.php' method='POST'>";
|
|
echo "<input name='aktion' type='hidden' value='1'>";
|
|
echo "<input type='submit' class='btn btn-primary' value='E-Mail Authentifizierung'><br>";
|
|
echo "</form>";
|
|
}
|
|
|
|
if (!check_userdatenvorhanden()) {
|
|
echo "<br><br>";
|
|
echo "Es fehlen noch Informationen in Ihren Stammdaten. Bitte pflegen Sie die Daten nach.<br>";
|
|
echo "<form action='settings.php' method='POST'>";
|
|
echo "<input name='aktion' type='hidden' value='1'>";
|
|
echo "<input type='submit' class='btn btn-primary' value='Stammdaten pflegen'><br>";
|
|
echo "</form>";
|
|
}
|
|
|
|
if (!(check_mailreg() && check_userdatenvorhanden())) {
|
|
echo "<br><br><br><form action='index.php' method='POST'>
|
|
<input type='submit' class='btn btn-primary' value='Zum Hauptmenü'>
|
|
</form>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
// action routing
|
|
$aktion = $_POST['aktion'] ?? ''; // '', choose, confirm, submit
|
|
|
|
// Ensure persons id early
|
|
try {
|
|
$internUserId = isset($_SESSION['userid']) ? (int)$_SESSION['userid'] : null;
|
|
$personId = ensurePersonFromInternUsersByEmail($pdo, (string)($user['email'] ?? ''), $internUserId);
|
|
} catch (Throwable $t) {
|
|
echo "<div class='alert alert-danger'>Fehler: " . e($t->getMessage()) . "</div>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
// Vacation check
|
|
if ($aktion === 'choose' || $aktion === 'confirm' || $aktion === 'submit' || $aktion === '') {
|
|
if (isPraxisImUrlaub($pdo)) {
|
|
$info = loadAktuelleUrlaubsInfo($pdo);
|
|
echo "<h2>Praxis im Urlaub</h2>";
|
|
echo "Wir befinden uns aktuell im Urlaub.<br>Wenden Sie sich an unsere Vertretung oder warten Sie bis nach unserem Urlaub mit Ihrer Anfrage.<br><br>";
|
|
|
|
if ($info) {
|
|
$ende = (string)$info['ende'];
|
|
$endeausgabe = date("d.m.Y", strtotime("+1 day", strtotime($ende)));
|
|
|
|
if (!empty($info['vertretung'])) echo "Unsere Vertretung: " . e($info['vertretung']) . "<br>";
|
|
if (!empty($info['vertreterurl'])) echo "Webseite Vertretung: " . e($info['vertreterurl']) . "<br>";
|
|
if (!empty($info['vertretertelefon'])) echo "Telefonischer Kontakt Vertretung: " . e($info['vertretertelefon']) . "<br>";
|
|
if (!empty($info['vertreteradresse'])) echo "Adresse Vertretung: " . e($info['vertreteradresse']) . "<br>";
|
|
|
|
echo "<br>Wir stehen Ihnen ab dem " . e($endeausgabe) . " wieder zur Verfügung.<br><br><br>";
|
|
}
|
|
|
|
echo "<form action='index.php' method='POST'><input type='submit' class='btn btn-primary' value='Zurück'></form>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// default: show selection
|
|
if ($aktion === '') {
|
|
echo "<p>Wählen Sie die Anfragenart aus:<br><br></p>";
|
|
echo "<form action='" . e($_SERVER['PHP_SELF']) . "' method='POST'>";
|
|
echo "<input type='hidden' name='aktion' value='choose'>";
|
|
|
|
echo "<h4>Benutzer</h4>";
|
|
echo "Name: " . e((string)$user["vorname"]) . " " . e((string)$user["nachname"]) . "<br>";
|
|
echo "Geburtstag: " . e((string)$user["geburtstag"]) . "<br>";
|
|
echo "Adresse: " . e((string)$user["strasse"]) . ", " . e((string)$user["plz"]) . ", " . e((string)$user["ort"]) . "<br>";
|
|
|
|
echo "<input type='hidden' name='requester_person_id' value='" . (int)$personId . "'>";
|
|
|
|
echo "<br><br>";
|
|
echo "<label for='anfrageart'>Art der Anfrage:</label>";
|
|
echo "<select class='form-control' name='anfrageart' id='anfrageart' required>
|
|
<option value='1'>Rezeptanfrage</option>
|
|
<option value='2'>Allgemeine Anfrage</option>
|
|
<option value='3'>Terminabsage</option>
|
|
</select>";
|
|
echo "<br><br>";
|
|
echo "<input type='submit' class='btn btn-primary' value='Anfrage stellen'><br>";
|
|
echo "</form>";
|
|
|
|
echo "<br><br><br><form action='index.php' method='POST'>
|
|
<input type='submit' class='btn btn-primary' value='Zum Hauptmenü'>
|
|
</form>";
|
|
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
// choose -> show form
|
|
if ($aktion === 'choose') {
|
|
$anfrageart = (int)($_POST['anfrageart'] ?? 0);
|
|
$requester_person_id = (int)($_POST['requester_person_id'] ?? $personId);
|
|
|
|
$mode = match ($anfrageart) {
|
|
1 => 'rezept',
|
|
2 => 'allgemein',
|
|
3 => 'terminabsage',
|
|
default => ''
|
|
};
|
|
if ($mode === '') {
|
|
echo "<div class='alert alert-danger'>Unbekannte Anfrageart.</div>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
$arten = loadAnfragearten($pdo, $mode);
|
|
|
|
echo "<p>Füllen Sie das Formular aus.</p>";
|
|
echo "<form action='" . e($_SERVER['PHP_SELF']) . "' method='POST'>";
|
|
echo "<input type='hidden' name='aktion' value='confirm'>";
|
|
echo "<input type='hidden' name='mode' value='" . e($mode) . "'>";
|
|
echo "<input type='hidden' name='requester_person_id' value='" . (int)$requester_person_id . "'>";
|
|
|
|
// User block
|
|
echo "<h4>Benutzer</h4>";
|
|
echo "Name: " . e((string)$user["vorname"]) . " " . e((string)$user["nachname"]) . "<br>";
|
|
echo "Geburtstag: " . e((string)$user["geburtstag"]) . "<br>";
|
|
echo "Adresse: " . e((string)$user["strasse"]) . ", " . e((string)$user["plz"]) . ", " . e((string)$user["ort"]) . "<br>";
|
|
|
|
echo "<br><br><div class='col-sm-10'>";
|
|
echo "<label for='category'>Thema:</label>";
|
|
echo "<select class='form-control' name='category' id='category' required>";
|
|
echo "<option value=''>Bitte wählen Sie aus</option>";
|
|
foreach ($arten as $a) {
|
|
$artid = (int)$a['artid'];
|
|
$artname = (string)$a['artname'];
|
|
echo "<option value='{$artid}'>" . e($artname) . "</option>";
|
|
}
|
|
echo "</select></div>";
|
|
|
|
// Special fields for rezept
|
|
if ($mode === 'rezept') {
|
|
$curdate = date('d.m.Y');
|
|
$curyear = date('Y');
|
|
$curMonth = (int)date('m');
|
|
$curQuarter = (int)ceil($curMonth / 3);
|
|
$current_quarter = (int)ceil(date('n') / 3);
|
|
$first_date = date('d.m.Y', strtotime(date('Y') . '-' . (($current_quarter * 3) - 2) . '-1'));
|
|
$last_date = date('t.m.Y', strtotime(date('Y') . '-' . (($current_quarter * 3)) . '-1'));
|
|
|
|
echo "<div class='col-sm-10'><br>";
|
|
echo "<label for='karte'>Ich habe dieses Quartal schon meine Gesundheitskarte in der Praxis einlesen lassen:</label><br>";
|
|
echo "Aktuell befinden wir uns im {$curQuarter}. Quartal von {$curyear}.<br>";
|
|
echo "Dieses geht vom <b>{$first_date} bis {$last_date}</b><br>";
|
|
echo "Heute ist der {$curdate}.<br>";
|
|
echo "War die Chipkarte dieses Quartal noch nicht eingelesen, ist die Abholung nur in der Praxis möglich.<br><br>";
|
|
echo "<select class='form-control' name='karte' id='karte' required onchange='checkkarte()'>
|
|
<option value=''>Bitte wählen Sie aus</option>
|
|
<option value='Ja'>Ja</option>
|
|
<option value='Nein'>Nein</option>
|
|
<option value='Privat'>Privatrezept (Selbstzahler)</option>
|
|
</select>";
|
|
echo "</div>";
|
|
|
|
echo "<div class='col-sm-10'><br>";
|
|
echo "<label for='abholung'>Ich möchte das Rezept hier abholen:</label>";
|
|
echo "<select class='form-control' name='abholung' id='abholung' required onchange='checkkarte()'>
|
|
<option value=''>Bitte wählen Sie aus</option>
|
|
<option value='Praxis'>Praxis Creutzburg</option>
|
|
<option value='Apotheke'>Apotheke</option>
|
|
</select>";
|
|
echo "</div>";
|
|
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
echo "<div class='col-sm-10'><br>";
|
|
echo "<input class='form-control' type='text' name='Medikament{$i}' placeholder='Medikament, Wirkstoff, Packungsgröße' maxlength='150'>";
|
|
echo "</div>";
|
|
}
|
|
}
|
|
|
|
echo "<div class='col-sm-10'><br>";
|
|
echo "<textarea class='form-control' name='message' id='message' placeholder='Ihre Nachricht/Bemerkung' rows='6' maxlength='500'></textarea>";
|
|
echo "</div>";
|
|
|
|
echo "<div class='col-sm-10'><br>";
|
|
echo "Bedenken Sie bitte, dass wir einmal im Quartal Ihre Chipkarte benötigen. Ohne Chipkarte sind seit 1.1.2016 keine Kassendienstleistungen mehr möglich.<br>";
|
|
echo "</div>";
|
|
|
|
echo "<div class='col-sm-10'><br><br>";
|
|
echo "<input class='form-control' type='submit' value='Weiter'>";
|
|
echo "<br><br><br></div>";
|
|
|
|
echo "</form>";
|
|
|
|
echo "<script>
|
|
function checkkarte(){
|
|
var karte = document.getElementById('karte');
|
|
var abholung = document.getElementById('abholung');
|
|
if (!karte || !abholung) return;
|
|
if (karte.value === 'Nein') {
|
|
abholung.value = 'Praxis';
|
|
}
|
|
}
|
|
</script>";
|
|
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
// confirm -> summary
|
|
if ($aktion === 'confirm') {
|
|
$mode = (string)($_POST['mode'] ?? '');
|
|
$requester_person_id = (int)($_POST['requester_person_id'] ?? 0);
|
|
$category = (int)($_POST['category'] ?? 0);
|
|
|
|
if ($requester_person_id <= 0 || $category <= 0 || $mode === '') {
|
|
echo "<div class='alert alert-danger'>Ungültige Eingaben.</div>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
$anfrageartText = loadAnfrageartName($pdo, $category);
|
|
|
|
echo "<h4>Kontrollieren Sie Ihre Angaben!</h4><br>";
|
|
echo "<form action='" . e($_SERVER['PHP_SELF']) . "' method='POST'>";
|
|
echo "<input type='hidden' name='aktion' value='submit'>";
|
|
echo "<input type='hidden' name='mode' value='" . e($mode) . "'>";
|
|
echo "<input type='hidden' name='requester_person_id' value='" . (int)$requester_person_id . "'>";
|
|
echo "<input type='hidden' name='category' value='" . (int)$category . "'>";
|
|
|
|
echo "<table border='0' class='table'>";
|
|
echo "<tr><td class='fett' style='width:160px;'>Thema</td><td>" . e($anfrageartText) . "</td></tr>";
|
|
|
|
if ($mode === 'rezept') {
|
|
$karte = (string)($_POST['karte'] ?? '');
|
|
$abholung = (string)($_POST['abholung'] ?? '');
|
|
echo "<input type='hidden' name='karte' value='" . e($karte) . "'>";
|
|
echo "<input type='hidden' name='abholung' value='" . e($abholung) . "'>";
|
|
echo "<tr><td class='fett'>Karte</td><td>" . e($karte) . "</td></tr>";
|
|
echo "<tr><td class='fett'>Abholung</td><td>" . e($abholung) . "</td></tr>";
|
|
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
$med = (string)($_POST["Medikament{$i}"] ?? '');
|
|
echo "<input type='hidden' name='Medikament{$i}' value='" . e($med) . "'>";
|
|
if ($med !== '') {
|
|
echo "<tr><td class='fett'>Medikament{$i}</td><td>" . e($med) . "</td></tr>";
|
|
}
|
|
}
|
|
}
|
|
|
|
$message = (string)($_POST['message'] ?? '');
|
|
echo "<input type='hidden' name='message' value='" . e($message) . "'>";
|
|
echo "<tr><td class='fett'>Nachricht</td><td>" . nl2br(e($message)) . "</td></tr>";
|
|
echo "</table>";
|
|
|
|
echo "<input type='submit' class='form-control' value='Anfrage abschicken'>";
|
|
echo "</form>";
|
|
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
// submit -> insert + mail
|
|
if ($aktion === 'submit') {
|
|
$mode = (string)($_POST['mode'] ?? '');
|
|
$requester_person_id = (int)($_POST['requester_person_id'] ?? 0);
|
|
$anforderungart = (int)($_POST['category'] ?? 0);
|
|
$message = (string)($_POST['message'] ?? '');
|
|
|
|
if ($requester_person_id <= 0 || $anforderungart <= 0) {
|
|
echo "<div class='alert alert-danger'>Ungültige Eingaben.</div>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
$nachricht = $message;
|
|
|
|
$abholungnr = 0;
|
|
if ($mode === 'rezept') {
|
|
$karte = (string)($_POST['karte'] ?? '');
|
|
$abholung = (string)($_POST['abholung'] ?? '');
|
|
|
|
$abholungnr = ($abholung === 'Praxis') ? 1 : (($abholung === 'Apotheke') ? 2 : 0);
|
|
if ($karte === 'Privat') {
|
|
$karte = 'Privatrezept (Selbstzahler)';
|
|
}
|
|
$nachricht = "Karte eingelesen: {$karte}<br>Abholungsort: {$abholung}<br>" . $nachricht;
|
|
}
|
|
|
|
$med = [];
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
$med[$i] = trim((string)($_POST["Medikament{$i}"] ?? ''));
|
|
}
|
|
|
|
// duplicate check (best effort)
|
|
$exists = false;
|
|
try {
|
|
$stmtDup = $pdo->prepare("
|
|
SELECT *
|
|
FROM anfragen
|
|
WHERE requester_person_id = :pid
|
|
AND anforderungart = :art
|
|
AND nachricht = :nachricht
|
|
AND create_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
|
");
|
|
$stmtDup->execute([
|
|
':pid' => $requester_person_id,
|
|
':art' => $anforderungart,
|
|
':nachricht' => $nachricht,
|
|
]);
|
|
$rows = $stmtDup->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$medFieldAliases = [
|
|
1 => ['med1', 'medikament1', 'med_1'],
|
|
2 => ['med2', 'medikament2', 'med_2'],
|
|
3 => ['med3', 'medikament3', 'med_3'],
|
|
4 => ['med4', 'medikament4', 'med_4'],
|
|
5 => ['med5', 'medikament5', 'med_5'],
|
|
6 => ['med6', 'medikament6', 'med_6'],
|
|
];
|
|
|
|
foreach ($rows as $row) {
|
|
$allMedsEqual = true;
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
$dbValue = '';
|
|
foreach ($medFieldAliases[$i] as $fieldName) {
|
|
if (array_key_exists($fieldName, $row)) {
|
|
$dbValue = trim((string)($row[$fieldName] ?? ''));
|
|
break;
|
|
}
|
|
}
|
|
if ($dbValue !== $med[$i]) {
|
|
$allMedsEqual = false;
|
|
break;
|
|
}
|
|
}
|
|
if ($allMedsEqual) {
|
|
$exists = true;
|
|
break;
|
|
}
|
|
}
|
|
} catch (Throwable $t) {
|
|
error_log('Duplicate check failed: ' . $t->getMessage());
|
|
$exists = false;
|
|
}
|
|
|
|
if ($exists) {
|
|
echo "<h3>Doppelte Anfrage</h3><br>Ihre Anfrage wurde schon in unserem System gespeichert.<br>
|
|
Sie haben die identische Anfrage schon in den letzten sieben Tagen eingereicht.<br>
|
|
Bitte warten Sie auf die Verarbeitung Ihrer Anfrage.<br><br>";
|
|
echo "<form action='index.php' method='POST'>
|
|
<input type='submit' class='btn btn-primary' value='Zum Hauptmenü'>
|
|
</form>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
$hash = bin2hex(random_bytes(16));
|
|
$ordnungsid = ($mode === 'rezept') ? 1 : 2;
|
|
|
|
try {
|
|
$anfrageid = insertAnfrage($pdo, [
|
|
'person_id' => $requester_person_id,
|
|
'anforderungart' => $anforderungart,
|
|
'med1' => $med[1],
|
|
'med2' => $med[2],
|
|
'med3' => $med[3],
|
|
'med4' => $med[4],
|
|
'med5' => $med[5],
|
|
'med6' => $med[6],
|
|
'nachricht' => $nachricht,
|
|
'hash' => $hash,
|
|
'ordnungsid' => $ordnungsid,
|
|
'abholort' => $abholungnr,
|
|
'sicherenachricht' => 1,
|
|
'checked' => 1,
|
|
]);
|
|
|
|
$templateId = ($mode === 'rezept') ? 26 : 19;
|
|
|
|
// IMPORTANT: Your SendMailMessageVorlage() must accept PDO after your migration.
|
|
SendMailMessageVorlage($pdo, "3", $anfrageid, (string)$templateId);
|
|
|
|
echo "<h3>Nachricht abgeschickt!</h3><br>Sie bekommen eine Bestätigung per E-Mail!<br>
|
|
Überprüfen Sie auch Ihren Spam-Filter!<br><br>";
|
|
|
|
} catch (Throwable $t) {
|
|
echo "<h3>Speicherung nicht erfolgreich</h3><br>Ihre Anfrage konnte nicht gespeichert werden.<br>";
|
|
echo "<div class='alert alert-danger'>Fehler: " . e($t->getMessage()) . "</div>";
|
|
}
|
|
|
|
echo "<br><br><br><form action='index.php' method='POST'>
|
|
<input type='submit' class='btn btn-primary' value='Zum Hauptmenü'>
|
|
</form>";
|
|
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|
|
exit;
|
|
}
|
|
|
|
// fallback
|
|
echo "<div class='alert alert-warning'>Unbekannte Aktion.</div>";
|
|
echo "</div></div>";
|
|
include(__DIR__ . "/templates/footer.inc.php");
|