dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
include/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(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(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, $texts, 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 = $texts->get_fd_message('avatar_save_error');
88 } else {
89 $error = $texts->format_fd_message(
90 'upload_error',
91 array('error' => $oUpload->error)
92 );
93 }
94
95 $oUpload->clean();
96 return false;
97 }
98
99 public function run() {
100 $uid = (int)dbx()->user();
101
102 $rid = $uid;
103
104 $db = dbx()->get_system_obj('dbxDB');
105 $data = $db->select1($this->ddUser, $rid);
106 $oForm = new \dbxForm();
107 $oForm->init('dbxUser_avatar', 'form-avatar');
108 $oForm->_fd = 'dbxUser|user-profile';
109 $oForm->load_fd_messages();
110 if (!is_array($data)) {
111 return '<div class="alert alert-warning">'
112 . $oForm->get_fd_message('user_not_found')
113 . '</div>';
114 }
115 $oForm->set_workflow_scope('self-' . $uid);
116 $oForm->_data = $data;
117 $oForm->_dd = $this->ddUser;
118 $oForm->_action = '?dbx_modul=dbxUser&dbx_run1=user&dbx_run2=edit_avatar';
119 $oForm->_msg_info = '';
120 $oForm->_rid = $uid;
121 $oForm->set_state_value('rid', $uid);
122
123 if ($oForm->submit()) {
124 if (!$this->has_upload_file('upload_file')) {
125 $oForm->_msg_error = $oForm->get_fd_message('avatar_select_file');
126 } else {
127 $avatarError = '';
128 $ok = $this->save_upload($rid, $db, $data, $oForm, $avatarError);
129 $oForm->_msg_success = $ok ? $oForm->get_fd_message('avatar_saved') : '';
130 $oForm->_msg_error = $ok ? '' : $avatarError;
131 }
132 }
133
134 $oForm->add_obj(
135 'avatar_preview',
136 'obj-value',
137 '<img class="dbx-avatar-img" src="'
138 . $this->avatar_url($data['avatar'] ?? '')
139 . '?' . time()
140 . '" alt="' . dbx()->esc($oForm->get_fd_message('avatar_alt')) . '">'
141 );
142 $jsMessages = json_encode(
143 array(
144 'upload_running' => $oForm->get_fd_message('upload_running'),
145 'file_selected' => $oForm->get_fd_message('upload_file_selected'),
146 'upload_ready' => $oForm->get_fd_message('upload_ready'),
147 'save_profile' => $oForm->get_fd_message('upload_save_profile'),
148 ),
149 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
150 );
151 $oForm->add_js_code(str_replace('{dbx_avatar_messages}', $jsMessages ?: '{}', <<<'JS'
152(function () {
153 var messages = {dbx_avatar_messages};
154 var drop = document.getElementById('uploader_{i}');
155 var panel = document.getElementById('dbx_avatar_panel_{i}');
156 if (!drop || !panel || drop.dataset.ready === '1') return;
157 drop.dataset.ready = '1';
158
159 var input = panel.querySelector('input[type="file"][name="upload_file"]');
160 var title = drop.querySelector('.dbx-avatar-drop-title');
161 var meta = drop.querySelector('.dbx-avatar-drop-meta');
162 var defaultTitle = title ? title.textContent : '';
163 var defaultMeta = meta ? meta.textContent : '';
164 var busy = false;
165
166 function setBusy(active) {
167 busy = active;
168 drop.classList.toggle('is-active', active);
169 drop.classList.toggle('is-uploading', active);
170 drop.setAttribute('aria-busy', active ? 'true' : 'false');
171 if (title) title.textContent = active ? messages.upload_running : (drop.dataset.fileName || defaultTitle);
172 if (meta && active) meta.textContent = messages.file_selected;
173 }
174
175 function setMessage(message) {
176 if (meta && message) meta.textContent = message;
177 }
178
179 function setSelected(file) {
180 if (!file) return;
181 drop.dataset.fileName = file.name || defaultTitle;
182 drop.classList.add('has-file');
183 if (title) title.textContent = file.name || defaultTitle;
184 if (meta) meta.textContent = messages.upload_ready;
185 }
186
187 function syncInput(file) {
188 if (!input || !file) return false;
189 try {
190 var transfer = new DataTransfer();
191 transfer.items.add(file);
192 input.files = transfer.files;
193 return input.files && input.files.length === 1;
194 } catch (e) {
195 return false;
196 }
197 }
198
199 function send(file, fileAlreadyOnInput) {
200 if (!file || busy) return;
201
202 fileAlreadyOnInput || syncInput(file);
203 setSelected(file);
204 setMessage(messages.save_profile);
205 }
206
207 function openPicker() {
208 if (!input || busy) return;
209 input.value = '';
210 if (title) title.textContent = defaultTitle;
211 if (meta) meta.textContent = defaultMeta;
212 drop.classList.remove('has-file');
213 input.click();
214 }
215
216 drop.addEventListener('click', function () {
217 if (busy) return false;
218 input.value = '';
219 if (title) title.textContent = defaultTitle;
220 if (meta) meta.textContent = defaultMeta;
221 drop.classList.remove('has-file');
222 });
223 drop.addEventListener('keydown', function (event) {
224 if (event.key === 'Enter' || event.key === ' ') {
225 event.preventDefault();
226 openPicker();
227 }
228 });
229
230 if (input) {
231 input.addEventListener('change', function () {
232 send(input.files && input.files[0], true);
233 });
234 }
235
236 var outerForm = panel.closest('form');
237 if (outerForm) {
238 outerForm.addEventListener('submit', function () {
239 if (input && input.files && input.files[0]) setBusy(true);
240 });
241 }
242
243 ['dragenter', 'dragover'].forEach(function (eventName) {
244 drop.addEventListener(eventName, function (event) {
245 event.preventDefault();
246 setBusy(true);
247 });
248 });
249
250 ['dragleave', 'drop'].forEach(function (eventName) {
251 drop.addEventListener(eventName, function (event) {
252 event.preventDefault();
253 setBusy(false);
254 });
255 });
256
257 drop.addEventListener('drop', function (event) {
258 event.preventDefault();
259 event.stopPropagation();
260 var files = event.dataTransfer && event.dataTransfer.files;
261 send(files && files[0], false);
262 });
263})();
264JS));
265
266 return $oForm->run();
267 }
268}
269?>
save_upload(int $rid, $db, array &$data, $texts, string &$error)
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
esc($value)
Escaped einen Wert fuer HTML-Text und HTML-Attribute.
Definition dbxApi.php:2310
DBX schema administration.