dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
register.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\dbxLogin;
3
4class register {
5
6 private string $ddUser = 'dbxUser';
7 private string $ddGroup = 'dbxUser_groups';
8 private string $pendingRole = 'registerd';
9 private string $confirmedRole = 'member';
10
11 private function user_exists($uname, $email = '') {
12 $db = dbx()->get_system_obj('dbxDB');
13 $server = $db->get_dd_server($this->ddUser);
14 $parts = array();
15
16 $uname = trim((string)$uname);
17 if ($uname !== '') {
18 $parts[] = "uname='" . $db->escape($uname, $server) . "'";
19 }
20
21 $email = trim((string)$email);
22 if ($email !== '') {
23 $parts[] = "email='" . $db->escape($email, $server) . "'";
24 }
25
26 if (!$parts) {
27 return 0;
28 }
29
30 return $db->count($this->ddUser, implode(' OR ', $parts));
31 }
32
33 private function ensure_pending_group() {
34 $db = dbx()->get_system_obj('dbxDB');
35 $server = $db->get_dd_server($this->ddGroup);
36 $name = $db->escape($this->pendingRole, $server);
37
38 if ($db->count($this->ddGroup, "name='$name'") > 0) {
39 return;
40 }
41
42 $db->insert($this->ddGroup, array(
43 'name' => $this->pendingRole,
44 'description' => 'Registriert, E-Mail noch nicht bestaetigt',
45 'active' => 1,
46 ), 0, 1, 1, 1);
47 }
48
49 private function new_token() {
50 return bin2hex(random_bytes(32));
51 }
52
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'),
58 );
59 return json_encode($settings, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
60 }
61
62 private function decode_settings($settings) {
63 $data = json_decode((string)$settings, true);
64 return is_array($data) ? $data : array();
65 }
66
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);
69 }
70
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';
75 }
76
77 private function send_confirm_mail(array $user, string $token) {
78 $url = $this->confirm_url((int)$user['id'], $token);
79 $tpl = dbx()->get_system_obj('dbxTPL');
80 $data = array(
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'),
84 );
85
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";
90
91 $ok = dbx()->send_mail(
92 'register@dbxapp.de',
93 (string)$user['email'],
94 'dbxApp Registrierung bestaetigen',
95 $html,
96 'html',
97 array(),
98 array('text' => $text)
99 );
100
101 if (!$ok) {
102 dbx()->sys_msg('error', 'register', (int)$user['id'], 'register confirm mail failed', (string)$user['email']);
103 }
104
105 return $ok;
106 }
107
108 private function confirmed_roles($roles) {
109 $parts = array_filter(array_map('trim', explode(',', (string)$roles)));
110 $out = array();
111
112 foreach ($parts as $role) {
113 if ($role === $this->pendingRole) {
114 continue;
115 }
116 $out[$role] = $role;
117 }
118
119 $out[$this->confirmedRole] = $this->confirmedRole;
120 return implode(',', array_values($out));
121 }
122
123 private function h($value) {
124 return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
125 }
126
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',
132 'title' => $title,
133 'message' => $message,
134 'detail' => $detail,
135 'icon' => $this->h($icon),
136 'detail_icon' => $this->h($detailIcon),
137 ));
138 }
139
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');
143
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');
146 }
147
148 $db = dbx()->get_system_obj('dbxDB');
149 $user = $db->select1($this->ddUser, $uid, '*', 0);
150
151 if (!is_array($user) || empty($user['id'])) {
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');
153 }
154
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');
158 }
159
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);
164
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');
167 }
168
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');
171 }
172
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'] ?? ''),
177 'is_confirm' => 1,
178 'settings' => $settingsJson,
179 ), $uid, 0, 1, 1, 1);
180
181 if ($ok === 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');
185 }
186
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');
188 }
189
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');
193 }
194
195 // Das Ziel rekonstruiert dasselbe Formular wie die Login-Seite. Die
196 // Fachaktion darf erst nach gültigem dbxForm-Submit weiterlaufen.
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: '');
200 if (!$form->submit() || $form->errors()) {
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');
203 }
204
205 $postedToken = (string)($_POST['dbx_token'] ?? '');
206 if (!dbx()->check_action_token('dbxLogin.resend_confirm', $postedToken)) {
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');
209 }
210
211 $uid = (int)dbx()->get_session_var('pending_confirm_uid', 0, 'confirm', 'dbxLogin');
212 if ($uid <= 0) {
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');
214 }
215
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');
221 }
222
223 $db = dbx()->get_system_obj('dbxDB');
224 $user = $db->select1($this->ddUser, $uid, '*', 0);
225 if (!is_array($user) || empty($user['id'])) {
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');
228 }
229
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');
234 }
235
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');
238 }
239
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);
245
246 if ($ok <= 0) {
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');
248 }
249
250 $mailOk = $this->send_confirm_mail($user, $token);
251 if (!$mailOk) {
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');
253 }
254
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');
257 }
258
259 public function run() {
260 $run2 = dbx()->get_modul_var('dbx_run2', '', 'parameter');
261 if ($run2 === 'confirm') {
262 return $this->confirm();
263 }
264 if ($run2 === 'resend_confirm') {
265 return $this->resend_confirm();
266 }
267
268 if (dbx()->user()) {
269 return dbx()->redirect('?dbx_modul=dbxUser&dbx_run1=user&dbx_run2=edit_profil', 1);
270 }
271
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(
277 'dbx_title',
278 $oForm->get_fd_message('page_title')
279 );
280 $oForm->add_module_bar(
281 $oForm->get_fd_message('bar_title'),
282 'bi-person-plus',
283 $oForm->get_fd_message('bar_subtitle')
284 );
285 // Den von init() erzeugten dbxForm-Security-Wert erhalten.
286 $oForm->_data = array_merge($oForm->_data, array(
287 'language' => 'de',
288 ));
289 $oForm->_action = '?dbx_modul=dbxLogin&dbx_run1=register';
290 $oForm->_msg_info = $oForm->format_fd_message(
291 'form_info',
292 array('domain' => $this->current_domain())
293 );
294 $oForm->_msg_error = $oForm->get_fd_message('validation_error');
295 $oForm->add_obj('login_link', 'obj-value', '');
296
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');
303
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');
310
311 if ($pass1 !== $pass2) {
312 $oForm->add_fld_error(
313 'password2',
314 $oForm->get_fd_message('password_mismatch')
315 );
316 $oForm->_msg_error = $oForm->get_fd_message(
317 'password_mismatch'
318 );
319 } elseif ($this->user_exists($uname, $email) > 0) {
320 $oForm->add_fld_error(
321 'uname',
322 $oForm->get_fd_message('user_exists')
323 );
324 $oForm->_msg_error = $oForm->get_fd_message('user_exists');
325 } else {
326 $this->ensure_pending_group();
327 $db = dbx()->get_system_obj('dbxDB');
328 $token = $this->new_token();
329 $values = array(
330 'uname' => $uname,
331 'name' => $oForm->get_post('name', '', 'words|max=60'),
332 'email' => $email,
333 'pass' => password_hash($pass1, PASSWORD_DEFAULT),
334 'roles' => $this->pendingRole,
335 'status' => 1,
336 'is_confirm' => 0,
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),
340 );
341
342 $id = ($db->insert($this->ddUser, $values, 0, 1, 1, 1) === 1) ? $db->get_insert_id() : 0;
343 if ($id > 0) {
344 $values['id'] = $id;
345 $mail_ok = $this->send_confirm_mail($values, $token);
346 dbx()->sys_msg('login', 'register', $id, 'new user registered', $uname);
347 if ($mail_ok) {
348 $oForm->_msg_success = $oForm->get_fd_message(
349 'register_success'
350 );
351 } else {
352 $oForm->_msg_error = $oForm->get_fd_message(
353 'confirm_mail_error'
354 );
355 }
356 $oForm->add_obj('login_link', 'dbxLogin|register-login-button');
357 } else {
358 $oForm->_msg_error = $oForm->get_fd_message(
359 'register_error'
360 );
361 }
362 }
363 } else {
364 $oForm->_msg_error = $oForm->get_fd_message(
365 'validation_error'
366 );
367 }
368 }
369
370 return $oForm->run();
371 }
372}
373?>
user($key='id')
Liest einen Wert des aktuellen Benutzers.
Definition dbxApi.php:1305
check_action_token(string $scope='global', string $token='')
Prueft ein sessiongebundenes Aktions-Token.
Definition dbxApi.php:1206
get_base_url()
Liefert die Basis-URL des aktuellen Requests.
Definition dbxApi.php:1488
$_SERVER['REQUEST_METHOD']
if($web->content_permalink_redirect_target() !=='') $tpl
DBX schema administration.