Geizkragen/register.php

328 lines
11 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
/**
* @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 350 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';
?>