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;
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() . 'files/user/avatar/');
11 if (!is_dir($dir)) {
12 @mkdir($dir, 0777, true);
13 }
14 return $dir;
15 }
16
17 private function legacy_avatar_dir() {
18 return dbx_os_path_file(dbx_get_base_dir() . 'dbx/modules/dbxUser/img/avatar/');
19 }
20
21 private function avatar_file($file) {
22 $file = trim((string)$file);
23 if ($file === '' || !preg_match('/^avatar-[0-9]+\.(?:webp|png|jpe?g|gif)$/i', $file)) {
24 return 'avatar-0.png';
25 }
26 if (file_exists($this->avatar_dir() . $file)) {
27 return $file;
28 }
29 if (file_exists($this->legacy_avatar_dir() . $file)) {
30 return $file;
31 }
32 return 'avatar-0.png';
33 }
34
35 private function avatar_url($file) {
36 $file = $this->avatar_file($file);
37 if (file_exists($this->avatar_dir() . $file)) {
38 return dbx()->get_base_url() . 'files/user/avatar/' . rawurlencode($file);
39 }
40 return dbx()->get_base_url() . 'dbx/modules/dbxUser/img/avatar/' . rawurlencode($file);
41 }
42
43 private function remove_old_avatar_files(int $rid, string $keep): void {
44 foreach (glob($this->avatar_dir() . 'avatar-' . $rid . '.*') ?: array() as $path) {
45 if (basename($path) !== $keep && is_file($path)) {
46 @unlink($path);
47 }
48 }
49 }
50
51 private function has_upload_file($key) {
52 return isset($_FILES[$key])
53 && is_array($_FILES[$key])
54 && (int)($_FILES[$key]['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE
55 && trim((string)($_FILES[$key]['name'] ?? '')) !== '';
56 }
57
58 public function save_upload(int $rid, $db, array &$data = array(), string &$error = ''): bool {
59 $error = '';
60 if (!$this->has_upload_file('upload_file')) {
61 return false;
62 }
63
64 $oUpload = dbx()->get_system_obj('dbxUpload');
65 $oUpload->upload($_FILES['upload_file']);
66 $oUpload->allowed = array('image/jpeg', 'image/jpg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', 'image/x-webp', 'image/gif');
67 $oUpload->file_max_size = 2 * 1024 * 1024;
68 $oUpload->file_overwrite = true;
69 $oUpload->file_new_name_body = 'avatar-' . $rid;
70 $oUpload->file_new_name_ext = 'webp';
71 $oUpload->image_convert = 'webp';
72 $oUpload->webp_quality = 86;
73 $oUpload->image_resize = true;
74 $oUpload->image_ratio_crop = true;
75 $oUpload->image_x = 640;
76 $oUpload->image_y = 640;
77 $oUpload->process($this->avatar_dir());
78
79 if ($oUpload->processed) {
80 $ok = $db->update($this->ddUser, array('avatar' => $oUpload->file_dst_name), $rid);
81 if ($ok) {
82 $data['avatar'] = $oUpload->file_dst_name;
83 $this->remove_old_avatar_files($rid, $oUpload->file_dst_name);
84 $oUpload->clean();
85 return true;
86 }
87 $error = 'Profilbild konnte nicht gespeichert werden.';
88 } else {
89 $error = 'Upload fehlgeschlagen: ' . $oUpload->error;
90 }
91
92 $oUpload->clean();
93 return false;
94 }
95
96 public function run() {
97 $uid = (int)dbx()->user();
98
99 $rid = $uid;
100
101 $db = dbx()->get_system_obj('dbxDB');
102 $data = $db->select1($this->ddUser, $rid);
103 if (!is_array($data)) {
104 return '<div class="alert alert-warning">Benutzer nicht gefunden.</div>';
105 }
106
107 $oForm = new \dbxForm();
108 $oForm->init('dbxUser_avatar', 'form-avatar');
109 $oForm->set_workflow_scope('self-' . $uid);
110 $oForm->_data = $data;
111 $oForm->_dd = $this->ddUser;
112 $oForm->_action = '?dbx_modul=dbxUser&dbx_run1=user&dbx_run2=edit_avatar';
113 $oForm->_msg_info = '';
114 $oForm->_rid = $uid;
115 $oForm->set_state_value('rid', $uid);
116
117 if ($oForm->submit()) {
118 if (!$this->has_upload_file('upload_file')) {
119 $oForm->_msg_error = 'Bitte waehlen Sie eine Bilddatei aus.';
120 } else {
121 $avatarError = '';
122 $ok = $this->save_upload($rid, $db, $data, $avatarError);
123 $oForm->_msg_success = $ok ? 'Avatar gespeichert.' : '';
124 $oForm->_msg_error = $ok ? '' : $avatarError;
125 }
126 }
127
128 $oForm->add_obj('avatar_preview', 'obj-value', '<img class="dbx-avatar-img" src="' . $this->avatar_url($data['avatar'] ?? '') . '?' . time() . '" alt="Avatar">');
129 $oForm->add_js_code(<<<'JS'
130(function () {
131 var drop = document.getElementById('uploader_{i}');
132 var panel = document.getElementById('dbx_avatar_panel_{i}');
133 if (!drop || !panel || drop.dataset.ready === '1') return;
134 drop.dataset.ready = '1';
135
136 var input = panel.querySelector('input[type="file"][name="upload_file"]');
137 var title = drop.querySelector('.dbx-avatar-drop-title');
138 var meta = drop.querySelector('.dbx-avatar-drop-meta');
139 var defaultTitle = title ? title.textContent : '';
140 var defaultMeta = meta ? meta.textContent : '';
141 var busy = false;
142
143 function setBusy(active) {
144 busy = active;
145 drop.classList.toggle('is-active', active);
146 drop.classList.toggle('is-uploading', active);
147 drop.setAttribute('aria-busy', active ? 'true' : 'false');
148 if (title) title.textContent = active ? 'Upload laeuft...' : (drop.dataset.fileName || defaultTitle);
149 if (meta && active) meta.textContent = 'Datei wurde ausgewaehlt.';
150 }
151
152 function setMessage(message) {
153 if (meta && message) meta.textContent = message;
154 }
155
156 function setSelected(file) {
157 if (!file) return;
158 drop.dataset.fileName = file.name || defaultTitle;
159 drop.classList.add('has-file');
160 if (title) title.textContent = file.name || defaultTitle;
161 if (meta) meta.textContent = 'Bereit zum Hochladen.';
162 }
163
164 function syncInput(file) {
165 if (!input || !file) return false;
166 try {
167 var transfer = new DataTransfer();
168 transfer.items.add(file);
169 input.files = transfer.files;
170 return input.files && input.files.length === 1;
171 } catch (e) {
172 return false;
173 }
174 }
175
176 function send(file, fileAlreadyOnInput) {
177 if (!file || busy) return;
178
179 fileAlreadyOnInput || syncInput(file);
180 setSelected(file);
181 setMessage('Profil speichern, um das Bild zu uebernehmen.');
182 }
183
184 function openPicker() {
185 if (!input || busy) return;
186 input.value = '';
187 if (title) title.textContent = defaultTitle;
188 if (meta) meta.textContent = defaultMeta;
189 drop.classList.remove('has-file');
190 input.click();
191 }
192
193 drop.addEventListener('click', function () {
194 if (busy) return false;
195 input.value = '';
196 if (title) title.textContent = defaultTitle;
197 if (meta) meta.textContent = defaultMeta;
198 drop.classList.remove('has-file');
199 });
200 drop.addEventListener('keydown', function (event) {
201 if (event.key === 'Enter' || event.key === ' ') {
202 event.preventDefault();
203 openPicker();
204 }
205 });
206
207 if (input) {
208 input.addEventListener('change', function () {
209 send(input.files && input.files[0], true);
210 });
211 }
212
213 var outerForm = panel.closest('form');
214 if (outerForm) {
215 outerForm.addEventListener('submit', function () {
216 if (input && input.files && input.files[0]) setBusy(true);
217 });
218 }
219
220 ['dragenter', 'dragover'].forEach(function (eventName) {
221 drop.addEventListener(eventName, function (event) {
222 event.preventDefault();
223 setBusy(true);
224 });
225 });
226
227 ['dragleave', 'drop'].forEach(function (eventName) {
228 drop.addEventListener(eventName, function (event) {
229 event.preventDefault();
230 setBusy(false);
231 });
232 });
233
234 drop.addEventListener('drop', function (event) {
235 event.preventDefault();
236 event.stopPropagation();
237 var files = event.dataTransfer && event.dataTransfer.files;
238 send(files && files[0], false);
239 });
240})();
241JS);
242
243 return $oForm->run();
244 }
245}
246?>
save_upload(int $rid, $db, array &$data=array(), string &$error='')
dbx_os_path_file($path_file)
Definition index.php:164
dbx_get_base_dir($cut_Data=0)
Definition index.php:157
DBX schema administration.