dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
dbxUser_avatar.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\dbxUser_admin;
3dbx()->use_system_class('dbxForm');
4
6
7 private string $ddUser = 'dbxUser';
8
9 private function avatar_dir() {
10 $dir = dbx_os_path_file(dbx_get_base_dir() . 'dbx/modules/dbxUser/img/avatar/');
11 if (!is_dir($dir)) {
12 @mkdir($dir, 0777, true);
13 }
14 return $dir;
15 }
16
17 private function avatar_file($file) {
18 $file = trim((string) $file);
19 if ($file === '' || !preg_match('/^[A-Za-z0-9_.-]+\.(png|jpg|jpeg|webp|gif)$/i', $file)) {
20 return 'avatar-0.png';
21 }
22
23 $path = $this->avatar_dir() . $file;
24 return is_file($path) ? $file : 'avatar-0.png';
25 }
26
27 private function avatar_url($file) {
28 $file = $this->avatar_file($file);
29 return dbx()->get_base_url() . 'dbx/modules/dbxUser/img/avatar/' . rawurlencode($file);
30 }
31
32 private function has_upload_file($key) {
33 return isset($_FILES[$key])
34 && is_array($_FILES[$key])
35 && (int)($_FILES[$key]['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE
36 && trim((string)($_FILES[$key]['name'] ?? '')) !== '';
37 }
38
39 public function run($rid = 0) {
40 $rid = (int) $rid;
41 if ($rid <= 0) {
42 $rid = (int) dbx()->get_request_var('rid', 0, 'int');
43 }
44 $db = dbx()->get_system_obj('dbxDB');
45
46 $data = $rid ? $db->select1($this->ddUser, $rid, array('id', 'avatar')) : array();
47 if (!is_array($data)) {
48 $data = array();
49 }
50
51 $uid = (int)($data['id'] ?? 0);
52 $avatar = $this->avatar_file($data['avatar'] ?? '');
53
54 $oForm = new \dbxForm();
55 $oForm->init('dbxUser_admin_avatar_' . (int) $rid, 'form-avatar');
56 $oForm->set_workflow_scope('admin-avatar-' . (int) $rid);
57 $oForm->_data = $data;
58 $oForm->_dd = $this->ddUser;
59 $oForm->_rid = (int) $rid;
60 $oForm->_action = '?dbx_modul=dbxUser_admin&dbx_run1=user&dbx_run2=edit_avatar&rid=' . (int) $rid;
61 $oForm->_msg_info = '';
62 $oForm->set_state_value('rid', (int) $rid);
63 $oForm->add_rep('rid', (int) $rid);
64 $oForm->add_rep('can_upload', ($rid > 0 && $uid > 0) ? 1 : 0);
65 $oForm->add_rep('cannot_upload', ($rid > 0 && $uid > 0) ? 0 : 1);
66
67 if ($oForm->submit()) {
68 if ($rid <= 0 || $uid <= 0) {
69 $oForm->_msg_error = 'Ein Avatar kann nach dem ersten Speichern des Benutzers hochgeladen werden.';
70 } elseif (!$this->has_upload_file('upload_file')) {
71 $oForm->_msg_error = 'Bitte waehlen Sie eine Bilddatei aus.';
72 } else {
73 $oUpload = dbx()->get_system_obj('dbxUpload');
74 $oUpload->upload($_FILES['upload_file']);
75 $oUpload->allowed = array('image/jpeg', 'image/jpg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', 'image/x-webp', 'image/gif');
76 $oUpload->file_max_size = 2 * 1024 * 1024;
77 $oUpload->file_overwrite = true;
78 $oUpload->file_new_name_body = 'avatar-' . $uid;
79 $oUpload->image_resize = true;
80 $oUpload->image_ratio_crop = true;
81 $oUpload->image_x = 640;
82 $oUpload->image_y = 640;
83 $oUpload->process($this->avatar_dir());
84
85 if ($oUpload->processed) {
86 $ok = $db->update($this->ddUser, array('avatar' => $oUpload->file_dst_name), $rid);
87 if ($ok) {
88 $avatar = $oUpload->file_dst_name;
89 $oForm->_msg_success = 'Profilbild gespeichert.';
90 } else {
91 $oForm->_msg_error = 'Profilbild konnte nicht gespeichert werden.';
92 }
93 } else {
94 $oForm->_msg_error = 'Upload fehlgeschlagen: ' . $oUpload->error;
95 }
96
97 $oUpload->clean();
98 }
99 }
100
101 if ($rid <= 0 || $uid <= 0) {
102 $oForm->_msg_info = 'Ein Avatar kann nach dem ersten Speichern des Benutzers hochgeladen werden.';
103 }
104
105 $oForm->add_obj('avatar_preview', 'obj-value', '<img src="' . $this->avatar_url($avatar) . '?' . time() . '" alt="Avatar" class="dbx-avatar-img">');
106 $oForm->add_js_code(<<<'JS'
107(function () {
108 var drop = document.getElementById('admin_avatar_uploader_{i}');
109 var form = document.getElementById('dbx_form_{i}');
110 if (!drop || !form || drop.dataset.ready === '1') return;
111 drop.dataset.ready = '1';
112
113 var input = form.querySelector('input[type="file"][name="upload_file"]');
114 var title = drop.querySelector('.dbx-avatar-drop-title');
115 var meta = drop.querySelector('.dbx-avatar-drop-meta');
116 var defaultTitle = title ? title.textContent : '';
117 var defaultMeta = meta ? meta.textContent : '';
118 var busy = false;
119
120 function setBusy(active) {
121 busy = active;
122 drop.classList.toggle('is-active', active);
123 drop.classList.toggle('is-uploading', active);
124 drop.setAttribute('aria-busy', active ? 'true' : 'false');
125 form.querySelectorAll('.dbx-form-save, button[type="submit"], input[type="submit"]').forEach(function (button) {
126 button.disabled = active;
127 });
128 if (title) title.textContent = active ? 'Upload laeuft...' : (drop.dataset.fileName || defaultTitle);
129 if (meta && active) meta.textContent = 'Bitte warten, das Bild wird gespeichert.';
130 }
131
132 function setMessage(message) {
133 if (meta && message) meta.textContent = message;
134 }
135
136 function setSelected(file) {
137 if (!file) return;
138 drop.dataset.fileName = file.name || defaultTitle;
139 drop.classList.add('has-file');
140 if (title) title.textContent = file.name || defaultTitle;
141 if (meta) meta.textContent = 'Bereit zum Hochladen.';
142 }
143
144 function syncInput(file) {
145 if (!input || !file) return false;
146 try {
147 var transfer = new DataTransfer();
148 transfer.items.add(file);
149 input.files = transfer.files;
150 return input.files && input.files.length === 1;
151 } catch (e) {
152 return false;
153 }
154 }
155
156 function refresh(html) {
157 var targetId = drop.getAttribute('data-dbx_target');
158 var target = targetId ? document.getElementById(targetId) : null;
159 if (!target) {
160 location.reload();
161 return;
162 }
163 target.innerHTML = html;
164 if (window.dbx && typeof window.dbx.scan === 'function') {
165 window.dbx.scan(target);
166 }
167 }
168
169 function requestUrl(raw) {
170 try {
171 var url = new URL(raw || form.getAttribute('action') || form.action || window.location.href, window.location.href);
172 if (
173 (url.protocol === 'http:' || url.protocol === 'https:') &&
174 url.hostname === window.location.hostname &&
175 url.port === window.location.port &&
176 url.protocol !== window.location.protocol
177 ) {
178 url.protocol = window.location.protocol;
179 }
180 return url.href;
181 } catch (e) {
182 return raw || form.getAttribute('action') || form.action;
183 }
184 }
185
186 function directUpload(file) {
187 if (typeof window.fetch !== 'function') {
188 return Promise.reject(new Error('fetch_unavailable'));
189 }
190
191 var data = new FormData(form);
192 data.set('upload_file', file);
193 return fetch(requestUrl(drop.getAttribute('data-dbx_get') || form.getAttribute('action') || form.action), {
194 method: 'POST',
195 body: data,
196 credentials: 'same-origin'
197 }).then(function (response) {
198 if (!response.ok) throw new Error('HTTP ' + response.status);
199 return response.text();
200 }).then(refresh);
201 }
202
203 function nativeSubmit() {
204 if (typeof HTMLFormElement !== 'undefined' && HTMLFormElement.prototype.submit) {
205 HTMLFormElement.prototype.submit.call(form);
206 } else {
207 form.submit();
208 }
209 }
210
211 function send(file, fileAlreadyOnInput) {
212 if (!file || busy) return;
213
214 var inputReady = fileAlreadyOnInput || syncInput(file);
215 setSelected(file);
216 setBusy(true);
217
218 directUpload(file)
219 .catch(function () {
220 if (inputReady) {
221 nativeSubmit();
222 } else {
223 setMessage('Upload konnte nicht gestartet werden. Bitte erneut versuchen.');
224 }
225 })
226 .finally(function () { setBusy(false); });
227 }
228
229 function openPicker() {
230 if (!input || busy) return;
231 input.value = '';
232 if (title) title.textContent = defaultTitle;
233 if (meta) meta.textContent = defaultMeta;
234 drop.classList.remove('has-file');
235 input.click();
236 }
237
238 drop.addEventListener('click', openPicker);
239 drop.addEventListener('keydown', function (event) {
240 if (event.key === 'Enter' || event.key === ' ') {
241 event.preventDefault();
242 openPicker();
243 }
244 });
245
246 if (input) {
247 input.addEventListener('change', function () {
248 send(input.files && input.files[0], true);
249 });
250 }
251
252 form.addEventListener('submit', function (event) {
253 if (busy) {
254 event.preventDefault();
255 event.stopPropagation();
256 return;
257 }
258
259 var file = input && input.files && input.files[0];
260 if (!file) {
261 event.preventDefault();
262 event.stopPropagation();
263 setMessage('Bitte waehlen Sie zuerst eine Bilddatei aus.');
264 drop.focus();
265 return;
266 }
267
268 event.preventDefault();
269 event.stopPropagation();
270 send(file, true);
271 });
272
273 ['dragenter', 'dragover'].forEach(function (eventName) {
274 drop.addEventListener(eventName, function (event) {
275 event.preventDefault();
276 setBusy(true);
277 });
278 });
279
280 ['dragleave', 'drop'].forEach(function (eventName) {
281 drop.addEventListener(eventName, function (event) {
282 event.preventDefault();
283 setBusy(false);
284 });
285 });
286
287 drop.addEventListener('drop', function (event) {
288 event.preventDefault();
289 event.stopPropagation();
290 var files = event.dataTransfer && event.dataTransfer.files;
291 send(files && files[0], false);
292 });
293})();
294JS);
295
296 return $oForm->run();
297 }
298}
299
300?>
dbx_os_path_file($path_file)
Definition index.php:164
dbx_get_base_dir($cut_Data=0)
Definition index.php:157
DBX schema administration.