Files
cat/process_registration.php
T

663 lines
24 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
session_set_cookie_params([
'httponly' => true,
'samesite' => 'Strict',
'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
'use_strict_mode' => true,
]);
session_start();
if ((int) ($_SERVER['CONTENT_LENGTH'] ?? 0) > 1048576) {
http_response_code(413);
exit('Anfrage zu groß.');
}
header('Cache-Control: no-store');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('Referrer-Policy: no-referrer');
header('Permissions-Policy: camera=(), microphone=(), geolocation=()');
header("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; base-uri 'self'; form-action 'self'; frame-ancestors 'none'");
require_once __DIR__ . '/inc/db.inc.php';
require_once __DIR__ . '/inc/mail.inc.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
header('Allow: POST');
exit('Methode nicht erlaubt.');
}
$submittedCsrf = $_POST['csrf_token'] ?? '';
$storedCsrf = $_SESSION['registration_csrf'] ?? '';
if (!is_string($submittedCsrf) || $storedCsrf === '' || !hash_equals($storedCsrf, $submittedCsrf)) {
http_response_code(403);
exit('Ungültige Anfrage.');
}
unset($_SESSION['registration_csrf']);
function postString(string $key): string
{
$value = $_POST[$key] ?? '';
return is_string($value) ? trim($value) : '';
}
function postStringList(string $key): array
{
$value = $_POST[$key] ?? [];
$values = is_array($value) ? $value : [$value];
return array_values(array_filter(
array_map(
static fn ($item): string => is_string($item) ? trim($item) : '',
$values
),
static fn (string $item): bool => $item !== ''
));
}
function postMealSelectionsByDay(): array
{
$value = $_POST['meals'] ?? [];
if (!is_array($value)) {
return [];
}
$result = [];
foreach ($value as $day => $meals) {
if (!is_array($meals)) {
continue;
}
$result[(string) $day] = array_values(array_filter(
array_map(static fn ($item): string => is_string($item) ? trim($item) : '', $meals),
static fn (string $item): bool => $item !== ''
));
}
return $result;
}
function formatMealSummary(array $days, array $mealsByDay): string
{
$dayLabels = ['1' => 'Fr.', '2' => 'Sa.', '3' => 'So.'];
$mealLabels = [
'breakfast' => 'Frühstück',
'lunch' => 'Mittagessen',
'coffee' => 'Kaffee',
'dinner' => 'Abendessen',
'drinks' => 'Getränkepauschale',
];
$parts = [];
foreach ($days as $day) {
$labels = array_map(static fn (string $meal): string => $mealLabels[$meal] ?? $meal, $mealsByDay[$day] ?? []);
$labels[] = $mealLabels['drinks'];
$labels[] = $mealLabels['rehearsal_room'];
$parts[] = ($dayLabels[$day] ?? $day) . ': ' . implode(', ', $labels);
}
return implode('; ', $parts) ?: '';
}
function escapeHtml(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
function smtpResponse($socket): string
{
$response = '';
do {
$line = fgets($socket);
if ($line === false) {
throw new RuntimeException('Keine gültige SMTP-Antwort erhalten.');
}
$response .= $line;
} while (isset($line[3]) && $line[3] === '-');
return $response;
}
function smtpCommand($socket, string $command, array $expectedCodes): void
{
fwrite($socket, $command . "\r\n");
$response = smtpResponse($socket);
$code = (int) substr($response, 0, 3);
if (!in_array($code, $expectedCodes, true)) {
throw new RuntimeException('SMTP-Befehl wurde abgelehnt.');
}
}
function encodedHeader(string $value): string
{
return '=?UTF-8?B?' . base64_encode($value) . '?=';
}
function calculateBookingTotal(PDO $pdo, bool $under27, string $guestType, ?string $roomType, array $mealsByDay): float
{
$ageSuffix = $under27 ? 'under_27' : 'over_27';
$keys = [];
if ($guestType === 'regular_guest' && $roomType !== null) {
$keys[] = $roomType . '_' . $ageSuffix;
}
if ($guestType === 'day_guest') {
foreach ($mealsByDay as $meals) {
foreach (array_unique(array_merge($meals, ['drinks'])) as $meal) {
if (in_array($meal, ['breakfast', 'lunch', 'coffee', 'dinner'], true)) {
$keys[] = $meal . '_' . $ageSuffix;
} elseif ($meal === 'drinks') {
$keys[] = 'drinks';
}
}
$keys[] = 'rehearsal_room';
}
}
if ($keys === []) {
return 0.0;
}
$uniqueKeys = array_values(array_unique($keys));
$placeholders = implode(',', array_fill(0, count($uniqueKeys), '?'));
$statement = $pdo->prepare("SELECT setting_key, price FROM pricing_settings WHERE setting_key IN ($placeholders)");
$statement->execute($uniqueKeys);
$prices = [];
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) {
$prices[(string) $row['setting_key']] = (float) $row['price'];
}
return round(array_sum(array_map(
static fn (string $key): float => $prices[$key] ?? 0.0,
$keys
)), 2);
}
function sendRegistrationEmail(
array $mailConfig,
string $recipient,
string $name,
string $participantPassword,
string $guestType,
bool $under27,
?string $roomType,
array $days,
array $mealsByDay,
string $allergies,
string $roommates,
string $otherNotes
): void {
$roomLabels = [
'single' => 'Einzelzimmer',
'double' => 'Doppelzimmer',
'multi' => 'Mehrbettzimmer',
];
$dayLabels = ['1' => 'Fr.', '2' => 'Sa.', '3' => 'So.'];
$mealLabels = [
'breakfast' => 'Frühstück',
'lunch' => 'Mittagessen',
'coffee' => 'Kaffee',
'drinks' => 'Getränkepauschale',
'dinner' => 'Abendessen',
'rehearsal_room' => 'Proberaumpauschale',
];
$guestLabel = $guestType === 'day_guest' ? 'Tagesgast' : 'Dauergast';
$ageLabel = $under27 ? 'Unter 27' : 'Ab 27';
$roomLabel = $roomLabels[$roomType ?? ''] ?? '';
$dayText = implode(', ', array_map(static fn (string $day): string => $dayLabels[$day] ?? $day, $days)) ?: '';
$mealText = formatMealSummary($days, $mealsByDay);
$roommates = $roommates !== '' ? $roommates : '';
$allergies = $allergies !== '' ? $allergies : '';
$otherNotes = $otherNotes !== '' ? $otherNotes : '';
$textBody = "Hallo {$name},\n\n"
. "deine Registrierung für das Chorwochenende wurde erfolgreich gespeichert.\n\n"
. "Zugang zur Änderung oder Löschung:\n"
. "E-Mail-Adresse: {$recipient}\n"
. "Passwort: {$participantPassword}\n\n"
. "Zusammenfassung:\n"
. "Altersgruppe: {$ageLabel}\n"
. "Gasttyp: {$guestLabel}\n"
. "Zimmerart: {$roomLabel}\n"
. "Anwesenheitstage: {$dayText}\n"
. "Mahlzeiten: {$mealText}\n"
. "Zimmerpartner-Wunsch: {$roommates}\n"
. "Allergien / Essensvorlieben: {$allergies}\n"
. "Sonstiges: {$otherNotes}\n\n"
. "Viele Grüße\n{$mailConfig['from_name']}";
$html = static fn (string $value): string => escapeHtml($value);
$htmlBody = '<!doctype html><html lang="de"><body>'
. '<p>Hallo ' . $html($name) . ',</p>'
. '<p>deine Registrierung für das Chorwochenende wurde erfolgreich gespeichert.</p>'
. '<h2>Deine Zugangsdaten</h2><p><strong>E-Mail-Adresse:</strong> ' . $html($recipient)
. '<br><strong>Passwort:</strong> <code>' . $html($participantPassword) . '</code></p>'
. '<h2>Zusammenfassung</h2><ul>'
. '<li><strong>Altersgruppe:</strong> ' . $html($ageLabel) . '</li>'
. '<li><strong>Gasttyp:</strong> ' . $html($guestLabel) . '</li>'
. '<li><strong>Zimmerart:</strong> ' . $html($roomLabel) . '</li>'
. '<li><strong>Anwesenheitstage:</strong> ' . $html($dayText) . '</li>'
. '<li><strong>Mahlzeiten:</strong> ' . $html($mealText) . '</li>'
. '<li><strong>Zimmerpartner-Wunsch:</strong> ' . $html($roommates) . '</li>'
. '<li><strong>Allergien / Essensvorlieben:</strong> ' . $html($allergies) . '</li>'
. '<li><strong>Sonstiges:</strong> ' . $html($otherNotes) . '</li></ul>'
. '<p>Viele Grüße<br>' . $html($mailConfig['from_name']) . '</p></body></html>';
$boundary = '=_cat_' . bin2hex(random_bytes(12));
$message = 'From: ' . encodedHeader($mailConfig['from_name']) . ' <' . $mailConfig['from_address'] . ">\r\n"
. 'To: ' . $recipient . "\r\n"
. 'Subject: ' . encodedHeader('Deine Registrierung für das Chorwochenende') . "\r\n"
. "MIME-Version: 1.0\r\n"
. 'Content-Type: multipart/alternative; boundary="' . $boundary . "\"\r\n\r\n"
. '--' . $boundary . "\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n"
. $textBody . "\r\n\r\n"
. '--' . $boundary . "\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n"
. $htmlBody . "\r\n\r\n"
. '--' . $boundary . "--\r\n";
$context = stream_context_create([
'ssl' => [
'peer_name' => $mailConfig['host'],
'verify_peer' => true,
'verify_peer_name' => true,
],
]);
$socket = stream_socket_client(
'tcp://' . $mailConfig['host'] . ':' . $mailConfig['port'],
$errorNumber,
$errorMessage,
20,
STREAM_CLIENT_CONNECT,
$context
);
if ($socket === false) {
throw new RuntimeException('SMTP-Server nicht erreichbar.');
}
stream_set_timeout($socket, 20);
try {
$response = smtpResponse($socket);
if ((int) substr($response, 0, 3) !== 220) {
throw new RuntimeException('SMTP-Verbindung wurde abgelehnt.');
}
smtpCommand($socket, 'EHLO localhost', [250]);
smtpCommand($socket, 'STARTTLS', [220]);
if (!stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
throw new RuntimeException('STARTTLS konnte nicht aktiviert werden.');
}
smtpCommand($socket, 'EHLO localhost', [250]);
smtpCommand($socket, 'AUTH LOGIN', [334]);
smtpCommand($socket, base64_encode($mailConfig['username']), [334]);
smtpCommand($socket, base64_encode($mailConfig['password']), [235]);
smtpCommand($socket, 'MAIL FROM:<' . $mailConfig['from_address'] . '>', [250]);
smtpCommand($socket, 'RCPT TO:<' . $recipient . '>', [250, 251]);
smtpCommand($socket, 'DATA', [354]);
$message = preg_replace('/^\./m', '..', $message);
fwrite($socket, $message . "\r\n.\r\n");
$response = smtpResponse($socket);
if ((int) substr($response, 0, 3) !== 250) {
throw new RuntimeException('E-Mail konnte nicht angenommen werden.');
}
fwrite($socket, "QUIT\r\n");
} finally {
fclose($socket);
}
}
function sendAdminNotificationEmail(
array $mailConfig,
string $recipient,
string $name,
string $participantEmail,
string $guestLabel,
string $ageLabel,
string $roomLabel,
string $dayText,
string $mealText,
string $roommates,
string $allergies,
string $otherNotes
): void {
$textBody = "Neue Registrierung für das Chorwochenende\n\n"
. "Name: {$name}\n"
. "E-Mail: {$participantEmail}\n"
. "Altersgruppe: {$ageLabel}\n"
. "Gasttyp: {$guestLabel}\n"
. "Zimmerart: {$roomLabel}\n"
. "Anwesenheitstage: {$dayText}\n"
. "Mahlzeiten: {$mealText}\n"
. "Zimmerpartner-Wunsch: {$roommates}\n"
. "Allergien / Essensvorlieben: {$allergies}\n"
. "Sonstiges: {$otherNotes}\n";
$subject = encodedHeader('Neue Registrierung Chorwochenende');
$message = 'From: ' . encodedHeader($mailConfig['from_name']) . ' <' . $mailConfig['from_address'] . ">\r\n"
. 'To: ' . $recipient . "\r\n"
. 'Subject: ' . $subject . "\r\n"
. "MIME-Version: 1.0\r\n"
. "Content-Type: text/plain; charset=UTF-8\r\n"
. "Content-Transfer-Encoding: 8bit\r\n\r\n"
. $textBody;
$context = stream_context_create([
'ssl' => [
'peer_name' => $mailConfig['host'],
'verify_peer' => true,
'verify_peer_name' => true,
],
]);
$socket = stream_socket_client(
'tcp://' . $mailConfig['host'] . ':' . $mailConfig['port'],
$errorNumber,
$errorMessage,
20,
STREAM_CLIENT_CONNECT,
$context
);
if ($socket === false) {
throw new RuntimeException('SMTP-Server nicht erreichbar.');
}
stream_set_timeout($socket, 20);
try {
$response = smtpResponse($socket);
if ((int) substr($response, 0, 3) !== 220) {
throw new RuntimeException('SMTP-Verbindung wurde abgelehnt.');
}
smtpCommand($socket, 'EHLO localhost', [250]);
smtpCommand($socket, 'STARTTLS', [220]);
if (!stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
throw new RuntimeException('STARTTLS konnte nicht aktiviert werden.');
}
smtpCommand($socket, 'EHLO localhost', [250]);
smtpCommand($socket, 'AUTH LOGIN', [334]);
smtpCommand($socket, base64_encode($mailConfig['username']), [334]);
smtpCommand($socket, base64_encode($mailConfig['password']), [235]);
smtpCommand($socket, 'MAIL FROM:<' . $mailConfig['from_address'] . '>', [250]);
smtpCommand($socket, 'RCPT TO:<' . $recipient . '>', [250, 251]);
smtpCommand($socket, 'DATA', [354]);
fwrite($socket, preg_replace('/^\./m', '..', $message) . "\r\n.\r\n");
$response = smtpResponse($socket);
if ((int) substr($response, 0, 3) !== 250) {
throw new RuntimeException('E-Mail konnte nicht angenommen werden.');
}
fwrite($socket, "QUIT\r\n");
} finally {
fclose($socket);
}
}
$name = postString('name');
$email = postString('email');
$under27 = isset($_POST['under_27']) && $_POST['under_27'] === '1';
$guestType = postString('guest_type');
$roomType = postString('room_type');
$roommates = postString('roommates');
$earlyDeparture = postString('early_departure');
$allergies = postString('allergies');
$otherNotes = postString('other_notes');
$days = postStringList('days');
$mealsByDay = postMealSelectionsByDay();
$errors = [];
$allowedDays = ['1', '2', '3'];
$allowedEarlyDepartures = [
'sat_breakfast',
'sat_lunch',
'sat_coffee',
'sat_dinner',
'sun_breakfast',
];
$allowedMealsByDay = [
'1' => ['dinner'],
'2' => ['breakfast', 'lunch', 'coffee', 'dinner'],
'3' => ['breakfast', 'lunch'],
];
$days = array_values(array_unique($days));
foreach ($mealsByDay as $day => $dayMeals) {
$mealsByDay[$day] = array_values(array_unique($dayMeals));
}
if (count($days) > count($allowedDays) || array_diff($days, $allowedDays) !== []) {
$errors[] = 'Bitte nur gültige Anwesenheitstage auswählen.';
}
if (array_diff(array_keys($mealsByDay), $allowedDays) !== []) {
$errors[] = 'Bitte nur gültige Mahlzeitentage auswählen.';
}
foreach ($mealsByDay as $day => $dayMeals) {
$allowedMeals = $allowedMealsByDay[(string) $day] ?? [];
if (array_diff($dayMeals, $allowedMeals) !== []) {
$errors[] = 'Bitte nur gültige Mahlzeiten auswählen.';
}
if (!in_array((string) $day, $days, true) && $dayMeals !== []) {
$errors[] = 'Mahlzeiten dürfen nur für ausgewählte Anwesenheitstage angegeben werden.';
}
}
foreach ($days as $day) {
$mealsByDay[$day] ??= [];
}
if (mb_strlen($roommates) > 1000 || mb_strlen($allergies) > 1000) {
$errors[] = 'Zimmerwunsch und Allergieangaben dürfen höchstens 1000 Zeichen enthalten.';
}
if ($name === '' || mb_strlen($name) > 255) {
$errors[] = 'Bitte einen gültigen Namen eingeben.';
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL) || mb_strlen($email) > 255) {
$errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.';
}
if ($otherNotes !== '' && mb_strlen($otherNotes) > 5000) {
$errors[] = 'Das Feld Sonstiges darf höchstens 5000 Zeichen enthalten.';
}
if (!in_array($guestType, ['day_guest', 'regular_guest'], true)) {
$errors[] = 'Bitte einen gültigen Gasttyp auswählen.';
}
if ($guestType === 'regular_guest' && !in_array($roomType, ['single', 'double', 'multi'], true)) {
$errors[] = 'Bitte eine gültige Zimmerart auswählen.';
}
if ($earlyDeparture !== '' && ($guestType !== 'regular_guest' || !in_array($earlyDeparture, $allowedEarlyDepartures, true))) {
$errors[] = 'Bitte einen gültigen Abreisezeitpunkt auswählen.';
}
if ($errors !== []) {
http_response_code(422);
exit(implode("\n", $errors));
}
$roommateEligible = $guestType === 'regular_guest' && in_array($roomType, ['double', 'multi'], true);
if (!$roommateEligible) {
$roommates = '';
}
$role = $guestType === 'day_guest' ? 'Tagesgast' : 'Dauergast';
$bookingType = $guestType === 'day_guest' ? 'Day' : 'Stay';
$accommodationType = $guestType === 'regular_guest' ? $roomType : null;
$roommateRequest = $roommateEligible && $roommates !== '' ? $roommates : null;
$earlyDeparture = $guestType === 'regular_guest' && in_array($earlyDeparture, $allowedEarlyDepartures, true)
? $earlyDeparture
: null;
$mealPreferences = null;
if ($guestType === 'day_guest') {
$mealPreferences = json_encode(
[
'days' => $days,
'meals_by_day' => $mealsByDay,
],
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
}
$participantId = sprintf(
'%s-%s-%s-%s-%s',
bin2hex(random_bytes(4)),
bin2hex(random_bytes(2)),
bin2hex(random_bytes(2)),
bin2hex(random_bytes(2)),
bin2hex(random_bytes(6))
);
$participantPassword = bin2hex(random_bytes(8));
$participantPasswordHash = password_hash($participantPassword, PASSWORD_DEFAULT);
try {
$dsn = sprintf(
'mysql:host=%s;port=%d;dbname=%s;charset=%s',
$dbConfig['host'],
$dbConfig['port'],
$dbConfig['database'],
$dbConfig['charset']
);
$pdo = new PDO($dsn, $dbConfig['username'], $dbConfig['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$totalPrice = calculateBookingTotal($pdo, $under27, $guestType, $accommodationType, $mealsByDay);
$pdo->beginTransaction();
$participantStatement = $pdo->prepare(
'INSERT INTO participants (id, name, email, allergies, role, under_27, password_hash)
VALUES (:id, :name, :email, :allergies, :role, :under_27, :password_hash)'
);
$participantStatement->execute([
':id' => $participantId,
':name' => $name,
':email' => $email,
':allergies' => $allergies !== '' ? $allergies : null,
':role' => $role,
':under_27' => $under27 ? 1 : 0,
':password_hash' => $participantPasswordHash,
]);
$bookingStatement = $pdo->prepare(
'INSERT INTO bookings
(participant_id, type, accommodation_type, meal_preferences, roommate_requests, early_departure, other_notes, total_price)
VALUES
(:participant_id, :type, :accommodation_type, :meal_preferences, :roommate_requests, :early_departure, :other_notes, :total_price)'
);
$bookingStatement->execute([
':participant_id' => $participantId,
':type' => $bookingType,
':accommodation_type' => $accommodationType,
':meal_preferences' => $mealPreferences,
':roommate_requests' => $roommateRequest,
':early_departure' => $earlyDeparture,
':other_notes' => $otherNotes !== '' ? $otherNotes : null,
':total_price' => number_format($totalPrice, 2, '.', ''),
]);
$pdo->commit();
$mailError = '';
try {
sendRegistrationEmail(
$mailConfig,
$email,
$name,
$participantPassword,
$guestType,
$under27,
$roomType,
$days,
$mealsByDay,
$allergies,
$roommates,
$otherNotes
);
} catch (Throwable $exception) {
error_log('Registrierung gespeichert, E-Mail konnte nicht versendet werden: ' . $exception->getMessage());
$mailError = '<p class="message error">Die Registrierung wurde gespeichert, aber die Bestätigungs-E-Mail konnte nicht versendet werden. Bitte bewahre die Zugangsdaten auf dieser Seite auf.</p>';
}
$roomLabels = ['single' => 'Einzelzimmer', 'double' => 'Doppelzimmer', 'multi' => 'Mehrbettzimmer'];
$dayLabels = ['1' => 'Fr.', '2' => 'Sa.', '3' => 'So.'];
$mealLabels = [
'breakfast' => 'Frühstück',
'lunch' => 'Mittagessen',
'coffee' => 'Kaffee',
'drinks' => 'Getränkepauschale',
'dinner' => 'Abendessen',
'rehearsal_room' => 'Proberaumpauschale',
];
$guestLabel = $guestType === 'day_guest' ? 'Tagesgast' : 'Dauergast';
$ageLabel = $under27 ? 'Unter 27' : 'Ab 27';
$roomLabel = $roomLabels[$roomType] ?? '';
$dayText = implode(', ', array_map(static fn (string $day): string => $dayLabels[$day] ?? $day, $days)) ?: '';
$mealText = formatMealSummary($days, $mealsByDay);
$adminEmails = $pdo->query(
"SELECT email FROM admin_users WHERE is_active = 1 AND email <> ''"
)->fetchAll(PDO::FETCH_COLUMN);
foreach ($adminEmails as $adminEmail) {
if (!is_string($adminEmail) || !filter_var($adminEmail, FILTER_VALIDATE_EMAIL)) {
continue;
}
try {
sendAdminNotificationEmail(
$mailConfig,
(string) $adminEmail,
$name,
$email,
$guestLabel,
$ageLabel,
$roomLabel,
$dayText,
$mealText,
$roommates !== '' ? $roommates : '',
$allergies !== '' ? $allergies : '',
$otherNotes !== '' ? $otherNotes : ''
);
} catch (Throwable $exception) {
error_log('Admin-Benachrichtigung konnte nicht versendet werden: ' . $exception->getMessage());
}
}
http_response_code(201);
$safeEmail = escapeHtml($email);
$safePassword = escapeHtml($participantPassword);
exit(<<<HTML
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registrierung erfolgreich</title>
<link rel="stylesheet" href="./css/booking.css">
</head>
<body>
<main class="success-card">
<h1>Registrierung erfolgreich</h1>
{$mailError}
<p>Bitte bewahre die folgenden Zugangsdaten auf. Du benötigst sie, um deine Registrierung später zu ändern oder zu löschen.</p>
<dl class="credentials">
<dt>E-Mail-Adresse</dt>
<dd>{$safeEmail}</dd>
<dt>Passwort</dt>
<dd><code>{$safePassword}</code></dd>
</dl>
<p><a href="edit_registration.php">Registrierung ändern oder löschen</a></p>
<p><a href="index.php">Zur Startseite</a></p>
</main>
</body>
</html>
HTML);
} catch (Throwable $exception) {
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
error_log($exception->getMessage());
if ($exception instanceof PDOException && $exception->getCode() === '23000'
&& str_contains($exception->getMessage(), "for key 'email'")) {
http_response_code(409);
exit('Diese E-Mail-Adresse ist bereits registriert. Bitte nutze die Änderungs- oder Löschfunktion deiner bestehenden Registrierung.');
}
http_response_code(500);
exit('Die Registrierung konnte nicht gespeichert werden.');
}