dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
admin/include/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(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 $texts = new \dbxForm();
41 $texts->init('dbxUser_admin_avatar_texts');
42 $texts->_fd = 'dbxUser_admin|user-admin';
43 $texts->load_fd_messages();
44 $texts->set_form_help_enabled(false);
45 $rid = (int) $rid;
46 if ($rid <= 0) {
47 $rid = (int) dbx()->get_request_var('rid', 0, 'int');
48 }
49 $db = dbx()->get_system_obj('dbxDB');
50
51 $data = $rid ? $db->select1($this->ddUser, $rid, array('id', 'avatar')) : array();
52 if (!is_array($data)) {
53 $data = array();
54 }
55
56 $uid = (int)($data['id'] ?? 0);
57 $avatar = $this->avatar_file($data['avatar'] ?? '');
58
59 $oForm = new \dbxForm();
60 $oForm->init('dbxUser_admin_avatar_' . (int) $rid, 'form-avatar');
61 $oForm->_fd = 'dbxUser_admin|user-admin';
62 $oForm->load_fd_messages();
63 $oForm->set_workflow_scope('admin-avatar-' . (int) $rid);
64 $oForm->_data = $data;
65 $oForm->_dd = $this->ddUser;
66 $oForm->_rid = (int) $rid;
67 $oForm->_action = '?dbx_modul=dbxUser_admin&dbx_run1=user&dbx_run2=edit_avatar&rid=' . (int) $rid;
68 $oForm->_msg_info = '';
69 $oForm->set_state_value('rid', (int) $rid);
70 $oForm->add_rep('rid', (int) $rid);
71 $oForm->add_rep('can_upload', ($rid > 0 && $uid > 0) ? 1 : 0);
72 $oForm->add_rep('cannot_upload', ($rid > 0 && $uid > 0) ? 0 : 1);
73
74 if ($oForm->submit()) {
75 if ($rid <= 0 || $uid <= 0) {
76 $oForm->_msg_error = $texts->get_fd_message('avatar_after_save');
77 } elseif (!$this->has_upload_file('upload_file')) {
78 $oForm->_msg_error = $texts->get_fd_message('avatar_select_file');
79 } else {
80 $oUpload = dbx()->get_system_obj('dbxUpload');
81 $oUpload->upload($_FILES['upload_file']);
82 $oUpload->allowed = array('image/jpeg', 'image/jpg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', 'image/x-webp', 'image/gif');
83 $oUpload->file_max_size = 2 * 1024 * 1024;
84 $oUpload->file_overwrite = true;
85 $oUpload->file_new_name_body = 'avatar-' . $uid;
86 $oUpload->image_resize = true;
87 $oUpload->image_ratio_crop = true;
88 $oUpload->image_x = 640;
89 $oUpload->image_y = 640;
90 $oUpload->process($this->avatar_dir());
91
92 if ($oUpload->processed) {
93 $ok = $db->update($this->ddUser, array('avatar' => $oUpload->file_dst_name), $rid);
94 if ($ok) {
95 $avatar = $oUpload->file_dst_name;
96 $oForm->_msg_success = $texts->get_fd_message('avatar_saved');
97 } else {
98 $oForm->_msg_error = $texts->get_fd_message('avatar_save_error');
99 }
100 } else {
101 $oForm->_msg_error = $texts->format_fd_message('upload_error', array('error' => $oUpload->error));
102 }
103
104 $oUpload->clean();
105 }
106 }
107
108 if ($rid <= 0 || $uid <= 0) {
109 $oForm->_msg_info = $texts->get_fd_message('avatar_after_save');
110 }
111
112 $oForm->add_obj('avatar_preview', 'obj-value', '<img src="' . $this->avatar_url($avatar) . '?' . time() . '" alt="Avatar" class="dbx-avatar-img">');
113 $oForm->add_rep('avatar_upload_running_json', json_encode($texts->get_fd_message('upload_running'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
114 $oForm->add_rep('avatar_upload_wait_json', json_encode($texts->get_fd_message('upload_wait'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
115 $oForm->add_rep('avatar_upload_ready_json', json_encode($texts->get_fd_message('upload_ready'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
116 $oForm->add_rep('avatar_upload_start_error_json', json_encode($texts->get_fd_message('upload_start_error'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
117 $oForm->add_rep('avatar_select_first_json', json_encode($texts->get_fd_message('avatar_select_first'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
118 $oForm->add_js_code(<<<'JS'
119(function () {
120 var drop = document.getElementById('admin_avatar_uploader_{i}');
121 var form = document.getElementById('dbx_form_{i}');
122 if (!drop || !form || drop.dataset.ready === '1') return;
123 drop.dataset.ready = '1';
124
125 var input = form.querySelector('input[type="file"][name="upload_file"]');
126 var title = drop.querySelector('.dbx-avatar-drop-title');
127 var meta = drop.querySelector('.dbx-avatar-drop-meta');
128 var defaultTitle = title ? title.textContent : '';
129 var defaultMeta = meta ? meta.textContent : '';
130 var busy = false;
131
132 function setBusy(active) {
133 busy = active;
134 drop.classList.toggle('is-active', active);
135 drop.classList.toggle('is-uploading', active);
136 drop.setAttribute('aria-busy', active ? 'true' : 'false');
137 form.querySelectorAll('.dbx-form-save, button[type="submit"], input[type="submit"]').forEach(function (button) {
138 button.disabled = active;
139 });
140 if (title) title.textContent = active ? {avatar_upload_running_json} : (drop.dataset.fileName || defaultTitle);
141 if (meta && active) meta.textContent = {avatar_upload_wait_json};
142 }
143
144 function setMessage(message) {
145 if (meta && message) meta.textContent = message;
146 }
147
148 function setSelected(file) {
149 if (!file) return;
150 drop.dataset.fileName = file.name || defaultTitle;
151 drop.classList.add('has-file');
152 if (title) title.textContent = file.name || defaultTitle;
153 if (meta) meta.textContent = {avatar_upload_ready_json};
154 }
155
156 function syncInput(file) {
157 if (!input || !file) return false;
158 try {
159 var transfer = new DataTransfer();
160 transfer.items.add(file);
161 input.files = transfer.files;
162 return input.files && input.files.length === 1;
163 } catch (e) {
164 return false;
165 }
166 }
167
168 function refresh(html) {
169 var targetId = drop.getAttribute('data-dbx_target');
170 var target = targetId ? document.getElementById(targetId) : null;
171 if (!target) {
172 if (window.dbx && dbx.utilities && dbx.utilities.leaveGuard) {
173 dbx.utilities.leaveGuard.allowOnce();
174 }
175 location.reload();
176 return;
177 }
178 target.innerHTML = html;
179 if (window.dbx && typeof window.dbx.scan === 'function') {
180 window.dbx.scan(target);
181 }
182 }
183
184 function requestUrl(raw) {
185 try {
186 var url = new URL(raw || form.getAttribute('action') || form.action || window.location.href, window.location.href);
187 if (
188 (url.protocol === 'http:' || url.protocol === 'https:') &&
189 url.hostname === window.location.hostname &&
190 url.port === window.location.port &&
191 url.protocol !== window.location.protocol
192 ) {
193 url.protocol = window.location.protocol;
194 }
195 return url.href;
196 } catch (e) {
197 return raw || form.getAttribute('action') || form.action;
198 }
199 }
200
201 function directUpload(file) {
202 if (typeof window.fetch !== 'function') {
203 return Promise.reject(new Error('fetch_unavailable'));
204 }
205
206 var data = new FormData(form);
207 data.set('upload_file', file);
208 return fetch(requestUrl(drop.getAttribute('data-dbx_get') || form.getAttribute('action') || form.action), {
209 method: 'POST',
210 body: data,
211 credentials: 'same-origin'
212 }).then(function (response) {
213 if (!response.ok) throw new Error('HTTP ' + response.status);
214 return response.text();
215 }).then(refresh);
216 }
217
218 function nativeSubmit() {
219 if (typeof HTMLFormElement !== 'undefined' && HTMLFormElement.prototype.submit) {
220 HTMLFormElement.prototype.submit.call(form);
221 } else {
222 form.submit();
223 }
224 }
225
226 function send(file, fileAlreadyOnInput) {
227 if (!file || busy) return;
228
229 var inputReady = fileAlreadyOnInput || syncInput(file);
230 setSelected(file);
231 setBusy(true);
232
233 directUpload(file)
234 .catch(function () {
235 if (inputReady) {
236 nativeSubmit();
237 } else {
238 setMessage({avatar_upload_start_error_json});
239 }
240 })
241 .finally(function () { setBusy(false); });
242 }
243
244 function openPicker() {
245 if (!input || busy) return;
246 input.value = '';
247 if (title) title.textContent = defaultTitle;
248 if (meta) meta.textContent = defaultMeta;
249 drop.classList.remove('has-file');
250 input.click();
251 }
252
253 drop.addEventListener('click', openPicker);
254 drop.addEventListener('keydown', function (event) {
255 if (event.key === 'Enter' || event.key === ' ') {
256 event.preventDefault();
257 openPicker();
258 }
259 });
260
261 if (input) {
262 input.addEventListener('change', function () {
263 send(input.files && input.files[0], true);
264 });
265 }
266
267 form.addEventListener('submit', function (event) {
268 if (busy) {
269 event.preventDefault();
270 event.stopPropagation();
271 return;
272 }
273
274 var file = input && input.files && input.files[0];
275 if (!file) {
276 event.preventDefault();
277 event.stopPropagation();
278 setMessage({avatar_select_first_json});
279 drop.focus();
280 return;
281 }
282
283 event.preventDefault();
284 event.stopPropagation();
285 send(file, true);
286 });
287
288 ['dragenter', 'dragover'].forEach(function (eventName) {
289 drop.addEventListener(eventName, function (event) {
290 event.preventDefault();
291 setBusy(true);
292 });
293 });
294
295 ['dragleave', 'drop'].forEach(function (eventName) {
296 drop.addEventListener(eventName, function (event) {
297 event.preventDefault();
298 setBusy(false);
299 });
300 });
301
302 drop.addEventListener('drop', function (event) {
303 event.preventDefault();
304 event.stopPropagation();
305 var files = event.dataTransfer && event.dataTransfer.files;
306 send(files && files[0], false);
307 });
308})();
309JS);
310
311 return $oForm->run();
312 }
313}
314
315?>
dbx()
Liefert die zentrale dbXapp-API als Singleton.
Definition dbxApi.php:2805
get_base_dir(int $cutData=0)
Liefert das Basisverzeichnis der Installation.
Definition dbxApi.php:1507
html($html)
Bereitet HTML fuer die Ausgabe auf.
Definition dbxApi.php:2296
DBX schema administration.