6 private string $ddUser =
'dbxUser';
7 private string $ddGroup =
'dbxUser_groups';
8 private string $pendingRole =
'registerd';
9 private string $confirmedRole =
'member';
11 private function user_exists($uname, $email =
'') {
12 $db =
dbx()->get_system_obj(
'dbxDB');
16 $uname = trim((
string)$uname);
18 $parts[] =
"uname='" .
$db->escape($uname,
$server) .
"'";
21 $email = trim((
string)$email);
23 $parts[] =
"email='" .
$db->escape($email,
$server) .
"'";
30 return $db->count($this->ddUser, implode(
' OR ', $parts));
33 private function ensure_pending_group() {
34 $db =
dbx()->get_system_obj(
'dbxDB');
36 $name =
$db->escape($this->pendingRole,
$server);
38 if (
$db->count($this->ddGroup,
"name='$name'") > 0) {
42 $db->insert($this->ddGroup, array(
43 'name' => $this->pendingRole,
44 'description' =>
'Registriert, E-Mail noch nicht bestaetigt',
49 private function new_token() {
50 return bin2hex(random_bytes(32));
53 private function settings_with_token(array $settings,
string $token) {
54 $settings[
'register_confirm'] = array(
55 'token_hash' => hash(
'sha256',
$token),
56 'expires' => time() + (48 * 3600),
57 'sent' => date(
'Y-m-d H:i:s'),
59 return json_encode($settings, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
62 private function decode_settings($settings) {
63 $data = json_decode((
string)$settings,
true);
64 return is_array($data) ? $data : array();
67 private function confirm_url($uid,
$token) {
68 return rtrim(
dbx()->
get_base_url(),
'/') .
'/?dbx_modul=dbxLogin&dbx_run1=register&dbx_run2=confirm&uid=' . (int)$uid .
'&token=' . rawurlencode(
$token);
71 private function current_domain() {
72 $domain = (string)(
$_SERVER[
'HTTP_HOST'] ??
$_SERVER[
'SERVER_NAME'] ??
'dbxApp');
73 $domain = preg_replace(
'/[^a-zA-Z0-9.\-_:]/',
'', $domain);
74 return $domain ?:
'dbxApp';
77 private function send_confirm_mail(array
$user,
string $token) {
79 $tpl =
dbx()->get_system_obj(
'dbxTPL');
81 'name' => htmlspecialchars((
string)(
$user[
'name'] ?:
$user[
'uname']), ENT_QUOTES,
'UTF-8'),
82 'uname' => htmlspecialchars((
string)
$user[
'uname'], ENT_QUOTES,
'UTF-8'),
83 'confirm_url' => htmlspecialchars(
$url, ENT_QUOTES,
'UTF-8'),
86 $html =
$tpl->get_tpl(
'dbxLogin|mail-register-confirm', $data);
87 $text =
"Hallo " . (string)(
$user[
'name'] ?:
$user[
'uname']) .
"\n\n"
88 .
"bitte bestaetige deine E-Mail-Adresse:\n" .
$url .
"\n\n"
89 .
"Erst danach erhaelt dein Konto die Rolle " . $this->confirmedRole .
".\n";
93 (
string)
$user[
'email'],
94 'dbxApp Registrierung bestaetigen',
98 array(
'text' => $text)
102 dbx()->sys_msg(
'error',
'register', (
int)
$user[
'id'],
'register confirm mail failed', (
string)
$user[
'email']);
108 private function confirmed_roles($roles) {
109 $parts = array_filter(array_map(
'trim', explode(
',', (
string)$roles)));
112 foreach ($parts as $role) {
113 if ($role === $this->pendingRole) {
119 $out[$this->confirmedRole] = $this->confirmedRole;
120 return implode(
',', array_values(
$out));
123 private function h(
$value) {
124 return htmlspecialchars((
string)
$value, ENT_QUOTES,
'UTF-8');
127 private function confirm_page(
string $status,
string $title,
string $message,
string $detail,
string $icon =
'bi-patch-check',
string $detailIcon =
'bi-envelope-check') {
128 $tpl =
dbx()->get_system_obj(
'dbxTPL');
129 return $tpl->get_tpl(
'dbxLogin|register-confirm', array(
130 'status' => $this->h($status),
131 'kicker' => $status ===
'error' ?
'Bestaetigung' :
'Willkommen',
133 'message' => $message,
135 'icon' => $this->h($icon),
136 'detail_icon' => $this->h($detailIcon),
140 private function confirm() {
141 $uid = (int)
dbx()->get_modul_var(
'uid', 0,
'int');
142 $token = (string)
dbx()->get_modul_var(
'token',
'',
'varchar|max=128');
144 if ($uid <= 0 ||
$token ===
'') {
145 return $this->confirm_page(
'error',
'Bestaetigungslink ungueltig',
'Der Link konnte nicht eindeutig zugeordnet werden.',
'Bitte pruefe den Link aus der E-Mail oder registriere dich erneut.',
'bi-exclamation-triangle',
'bi-link-45deg');
148 $db =
dbx()->get_system_obj(
'dbxDB');
149 $user =
$db->select1($this->ddUser, $uid,
'*', 0);
152 return $this->confirm_page(
'error',
'Benutzer nicht gefunden',
'Zu diesem Bestaetigungslink wurde kein Benutzerkonto gefunden.',
'Bitte registriere dich erneut oder wende dich an den Administrator.',
'bi-person-x',
'bi-search');
155 if ((
int)(
$user[
'is_confirm'] ?? 0) === 1 && preg_match(
'/(^|,)' . preg_quote($this->confirmedRole,
'/') .
'(,|$)/', (
string)(
$user[
'roles'] ??
''))) {
156 $name = (string)(
$user[
'name'] ?:
$user[
'uname'] ??
'');
157 return $this->confirm_page(
'success',
'Willkommen zurueck' . ($name ?
', ' . $name :
''),
'Deine E-Mail-Adresse ist bereits bestaetigt.',
'Dein Konto ist freigeschaltet. Du kannst dich jetzt anmelden.',
'bi-patch-check',
'bi-person-check');
160 $settings = $this->decode_settings(
$user[
'settings'] ??
'');
161 $confirm = $settings[
'register_confirm'] ?? array();
162 $hash = (string)(
$confirm[
'token_hash'] ??
'');
163 $expires = (int)(
$confirm[
'expires'] ?? 0);
165 if ($hash ===
'' || !hash_equals($hash, hash(
'sha256',
$token))) {
166 return $this->confirm_page(
'error',
'Bestaetigungslink ungueltig',
'Der Token passt nicht zu diesem Benutzerkonto.',
'Bitte nutze den neuesten Link aus deiner E-Mail oder registriere dich erneut.',
'bi-exclamation-triangle',
'bi-shield-x');
169 if ($expires > 0 && $expires < time()) {
170 return $this->confirm_page(
'error',
'Bestaetigungslink abgelaufen',
'Dieser Link ist nicht mehr gueltig.',
'Bitte registriere dich erneut oder fordere einen neuen Link an.',
'bi-hourglass-split',
'bi-clock-history');
173 unset($settings[
'register_confirm']);
174 $settingsJson = $settings ? json_encode($settings, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) :
'{}';
175 $ok =
$db->update($this->ddUser, array(
176 'roles' => $this->confirmed_roles(
$user[
'roles'] ??
''),
178 'settings' => $settingsJson,
179 ), $uid, 0, 1, 1, 1);
182 dbx()->sys_msg(
'info',
'register', $uid,
'user email confirmed', (
string)(
$user[
'uname'] ??
''));
183 $name = (string)(
$user[
'name'] ?:
$user[
'uname'] ??
'');
184 return $this->confirm_page(
'success',
'Willkommen' . ($name ?
', ' . $name :
''),
'Deine E-Mail-Adresse ist bestaetigt.',
'Dein Konto ist jetzt als member freigeschaltet. Du kannst dich direkt anmelden.',
'bi-patch-check',
'bi-stars');
187 return $this->confirm_page(
'error',
'Bestaetigung nicht gespeichert',
'Die Bestaetigung konnte technisch nicht gespeichert werden.',
'Bitte versuche es erneut oder wende dich an den Administrator.',
'bi-exclamation-triangle',
'bi-database-x');
190 private function resend_confirm() {
191 if (strtoupper((
string)(
$_SERVER[
'REQUEST_METHOD'] ??
'GET')) !==
'POST') {
192 return $this->confirm_page(
'error',
'Aktion nicht erlaubt',
'Der Bestaetigungslink kann nur ueber das Formular erneut angefordert werden.',
'Bitte melde dich erneut an und nutze den Button zum erneuten Versand.',
'bi-exclamation-triangle',
'bi-shield-x');
197 $form =
dbx()->get_system_obj(
'dbxForm');
198 $form->init(
'login-unconfirmed',
'login-unconfirmed');
199 $form->add_fld(
'dbx_token',
'dbx|hidden', rules:
'parameter', dd:
'');
201 dbx()->sys_msg(
'security',
'register',
'',
'invalid resend confirm form',
$_SERVER[
'REMOTE_ADDR'] ??
'');
202 return $this->confirm_page(
'error',
'Sicherheitspruefung fehlgeschlagen',
'Der erneute Versand konnte nicht gestartet werden.',
'Bitte melde dich erneut an und versuche es noch einmal.',
'bi-exclamation-triangle',
'bi-shield-lock');
205 $postedToken = (string)(
$_POST[
'dbx_token'] ??
'');
207 dbx()->sys_msg(
'security',
'register',
'',
'invalid resend confirm token',
$_SERVER[
'REMOTE_ADDR'] ??
'');
208 return $this->confirm_page(
'error',
'Sicherheitspruefung fehlgeschlagen',
'Der erneute Versand konnte nicht gestartet werden.',
'Bitte melde dich erneut an und versuche es noch einmal.',
'bi-exclamation-triangle',
'bi-shield-lock');
211 $uid = (int)
dbx()->get_session_var(
'pending_confirm_uid', 0,
'confirm',
'dbxLogin');
213 return $this->confirm_page(
'error',
'Anmeldung abgelaufen',
'Die zu bestaetigende Anmeldung wurde nicht mehr gefunden.',
'Bitte melde dich erneut mit Benutzername und Passwort an.',
'bi-hourglass-split',
'bi-person-x');
216 $currentUid = (int)
dbx()->user();
217 if ($currentUid > 0 && $currentUid !== $uid) {
218 dbx()->delete_session_var(
'pending_confirm_uid',
'confirm',
'dbxLogin');
219 dbx()->sys_msg(
'security',
'register', $uid,
'resend confirm user mismatch',
'current=' . $currentUid .
' ip=' . (
$_SERVER[
'REMOTE_ADDR'] ??
''));
220 return $this->confirm_page(
'error',
'Anmeldung passt nicht',
'Der erneute Versand passt nicht zu deiner aktuellen Sitzung.',
'Bitte melde dich erneut mit dem betroffenen Benutzerkonto an.',
'bi-exclamation-triangle',
'bi-person-x');
223 $db =
dbx()->get_system_obj(
'dbxDB');
224 $user =
$db->select1($this->ddUser, $uid,
'*', 0);
226 dbx()->delete_session_var(
'pending_confirm_uid',
'confirm',
'dbxLogin');
227 return $this->confirm_page(
'error',
'Benutzer nicht gefunden',
'Das Benutzerkonto konnte nicht mehr geladen werden.',
'Bitte registriere dich erneut oder wende dich an den Administrator.',
'bi-person-x',
'bi-search');
230 if ((
int)(
$user[
'is_confirm'] ?? 0) === 1) {
231 dbx()->delete_session_var(
'pending_confirm_uid',
'confirm',
'dbxLogin');
232 $name = (string)(
$user[
'name'] ?:
$user[
'uname'] ??
'');
233 return $this->confirm_page(
'success',
'Willkommen zurueck' . ($name ?
', ' . $name :
''),
'Deine E-Mail-Adresse ist bereits bestaetigt.',
'Dein Konto ist freigeschaltet. Du kannst dich jetzt anmelden.',
'bi-patch-check',
'bi-person-check');
236 if (trim((
string)(
$user[
'email'] ??
'')) ===
'') {
237 return $this->confirm_page(
'error',
'Keine E-Mail-Adresse hinterlegt',
'Fuer dieses Benutzerkonto ist keine E-Mail-Adresse gespeichert.',
'Bitte wende dich an den Administrator, damit die Adresse korrigiert werden kann.',
'bi-exclamation-triangle',
'bi-envelope-x');
240 $token = $this->new_token();
241 $settings = $this->decode_settings(
$user[
'settings'] ??
'');
242 $ok =
$db->update($this->ddUser, array(
243 'settings' => $this->settings_with_token($settings,
$token),
244 ), $uid, 0, 1, 1, 1);
247 return $this->confirm_page(
'error',
'Bestaetigungslink nicht gespeichert',
'Der neue Bestaetigungslink konnte technisch nicht gespeichert werden.',
'Bitte versuche es erneut oder wende dich an den Administrator.',
'bi-exclamation-triangle',
'bi-database-x');
252 return $this->confirm_page(
'error',
'E-Mail nicht gesendet',
'Der Bestaetigungslink wurde erzeugt, die E-Mail konnte aber nicht versendet werden.',
'Bitte pruefe die Mail-Konfiguration oder wende dich an den Administrator.',
'bi-exclamation-triangle',
'bi-envelope-x');
255 dbx()->sys_msg(
'info',
'register', $uid,
'confirm mail resent', (
string)(
$user[
'email'] ??
''));
256 return $this->confirm_page(
'success',
'Bestaetigungslink gesendet',
'Wir haben dir einen neuen Link zur E-Mail-Bestaetigung gesendet.',
'Bitte pruefe dein Postfach und auch den Spam-Ordner.',
'bi-envelope-check',
'bi-send-check');
260 $run2 =
dbx()->get_modul_var(
'dbx_run2',
'',
'parameter');
261 if ($run2 ===
'confirm') {
262 return $this->confirm();
264 if ($run2 ===
'resend_confirm') {
265 return $this->resend_confirm();
269 return dbx()->redirect(
'?dbx_modul=dbxUser&dbx_run1=user&dbx_run2=edit_profil', 1);
272 $oForm =
dbx()->get_system_obj(
'dbxForm');
273 $oForm->init(
'form-register');
274 $oForm->_fd =
'dbxLogin|register';
275 $oForm->load_fd_messages();
276 dbx()->set_system_var(
278 $oForm->get_fd_message(
'page_title')
280 $oForm->add_module_bar(
281 $oForm->get_fd_message(
'bar_title'),
283 $oForm->get_fd_message(
'bar_subtitle')
286 $oForm->_data = array_merge($oForm->_data, array(
289 $oForm->_action =
'?dbx_modul=dbxLogin&dbx_run1=register';
290 $oForm->_msg_info = $oForm->format_fd_message(
292 array(
'domain' => $this->current_domain())
294 $oForm->_msg_error = $oForm->get_fd_message(
'validation_error');
295 $oForm->add_obj(
'login_link',
'obj-value',
'');
297 $oForm->add_fld(
'uname');
298 $oForm->add_fld(
'name');
299 $oForm->add_fld(
'email');
300 $oForm->add_fld(
'password');
301 $oForm->add_fld(
'password2');
302 $oForm->add_fld(
'language');
304 if ($oForm->submit()) {
305 if (!$oForm->errors()) {
306 $uname = $oForm->get_post(
'uname',
'',
'parameter|max=60');
307 $email = $oForm->get_post(
'email',
'',
'email|max=60');
308 $pass1 = $oForm->get_post_data(
'password',
'',
'varchar|max=128');
309 $pass2 = $oForm->get_post_data(
'password2',
'',
'varchar|max=128');
311 if ($pass1 !== $pass2) {
312 $oForm->add_fld_error(
314 $oForm->get_fd_message(
'password_mismatch')
316 $oForm->_msg_error = $oForm->get_fd_message(
319 } elseif ($this->user_exists($uname, $email) > 0) {
320 $oForm->add_fld_error(
322 $oForm->get_fd_message(
'user_exists')
324 $oForm->_msg_error = $oForm->get_fd_message(
'user_exists');
326 $this->ensure_pending_group();
327 $db =
dbx()->get_system_obj(
'dbxDB');
328 $token = $this->new_token();
331 'name' => $oForm->get_post(
'name',
'',
'words|max=60'),
333 'pass' => password_hash($pass1, PASSWORD_DEFAULT),
334 'roles' => $this->pendingRole,
337 'language' => $oForm->get_post(
'language',
'de',
'parameter|min=2|max=3'),
338 'avatar' =>
'avatar-0.png',
339 'settings' => $this->settings_with_token(array(),
$token),
342 $id = (
$db->insert($this->ddUser, $values, 0, 1, 1, 1) === 1) ?
$db->get_insert_id() : 0;
345 $mail_ok = $this->send_confirm_mail($values,
$token);
346 dbx()->sys_msg(
'login',
'register', $id,
'new user registered', $uname);
348 $oForm->_msg_success = $oForm->get_fd_message(
352 $oForm->_msg_error = $oForm->get_fd_message(
356 $oForm->add_obj(
'login_link',
'dbxLogin|register-login-button');
358 $oForm->_msg_error = $oForm->get_fd_message(
364 $oForm->_msg_error = $oForm->get_fd_message(
370 return $oForm->run();