Files
skyview.astronomiemuseum.de/public/register.php
T

324 lines
9.7 KiB
PHP

<?php
declare(strict_types=1);
ini_set('display_errors', '1');
error_reporting(E_ALL);
session_start();
$config = require __DIR__ . '/../config/database.php';
$dsn = sprintf(
'mysql:host=%s;dbname=%s;charset=%s',
$config['host'],
$config['dbname'],
$config['charset'] ?? 'utf8mb4'
);
$pdo = new PDO(
$dsn,
$config['user'],
$config['pass'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
$errors = [];
$successMessage = '';
const DEFAULT_LOCATION_NAME = 'Sternwarte Sonneberg';
const DEFAULT_LOCATION_LATITUDE = 50.377;
const DEFAULT_LOCATION_LONGITUDE = 11.189;
const DEFAULT_LOCATION_ELEVATION = 640.0;
const DEFAULT_LOCATION_TIMEZONE = 'Europe/Berlin';
const DEFAULT_SATELLITE_ID = 61;
function sendRegistrationNotification(string $username, string $email, ?string $displayName): void
{
$to = 'tm@astronomiemuseum.de';
$subject = 'Neue Registrierung bei SkyView';
$safeDisplayName = $displayName !== null && $displayName !== '' ? $displayName : '-';
$messageLines = [
'Ein neuer Benutzer hat sich registriert.',
'',
'Benutzername: ' . $username,
'E-Mail: ' . $email,
'Anzeigename: ' . $safeDisplayName,
'Zeitpunkt: ' . date('Y-m-d H:i:s'),
];
$headers = [
'MIME-Version: 1.0',
'Content-Type: text/plain; charset=UTF-8',
'From: noreply@astronomiemuseum.de',
'Reply-To: ' . $email,
];
try {
mail(
$to,
$subject,
implode(PHP_EOL, $messageLines),
implode("\r\n", $headers)
);
} catch (Throwable $e) {
error_log('Registration notification mail failed: ' . $e->getMessage());
}
}
function textLength(string $value): int
{
if (function_exists('mb_strlen')) {
return mb_strlen($value);
}
return strlen($value);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$email = trim($_POST['email'] ?? '');
$displayName = trim($_POST['display_name'] ?? '');
$password = $_POST['password'] ?? '';
$passwordRepeat = $_POST['password_repeat'] ?? '';
if ($username === '') {
$errors[] = 'Bitte einen Benutzernamen eingeben.';
} elseif (textLength($username) < 3) {
$errors[] = 'Der Benutzername muss mindestens 3 Zeichen lang sein.';
} elseif (textLength($username) > 50) {
$errors[] = 'Der Benutzername darf maximal 50 Zeichen lang sein.';
}
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.';
}
if ($password === '') {
$errors[] = 'Bitte ein Passwort eingeben.';
} elseif (strlen($password) < 8) {
$errors[] = 'Das Passwort muss mindestens 8 Zeichen lang sein.';
}
if ($passwordRepeat === '') {
$errors[] = 'Bitte das Passwort wiederholen.';
} elseif ($password !== $passwordRepeat) {
$errors[] = 'Die Passwörter stimmen nicht überein.';
}
if ($displayName !== '' && textLength($displayName) > 100) {
$errors[] = 'Der Anzeigename darf maximal 100 Zeichen lang sein.';
}
if (empty($errors)) {
$stmtCheck = $pdo->prepare("
SELECT `id`
FROM `app_users`
WHERE `username` = :username OR `email` = :email
LIMIT 1
");
$stmtCheck->execute([
':username' => $username,
':email' => $email,
]);
if ($stmtCheck->fetch()) {
$errors[] = 'Benutzername oder E-Mail-Adresse ist bereits vergeben.';
}
}
if (empty($errors)) {
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
$pdo->beginTransaction();
try {
$stmtInsert = $pdo->prepare("
INSERT INTO `app_users` (
`username`,
`email`,
`password_hash`,
`display_name`,
`role`,
`is_active`,
`created_at`,
`updated_at`
) VALUES (
:username,
:email,
:password_hash,
:display_name,
'user',
0,
NOW(),
NOW()
)
");
$stmtInsert->execute([
':username' => $username,
':email' => $email,
':password_hash' => $passwordHash,
':display_name' => $displayName !== '' ? $displayName : null,
]);
$userId = (int)$pdo->lastInsertId();
$stmtInsertLocation = $pdo->prepare("
INSERT INTO `app_user_locations` (
`user_id`,
`name`,
`latitude`,
`longitude`,
`elevation`,
`timezone`,
`is_default`,
`created_at`,
`updated_at`
) VALUES (
:user_id,
:name,
:latitude,
:longitude,
:elevation,
:timezone,
1,
NOW(),
NOW()
)
");
$stmtInsertLocation->execute([
':user_id' => $userId,
':name' => DEFAULT_LOCATION_NAME,
':latitude' => DEFAULT_LOCATION_LATITUDE,
':longitude' => DEFAULT_LOCATION_LONGITUDE,
':elevation' => DEFAULT_LOCATION_ELEVATION,
':timezone' => DEFAULT_LOCATION_TIMEZONE,
]);
$stmtInsertSatellite = $pdo->prepare("
INSERT INTO `app_user_satellites` (
`user_id`,
`satellite_id`,
`is_favorite`,
`created_at`
) VALUES (
:user_id,
:satellite_id,
1,
NOW()
)
");
$stmtInsertSatellite->execute([
':user_id' => $userId,
':satellite_id' => DEFAULT_SATELLITE_ID,
]);
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
throw $e;
}
sendRegistrationNotification(
$username,
$email,
$displayName !== '' ? $displayName : null
);
$successMessage = 'Die Registrierung war erfolgreich. Das Konto wurde angelegt und muss noch freigeschaltet werden.';
$_POST = [];
}
}
$loggedIn = false;
?>
<?php require __DIR__ . '/header.php'; ?>
<div class="auth-wrap">
<div class="card auth-card">
<h2>Registrieren</h2>
<p class="hint mb-lg">Nach der Registrierung wird das Konto zunächst deaktiviert und später freigeschaltet.</p>
<?php if ($successMessage !== ''): ?>
<p class="msg-success"><?= htmlspecialchars($successMessage, ENT_QUOTES, 'UTF-8') ?></p>
<?php endif; ?>
<?php if (!empty($errors)): ?>
<ul class="msg-error">
<?php foreach ($errors as $error): ?>
<li><?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<form method="post" action="" class="form-stack">
<div class="form-group">
<label for="username">Benutzername</label>
<input
type="text"
id="username"
name="username"
required
maxlength="50"
value="<?= htmlspecialchars($_POST['username'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
>
</div>
<div class="form-group">
<label for="display_name">Anzeigename <span class="form-optional">(optional)</span></label>
<input
type="text"
id="display_name"
name="display_name"
maxlength="100"
value="<?= htmlspecialchars($_POST['display_name'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
>
</div>
<div class="form-group">
<label for="email">E-Mail-Adresse</label>
<input
type="email"
id="email"
name="email"
required
maxlength="190"
value="<?= htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
>
</div>
<div class="form-group">
<label for="password">Passwort</label>
<input
type="password"
id="password"
name="password"
required
>
</div>
<div class="form-group">
<label for="password_repeat">Passwort wiederholen</label>
<input
type="password"
id="password_repeat"
name="password_repeat"
required
>
</div>
<button type="submit" class="btn btn-primary btn-full">Konto anlegen</button>
</form>
<p class="form-footer">Bereits registriert? <a href="login.php">Anmelden</a></p>
</div>
</div>
<?php require __DIR__ . '/footer.php'; ?>