dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
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 $postedToken = (string)($_POST['dbx_token'] ?? '');
196 if (!dbx()->check_action_token('dbxLogin.resend_confirm', $postedToken)) {
197 dbx()->sys_msg('security', 'register', '', 'invalid resend confirm token', $_SERVER['REMOTE_ADDR'] ?? '');
198 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');
199 }
200
201 $uid = (int)dbx()->get_session_var('pending_confirm_uid', 0, 'confirm', 'dbxLogin');
202 if ($uid <= 0) {
203 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');
204 }
205
206 $currentUid = (int)dbx()->user();
207 if ($currentUid > 0 && $currentUid !== $uid) {
208 dbx()->delete_session_var('pending_confirm_uid', 'confirm', 'dbxLogin');
209 dbx()->sys_msg('security', 'register', $uid, 'resend confirm user mismatch', 'current=' . $currentUid . ' ip=' . ($_SERVER['REMOTE_ADDR'] ?? ''));
210 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');
211 }
212
213 $db = dbx()->get_system_obj('dbxDB');
214 $user = $db->select1($this->ddUser, $uid, '*', 0);
215 if (!is_array($user) || empty($user['id'])) {
216 dbx()->delete_session_var('pending_confirm_uid', 'confirm', 'dbxLogin');
217 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');
218 }
219
220 if ((int)($user['is_confirm'] ?? 0) === 1) {
221 dbx()->delete_session_var('pending_confirm_uid', 'confirm', 'dbxLogin');
222 $name = (string)($user['name'] ?: $user['uname'] ?? '');
223 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');
224 }
225
226 if (trim((string)($user['email'] ?? '')) === '') {
227 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');
228 }
229
230 $token = $this->new_token();
231 $settings = $this->decode_settings($user['settings'] ?? '');
232 $ok = $db->update($this->ddUser, array(
233 'settings' => $this->settings_with_token($settings, $token),
234 ), $uid, 0, 1, 1, 1);
235
236 if ($ok <= 0) {
237 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');
238 }
239
240 $mailOk = $this->send_confirm_mail($user, $token);
241 if (!$mailOk) {
242 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');
243 }
244
245 dbx()->sys_msg('info', 'register', $uid, 'confirm mail resent', (string)($user['email'] ?? ''));
246 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');
247 }
248
249 public function run() {
250 $run2 = dbx()->get_modul_var('dbx_run2', '', 'parameter');
251 if ($run2 === 'confirm') {
252 return $this->confirm();
253 }
254 if ($run2 === 'resend_confirm') {
255 return $this->resend_confirm();
256 }
257
258 if (dbx()->user()) {
259 return dbx()->redirect('?dbx_modul=dbxUser&dbx_run1=user&dbx_run2=edit_profil', 1);
260 }
261
262 dbx()->set_system_var('dbx_title', 'Registrierung');
263
264 $oForm = dbx()->get_system_obj('dbxForm');
265 $oForm->init('form-register');
266 $oForm->_fd = 'dbxLogin|register';
267 $oForm->_data = array(
268 'language' => 'de',
269 );
270 $oForm->_action = '?dbx_modul=dbxLogin&dbx_run1=register';
271 $oForm->_msg_info = 'Bei ' . $this->current_domain() . ' anmelden.';
272 $oForm->add_obj('login_link', 'obj-value', '');
273
274 $oForm->add_fld('uname');
275 $oForm->add_fld('name');
276 $oForm->add_fld('email');
277 $oForm->add_fld('password');
278 $oForm->add_fld('password2');
279 $oForm->add_fld('language');
280
281 if ($oForm->submit()) {
282 if (!$oForm->errors()) {
283 $uname = $oForm->get_post('uname', '', 'parameter|max=60');
284 $email = $oForm->get_post('email', '', 'email|max=60');
285 $pass1 = $oForm->get_post_data('password', '', 'varchar|max=128');
286 $pass2 = $oForm->get_post_data('password2', '', 'varchar|max=128');
287
288 if ($pass1 !== $pass2) {
289 $oForm->add_fld_error('password2', 'Passwoerter stimmen nicht ueberein.');
290 $oForm->_msg_error = 'Passwoerter stimmen nicht ueberein.';
291 } elseif ($this->user_exists($uname, $email) > 0) {
292 $oForm->add_fld_error('uname', 'Benutzer oder E-Mail existiert bereits.');
293 $oForm->_msg_error = 'Benutzer oder E-Mail existiert bereits.';
294 } else {
295 $this->ensure_pending_group();
296 $db = dbx()->get_system_obj('dbxDB');
297 $token = $this->new_token();
298 $values = array(
299 'uname' => $uname,
300 'name' => $oForm->get_post('name', '', 'words|max=60'),
301 'email' => $email,
302 'pass' => password_hash($pass1, PASSWORD_DEFAULT),
303 'roles' => $this->pendingRole,
304 'status' => 1,
305 'is_confirm' => 0,
306 'language' => $oForm->get_post('language', 'de', 'parameter|min=2|max=3'),
307 'avatar' => 'avatar-0.png',
308 'settings' => $this->settings_with_token(array(), $token),
309 );
310
311 $id = ($db->insert($this->ddUser, $values, 0, 1, 1, 1) === 1) ? $db->get_insert_id() : 0;
312 if ($id > 0) {
313 $values['id'] = $id;
314 $mail_ok = $this->send_confirm_mail($values, $token);
315 dbx()->sys_msg('login', 'register', $id, 'new user registered', $uname);
316 if ($mail_ok) {
317 $oForm->_msg_success = 'Registrierung gespeichert. Bitte bestaetige deine E-Mail-Adresse ueber den Link in der E-Mail.';
318 } else {
319 $oForm->_msg_error = 'Benutzer wurde angelegt, aber die Bestaetigungs-E-Mail konnte nicht gesendet werden.';
320 }
321 $oForm->add_obj('login_link', 'dbxLogin|register-login-button');
322 } else {
323 $oForm->_msg_error = 'Benutzer konnte nicht angelegt werden.';
324 }
325 }
326 } else {
327 $oForm->_msg_error = 'Pruefen sie bitte ihre Eingaben.';
328 }
329 }
330
331 return $oForm->run();
332 }
333}
334?>
DBX schema administration.
$_SERVER['REQUEST_URI']