328 lines
11 KiB
PHP
328 lines
11 KiB
PHP
<?php
|
||
/**
|
||
* @file register.php
|
||
* @brief Behandelt die Registrierung neuer Benutzer.
|
||
*
|
||
* @details Diese Datei stellt das Registrierungsformular bereit und verarbeitet die
|
||
* abgesendeten POST-Daten. Sie validiert die Eingaben (E-Mail, Benutzername, Passwort),
|
||
* prüft auf Duplikate in der Datenbank und legt bei erfolgreicher Validierung einen neuen
|
||
* Benutzer samt zugehöriger Standard-Rolle ("USER") in der Datenbank an.
|
||
*
|
||
* @author System
|
||
* @version 1.0
|
||
*/
|
||
|
||
// register.php
|
||
|
||
require_once __DIR__ . '/lib/bootstrap.php';
|
||
require_once __DIR__ . '/lib/strings.php';
|
||
|
||
/**
|
||
* @brief Initiiert die globale Datenbankverbindung.
|
||
* @details Ruft die Funktion db_connect() auf, um eine Verbindung zur konfigurierten
|
||
* Datenbank herzustellen. Diese Verbindung wird für alle folgenden Queries verwendet.
|
||
*/
|
||
// 1) DB-Verbindung (einmal)
|
||
$conn = db_connect();
|
||
|
||
/**
|
||
* @brief Array zur Speicherung möglicher Validierungs- oder Datenbankfehler.
|
||
* @var array $errors
|
||
*/
|
||
$errors = [];
|
||
|
||
/**
|
||
* @brief Array zur Zwischenspeicherung der eingegebenen Formulardaten.
|
||
* @details Dient dazu, die Eingaben des Nutzers (E-Mail und Anzeigename) nach
|
||
* einem fehlerhaften Submit-Versuch wieder im Formularfeld anzeigen zu können.
|
||
* @var array $values
|
||
*/
|
||
$values = [
|
||
'email' => '',
|
||
'displayName' => ''
|
||
];
|
||
|
||
/**
|
||
* @brief Prüft, ob das Formular per POST-Methode abgesendet wurde.
|
||
* @details Alle Validierungs- und Registrierungsschritte werden nur ausgeführt,
|
||
* wenn Daten via POST übermittelt wurden.
|
||
*/
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST')
|
||
{
|
||
/**
|
||
* @brief Holt und bereinigt die eingegebene E-Mail-Adresse.
|
||
* @var string $email
|
||
*/
|
||
$email = '';
|
||
if (isset($_POST['email']))
|
||
{
|
||
$email = trim((string)$_POST['email']);
|
||
}
|
||
|
||
/**
|
||
* @brief Holt und bereinigt den eingegebenen Benutzernamen.
|
||
* @var string $displayName
|
||
*/
|
||
$displayName = '';
|
||
if (isset($_POST['displayName']))
|
||
{
|
||
$displayName = trim((string)$_POST['displayName']);
|
||
}
|
||
|
||
/**
|
||
* @brief Holt das eingegebene Passwort.
|
||
* @var string $pw
|
||
*/
|
||
$pw = '';
|
||
if (isset($_POST['pw']))
|
||
{
|
||
$pw = (string)$_POST['pw'];
|
||
}
|
||
|
||
/**
|
||
* @brief Holt die Wiederholung des eingegebenen Passworts.
|
||
* @var string $pw2
|
||
*/
|
||
$pw2 = '';
|
||
if (isset($_POST['pw2']))
|
||
{
|
||
$pw2 = (string)$_POST['pw2'];
|
||
}
|
||
|
||
/**
|
||
* @brief Standard-Profilbild für neu registrierte Nutzer.
|
||
* @var string $profilePicture
|
||
*/
|
||
$profilePicture = 'assets/images/profilePictures/default.png';
|
||
|
||
// Aktualisiere das $values-Array für die erneute Anzeige bei Fehlern
|
||
$values['email'] = $email;
|
||
$values['displayName'] = $displayName;
|
||
|
||
/**
|
||
* @brief Validierung der Eingabedaten.
|
||
* @details Prüft E-Mail-Format, Länge des Benutzernamens (3-50 Zeichen),
|
||
* Passwortlänge (min. 8 Zeichen) und Übereinstimmung der Passwörter.
|
||
*/
|
||
// Validierung
|
||
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL))
|
||
{
|
||
$errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.';
|
||
}
|
||
|
||
if ($displayName === '' || str_length($displayName) < 3 || str_length($displayName) > 50)
|
||
{
|
||
$errors[] = 'Bitte einen Benutzernamen mit 3–50 Zeichen eingeben.';
|
||
}
|
||
|
||
if ($pw === '' || str_length($pw) < 8)
|
||
{
|
||
$errors[] = 'Bitte ein Passwort mit mindestens 8 Zeichen wählen.';
|
||
}
|
||
|
||
if ($pw !== $pw2)
|
||
{
|
||
$errors[] = 'Die Passwörter stimmen nicht überein.';
|
||
}
|
||
|
||
/**
|
||
* @brief Prüfung auf bereits existierende E-Mail.
|
||
* @details Falls bisher keine Fehler aufgetreten sind, wird in der Datenbank
|
||
* geprüft, ob die angegebene E-Mail bereits von einem anderen Account genutzt wird.
|
||
*/
|
||
// Duplicate-Checks
|
||
if (!$errors)
|
||
{
|
||
$stmt = mysqli_prepare($conn, 'SELECT userID FROM users WHERE email = ? LIMIT 1');
|
||
if (!$stmt)
|
||
{
|
||
$errors[] = 'Datenbankfehler.';
|
||
}
|
||
else
|
||
{
|
||
mysqli_stmt_bind_param($stmt, 's', $email);
|
||
mysqli_stmt_execute($stmt);
|
||
$result = mysqli_stmt_get_result($stmt);
|
||
if ($result && mysqli_fetch_assoc($result))
|
||
{
|
||
$errors[] = 'Diese E-Mail ist bereits registriert.';
|
||
}
|
||
mysqli_stmt_close($stmt);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Prüfung auf bereits existierenden Benutzernamen.
|
||
* @details Führt eine Datenbankabfrage durch, um sicherzustellen, dass
|
||
* der gewählte Anzeigename (displayName) noch verfügbar ist.
|
||
*/
|
||
if (!$errors)
|
||
{
|
||
$stmt = mysqli_prepare($conn, 'SELECT userID FROM users WHERE displayName = ? LIMIT 1');
|
||
if (!$stmt)
|
||
{
|
||
$errors[] = 'Datenbankfehler.';
|
||
}
|
||
else
|
||
{
|
||
mysqli_stmt_bind_param($stmt, 's', $displayName);
|
||
mysqli_stmt_execute($stmt);
|
||
$result = mysqli_stmt_get_result($stmt);
|
||
if ($result && mysqli_fetch_assoc($result))
|
||
{
|
||
$errors[] = 'Dieser Benutzername ist bereits vergeben.';
|
||
}
|
||
mysqli_stmt_close($stmt);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Finaler Insert-Vorgang für den neuen Benutzer.
|
||
* @details Wenn keine Fehler vorliegen, wird das Passwort gehasht und der
|
||
* Benutzer in der Tabelle `users` gespeichert. Anschließend wird ihm die
|
||
* Standard-Rolle (USER) auf der Tabelle `userRoles` zugewiesen und
|
||
* auf die Login-Seite weitergeleitet.
|
||
*/
|
||
// Insert
|
||
if (!$errors)
|
||
{
|
||
$hash = password_hash($pw, PASSWORD_DEFAULT);
|
||
$stmt = mysqli_prepare(
|
||
$conn,
|
||
"INSERT INTO users (email, passwordHash, displayName, isActive, createdAt, profilePicture) VALUES (?, ?, ?, 1, NOW(), ?)"
|
||
);
|
||
|
||
if (!$stmt)
|
||
{
|
||
$errors[] = 'Datenbankfehler.';
|
||
}
|
||
else
|
||
{
|
||
mysqli_stmt_bind_param($stmt, 'ssss', $email, $hash, $displayName, $profilePicture);
|
||
$ok = mysqli_stmt_execute($stmt);
|
||
|
||
if ($ok)
|
||
{
|
||
/**
|
||
* @brief ID des soeben neu erstellten Benutzers.
|
||
* @var int $newUserId
|
||
*/
|
||
$newUserId = mysqli_insert_id($conn);
|
||
|
||
/**
|
||
* @brief Zuweisung der initialen Benutzerrolle "USER".
|
||
* @details Sucht die ID der "USER"-Rolle aus der Tabelle `roles`
|
||
* und verknüpft sie mit der neuen Benutzer-ID in `userRoles`.
|
||
*/
|
||
// Get USER roleID
|
||
$roleStmt = mysqli_prepare($conn, "SELECT roleID FROM roles WHERE name = 'USER' LIMIT 1");
|
||
if ($roleStmt) {
|
||
mysqli_stmt_execute($roleStmt);
|
||
$roleResult = mysqli_stmt_get_result($roleStmt);
|
||
if ($roleRow = mysqli_fetch_assoc($roleResult)) {
|
||
$userRoleId = $roleRow['roleID'];
|
||
|
||
$insertRoleStmt = mysqli_prepare($conn, "INSERT INTO userRoles (userID, roleID) VALUES (?, ?)");
|
||
if ($insertRoleStmt) {
|
||
mysqli_stmt_bind_param($insertRoleStmt, 'ii', $newUserId, $userRoleId);
|
||
mysqli_stmt_execute($insertRoleStmt);
|
||
mysqli_stmt_close($insertRoleStmt);
|
||
}
|
||
}
|
||
mysqli_stmt_close($roleStmt);
|
||
}
|
||
|
||
mysqli_stmt_close($stmt);
|
||
|
||
mysqli_close($conn);
|
||
|
||
/**
|
||
* @brief Weiterleitung nach erfolgreicher Registrierung.
|
||
* @details Leitet zurück auf login.php mit dem GET-Parameter `registered=1`,
|
||
* damit der Nutzer eine Erfolgsmeldung erhält.
|
||
*/
|
||
header('Location: login.php?registered=1');
|
||
exit;
|
||
}
|
||
|
||
mysqli_stmt_close($stmt);
|
||
$errors[] = 'Registrierung fehlgeschlagen.';
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Einbinden des Seiten-Headers.
|
||
* @details Lädt die globale Navigationstruktur für die visuelle Darstellung (HTML/CSS).
|
||
*/
|
||
include 'header.php';
|
||
?>
|
||
|
||
<!--
|
||
@brief Start des HTML-Hauptbereichs für die Registrierung.
|
||
@details Beinhaltet das Registrierungsformular, die Ausgabe etwaiger Fehler
|
||
sowie Links zum Login für bereits angemeldete Benutzer.
|
||
-->
|
||
<main class="auth" role="main">
|
||
<section class="auth__grid" aria-label="Registrierung Bereich">
|
||
<div class="auth__card">
|
||
<header class="auth__header">
|
||
<h2 class="auth__title">Registrierung</h2>
|
||
</header>
|
||
|
||
<?php if ($errors): ?>
|
||
<div class="auth__alert" role="alert">
|
||
<ul>
|
||
<?php foreach ($errors as $e): ?>
|
||
<li><?php echo htmlspecialchars($e, ENT_QUOTES, 'UTF-8'); ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<form class="auth__form" action="register.php" method="POST" autocomplete="on">
|
||
<div class="auth__field">
|
||
<label for="email">E-Mail</label>
|
||
<input type="text" id="email" name="email" autocomplete="email" required
|
||
value="<?php echo htmlspecialchars($values['email'], ENT_QUOTES, 'UTF-8'); ?>">
|
||
</div>
|
||
|
||
<div class="auth__field">
|
||
<label for="displayName">Username</label>
|
||
<input type="text" id="displayName" name="displayName" inputmode="text" autocomplete="username"
|
||
required
|
||
value="<?php echo htmlspecialchars($values['displayName'], ENT_QUOTES, 'UTF-8'); ?>">
|
||
</div>
|
||
|
||
<div class="auth__field">
|
||
<label for="pw">Passwort</label>
|
||
<input type="password" id="pw" name="pw" autocomplete="new-password" required>
|
||
</div>
|
||
|
||
<div class="auth__field">
|
||
<label for="pw2">Passwort wiederholen</label>
|
||
<input type="password" id="pw2" name="pw2" autocomplete="new-password" required>
|
||
</div>
|
||
|
||
<div class="auth__actions">
|
||
<input class="auth__submit" type="submit" value="Registrieren">
|
||
</div>
|
||
</form>
|
||
|
||
<div class="auth__links">
|
||
<p class="auth__muted">Schon registriert? <a href="login.php">Einloggen</a></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<?php
|
||
/**
|
||
* @brief Schließt die Datenbankverbindung und bindet den Footer ein.
|
||
* @details Säubert die offene MySQLi-Verbindung. Der Footer schließt
|
||
* das HTML-Dokument korrekt ab.
|
||
*/
|
||
mysqli_close($conn);
|
||
include 'footer.php';
|
||
?>
|