Subversion Repositories oidplus

Rev

Rev 899 | Rev 1086 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
635 daniel-mar 21
 
22
class OIDplusPagePublicAttachments extends OIDplusPagePluginPublic {
23
 
24
        const DIR_UNLOCK_FILE = 'oidplus_upload.dir';
25
 
26
        private static function checkUploadDir($dir) {
27
                if (!is_dir($dir)) {
28
                        throw new OIDplusException(_L('The attachment directory "%1" is not existing.', $dir));
29
                }
30
 
31
                $realdir = realpath($dir);
32
                if ($realdir === false) {
33
                        throw new OIDplusException(_L('The attachment directory "%1" cannot be resolved (realpath).', $dir));
34
                }
35
 
36
                $unlock_file = $realdir . DIRECTORY_SEPARATOR . self::DIR_UNLOCK_FILE;
37
                if (!file_exists($unlock_file)) {
38
                        throw new OIDplusException(_L('Unlock file "%1" is not existing in attachment directory "%2".', self::DIR_UNLOCK_FILE, $dir));
39
                }
40
 
41
                if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
42
                        // Linux check 1: Check for critical directories
43
                        if (self::isCriticalLinuxDirectory($realdir)) {
44
                                throw new OIDplusException(_L('The attachment directory must not be inside a critical system directory!'));
45
                        }
46
 
47
                        // Linux check 2: Check file owner
48
                        $file_owner_a = fileowner(OIDplus::localpath().'index.php');
49
                        if ($file_owner_a === false) {
50
                                $file_owner_a = -1;
51
                                $file_owner_a_name = '???';
52
                        } else {
720 daniel-mar 53
                                $tmp = function_exists('posix_getpwuid') ? posix_getpwuid($file_owner_a) : false;
635 daniel-mar 54
                                $file_owner_a_name = $tmp !== false ? $tmp['name'] : 'UID '.$file_owner_a;
55
                        }
56
 
57
                        $file_owner_b = fileowner($unlock_file);
58
                        if ($file_owner_b === false) {
59
                                $file_owner_b = -1;
60
                                $file_owner_b_name = '???';
61
                        } else {
720 daniel-mar 62
                                $tmp = function_exists('posix_getpwuid') ? posix_getpwuid($file_owner_b) : false;
635 daniel-mar 63
                                $file_owner_b_name = $tmp !== false ? $tmp['name'] : 'UID '.$file_owner_b;
64
                        }
65
 
66
                        if ($file_owner_a != $file_owner_b) {
67
                                throw new OIDplusException(_L('Owner of unlock file "%1" is wrong. It is "%2", but it should be "%3".', $unlock_file, $file_owner_b_name, $file_owner_a_name));
68
                        }
69
                } else {
70
                        // Windows check 1: Check for critical directories
71
                        if (self::isCriticalWindowsDirectory($realdir)) {
72
                                throw new OIDplusException(_L('The attachment directory must not be inside a critical system directory!'));
73
                        }
74
 
75
                        // Note: We will not query the file owner in Windows systems.
76
                        // It would be possible, however, on Windows systems, the file
77
                        // ownership is rather hidden to the user and the user needs
78
                        // to go into several menus and windows in order to see/change
79
                        // the owner. We don't want to over-complicate it to the Windows admin.
80
                }
81
        }
82
 
83
        private static function isCriticalWindowsDirectory($dir) {
84
                $dir .= '\\';
85
                $windir = isset($_SERVER['SystemRoot']) ? $_SERVER['SystemRoot'].'\\' : 'C:\\Windows\\';
86
                if (stripos($dir,$windir) === 0) return true;
87
                return false;
88
        }
89
 
90
        private static function isCriticalLinuxDirectory($dir) {
91
                if ($dir == '/') return true;
92
                $dir .= '/';
93
                if (strpos($dir,'/bin/') === 0) return true;
94
                if (strpos($dir,'/boot/') === 0) return true;
95
                if (strpos($dir,'/dev/') === 0) return true;
96
                if (strpos($dir,'/etc/') === 0) return true;
97
                if (strpos($dir,'/lib') === 0) return true;
98
                if (strpos($dir,'/opt/') === 0) return true;
99
                if (strpos($dir,'/proc/') === 0) return true;
100
                if (strpos($dir,'/root/') === 0) return true;
101
                if (strpos($dir,'/run/') === 0) return true;
102
                if (strpos($dir,'/sbin/') === 0) return true;
103
                if (strpos($dir,'/sys/') === 0) return true;
104
                if (strpos($dir,'/tmp/') === 0) return true;
105
                if (strpos($dir,'/usr/bin/') === 0) return true;
106
                if (strpos($dir,'/usr/include/') === 0) return true;
107
                if (strpos($dir,'/usr/lib') === 0) return true;
108
                if (strpos($dir,'/usr/sbin/') === 0) return true;
109
                if (strpos($dir,'/usr/src/') === 0) return true;
110
                if (strpos($dir,'/var/cache/') === 0) return true;
111
                if (strpos($dir,'/var/lib') === 0) return true;
112
                if (strpos($dir,'/var/lock/') === 0) return true;
113
                if (strpos($dir,'/var/log/') === 0) return true;
114
                if (strpos($dir,'/var/mail/') === 0) return true;
115
                if (strpos($dir,'/var/opt/') === 0) return true;
116
                if (strpos($dir,'/var/run/') === 0) return true;
117
                if (strpos($dir,'/var/spool/') === 0) return true;
118
                if (strpos($dir,'/var/tmp/') === 0) return true;
119
                return false;
120
        }
121
 
122
        public static function getUploadDir($id=null) {
123
                // Get base path
124
                $cfg = OIDplus::config()->getValue('attachment_upload_dir', '');
125
                $cfg = trim($cfg);
126
                if ($cfg === '') {
127
                        $basepath = OIDplus::localpath() . 'userdata' . DIRECTORY_SEPARATOR . 'attachments';
128
                } else {
129
                        $basepath = $cfg;
130
                }
131
 
132
                try {
133
                        self::checkUploadDir($basepath);
1050 daniel-mar 134
                } catch (\Exception $e) {
635 daniel-mar 135
                        $error = _L('This functionality is not available due to a misconfiguration');
136
                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
137
                                $error .= ': '.$e->getMessage();
138
                        } else {
139
                                $error .= '. '._L('Please notify the system administrator. After they log-in, they can see the reason at this place.');
140
                        }
141
                        throw new OIDplusException($error);
142
                }
143
 
144
                // Get object-specific path
145
                if (!is_null($id)) {
146
                        $obj = OIDplusObject::parse($id);
147
                        if ($obj === null) throw new OIDplusException(_L('Invalid object "%1"',$id));
148
 
149
                        $path_v1 = $basepath . DIRECTORY_SEPARATOR . $obj->getLegacyDirectoryName();
150
                        $path_v1_bug = $basepath . $obj->getLegacyDirectoryName();
151
                        $path_v2 = $basepath . DIRECTORY_SEPARATOR . $obj->getDirectoryName();
152
 
153
                        if (is_dir($path_v1)) return $path_v1; // backwards compatibility
154
                        if (is_dir($path_v1_bug)) return $path_v1_bug; // backwards compatibility
155
                        return $path_v2;
156
                } else {
157
                        return $basepath;
158
                }
159
        }
160
 
161
        private function raMayDelete() {
162
                return OIDplus::config()->getValue('attachments_allow_ra_delete', 0);
163
        }
164
 
165
        private function raMayUpload() {
166
                return OIDplus::config()->getValue('attachments_allow_ra_upload', 0);
167
        }
168
 
169
        public function action($actionID, $params) {
170
 
171
                if ($actionID == 'deleteAttachment') {
172
                        _CheckParamExists($params, 'id');
173
                        $id = $params['id'];
174
                        $obj = OIDplusObject::parse($id);
175
                        if ($obj === null) throw new OIDplusException(_L('Invalid object "%1"',$id));
176
                        if (!$obj->userHasWriteRights()) throw new OIDplusException(_L('Authentication error. Please log in as admin, or as the RA of "%1" to upload an attachment.',$id));
177
 
178
                        if (!OIDplus::authUtils()->isAdminLoggedIn() && !$this->raMayDelete()) {
179
                                throw new OIDplusException(_L('The administrator has disabled deleting attachments by RAs.'));
180
                        }
181
 
182
                        _CheckParamExists($params, 'filename');
183
                        $req_filename = $params['filename'];
184
                        if (strpos($req_filename, '/') !== false) throw new OIDplusException(_L('Illegal file name'));
185
                        if (strpos($req_filename, '\\') !== false) throw new OIDplusException(_L('Illegal file name'));
186
                        if (strpos($req_filename, '..') !== false) throw new OIDplusException(_L('Illegal file name'));
187
                        if (strpos($req_filename, chr(0)) !== false) throw new OIDplusException(_L('Illegal file name'));
188
 
189
                        $uploaddir = self::getUploadDir($id);
190
                        $uploadfile = $uploaddir . DIRECTORY_SEPARATOR . basename($req_filename);
191
 
192
                        if (!file_exists($uploadfile)) throw new OIDplusException(_L('File does not exist'));
193
                        @unlink($uploadfile);
194
                        if (file_exists($uploadfile)) {
195
                                OIDplus::logger()->log("[ERR]OID($id)+[ERR]A!", "Attachment file '".basename($uploadfile)."' could not be deleted from object '$id' (problem with permissions?)");
196
                                $msg = _L('Attachment file "%1" could not be deleted from object "%2" (problem with permissions?)',basename($uploadfile),$id);
197
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
198
                                        throw new OIDplusException($msg);
199
                                } else {
200
                                        throw new OIDplusException($msg.'. '._L('Please contact the system administrator.'));
201
                                }
202
                        } else {
203
                                // If it was the last file, delete the empty directory
719 daniel-mar 204
                                $ary = @glob($uploaddir . DIRECTORY_SEPARATOR . '*');
205
                                if (is_array($ary) && (count($ary) == 0)) @rmdir($uploaddir);
635 daniel-mar 206
                        }
207
 
208
                        OIDplus::logger()->log("[OK]OID($id)+[?INFO/!OK]OIDRA($id)?/[?INFO/!OK]A?", "Deleted attachment '".basename($uploadfile)."' from object '$id'");
209
 
210
                        return array("status" => 0);
211
 
212
                } else if ($actionID == 'uploadAttachment') {
213
                        _CheckParamExists($params, 'id');
214
                        $id = $params['id'];
215
                        $obj = OIDplusObject::parse($id);
216
                        if ($obj === null) throw new OIDplusException(_L('Invalid object "%1"',$id));
217
                        if (!$obj->userHasWriteRights()) throw new OIDplusException(_L('Authentication error. Please log in as admin, or as the RA of "%1" to upload an attachment.',$id));
218
 
219
                        if (!OIDplus::authUtils()->isAdminLoggedIn() && !$this->raMayUpload()) {
220
                                throw new OIDplusException(_L('The administrator has disabled uploading attachments by RAs.'));
221
                        }
222
 
223
                        if (!isset($_FILES['userfile'])) {
224
                                throw new OIDplusException(_L('Please choose a file.'));
225
                        }
226
 
227
                        if (!OIDplus::authUtils()->isAdminLoggedIn()) {
836 daniel-mar 228
                                $fname = basename($_FILES['userfile']['name']);
229
 
834 daniel-mar 230
                                // 1. If something is on the blacklist, we always block it, even if it is on the whitelist, too
635 daniel-mar 231
                                $banned = explode(',', OIDplus::config()->getValue('attachments_block_extensions', ''));
232
                                foreach ($banned as $ext) {
233
                                        $ext = trim($ext);
234
                                        if ($ext == '') continue;
836 daniel-mar 235
                                        if (strtolower(substr($fname, -strlen($ext)-1)) == strtolower('.'.$ext)) {
635 daniel-mar 236
                                                throw new OIDplusException(_L('The file extension "%1" is banned by the administrator (it can be uploaded by the administrator though)',$ext));
237
                                        }
238
                                }
834 daniel-mar 239
 
240
                                // 2. Something on the whitelist is always OK
241
                                $allowed = explode(',', OIDplus::config()->getValue('attachments_allow_extensions', ''));
242
                                $is_whitelisted = false;
243
                                foreach ($allowed as $ext) {
244
                                        $ext = trim($ext);
245
                                        if ($ext == '') continue;
836 daniel-mar 246
                                        if (strtolower(substr($fname, -strlen($ext)-1)) == strtolower('.'.$ext)) {
834 daniel-mar 247
                                                $is_whitelisted = true;
248
                                                break;
249
                                        }
250
                                }
251
 
252
                                // 3. For everything that is neither whitelisted, nor blacklisted, the admin can decide if these grey zone is allowed or blocked
253
                                if (!$is_whitelisted) {
254
                                        if (!OIDplus::config()->getValue('attachments_allow_grey_extensions', '1')) {
836 daniel-mar 255
                                                $tmp = explode('.', $fname);
256
                                                $ext = array_pop($tmp);
834 daniel-mar 257
                                                throw new OIDplusException(_L('The file extension "%1" is not on the whitelist (it can be uploaded by the administrator though)',$ext));
258
                                        }
259
                                }
635 daniel-mar 260
                        }
261
 
262
                        $req_filename = $_FILES['userfile']['name'];
263
                        if (strpos($req_filename, '/') !== false) throw new OIDplusException(_L('Illegal file name'));
264
                        if (strpos($req_filename, '\\') !== false) throw new OIDplusException(_L('Illegal file name'));
265
                        if (strpos($req_filename, '..') !== false) throw new OIDplusException(_L('Illegal file name'));
266
                        if (strpos($req_filename, chr(0)) !== false) throw new OIDplusException(_L('Illegal file name'));
267
 
268
                        $uploaddir = self::getUploadDir($id);
269
                        $uploadfile = $uploaddir . DIRECTORY_SEPARATOR . basename($req_filename);
270
 
271
                        if (!is_dir($uploaddir)) {
272
                                @mkdir($uploaddir, 0777, true);
273
                                if (!is_dir($uploaddir)) {
274
                                        OIDplus::logger()->log("[ERR]OID($id)+[ERR]A!", "Upload attachment '".basename($uploadfile)."' to object '$id' failed: Cannot create directory '".basename($uploaddir)."' (problem with permissions?)");
275
                                        $msg = _L('Upload attachment "%1" to object "%2" failed',basename($uploadfile),$id).': '._L('Cannot create directory "%1" (problem with permissions?)',basename($uploaddir));
276
                                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
277
                                                throw new OIDplusException($msg);
278
                                        } else {
279
                                                throw new OIDplusException($msg.'. '._L('Please contact the system administrator.'));
280
                                        }
281
                                }
282
                        }
283
 
284
                        if (!@move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
285
                                OIDplus::logger()->log("[ERR]OID($id)+[ERR]A!", "Upload attachment '".basename($uploadfile)."' to object '$id' failed: Cannot move uploaded file into directory (problem with permissions?)");
286
                                $msg = _L('Upload attachment "%1" to object "%2" failed',basename($uploadfile),$id).': '._L('Cannot move uploaded file into directory (problem with permissions?)');
287
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
288
                                        throw new OIDplusException($msg);
289
                                } else {
290
                                        throw new OIDplusException($msg.'. '._L('Please contact the system administrator.'));
291
                                }
292
                        }
293
 
294
                        OIDplus::logger()->log("[OK]OID($id)+[?INFO/!OK]OIDRA($id)?/[?INFO/!OK]A?", "Uploaded attachment '".basename($uploadfile)."' to object '$id'");
295
 
296
                        return array("status" => 0);
297
                } else {
298
                        throw new OIDplusException(_L('Unknown action ID'));
299
                }
300
        }
301
 
302
        public function init($html=true) {
303
                OIDplus::config()->prepareConfigKey('attachments_block_extensions', 'Block file name extensions being used in file attachments (comma separated)', 'exe,scr,pif,bat,com,vbs,cmd', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
834 daniel-mar 304
                        // TODO: check if a blacklist entry is also on the whitelist (which is not allowed)
635 daniel-mar 305
                });
834 daniel-mar 306
                OIDplus::config()->prepareConfigKey('attachments_allow_extensions', 'Allow (whitelist) file name extensions being used in file attachments (comma separated)', '', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
307
                        // TODO: check if a whitelist entry is also on the blacklist (which is not allowed)
308
                });
309
                OIDplus::config()->prepareConfigKey('attachments_allow_grey_extensions', 'Should file-extensions which are neither be on the whitelist, nor be at the blacklist, be allowed? (1=Yes, 0=No)', '1', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
310
                        if (!is_numeric($value) || ($value < 0) || ($value > 1)) {
311
                                throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
312
                        }
313
                });
635 daniel-mar 314
                OIDplus::config()->prepareConfigKey('attachments_allow_ra_delete', 'Allow that RAs delete file attachments? (0=no, 1=yes)', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
315
                        if (!is_numeric($value) || ($value < 0) || ($value > 1)) {
316
                                throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
317
                        }
318
                });
319
                OIDplus::config()->prepareConfigKey('attachments_allow_ra_upload', 'Allow that RAs upload file attachments? (0=no, 1=yes)', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
320
                        if (!is_numeric($value) || ($value < 0) || ($value > 1)) {
321
                                throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
322
                        }
323
                });
324
 
325
                $info_txt  = 'Alternative directory for attachments. It must contain a file named "';
326
                $info_txt .= self::DIR_UNLOCK_FILE;
327
                $info_txt .= '"';
328
                if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
329
                        $info_txt .= ' with the same owner as index.php';
330
                }
331
                $info_txt .= '. If this setting is empty, then the userdata directory is used.';
332
                OIDplus::config()->prepareConfigKey('attachment_upload_dir', $info_txt, '', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
333
                        if (trim($value) !== '') {
334
                                self::checkUploadDir($value);
335
                        }
336
                });
337
        }
338
 
339
        public function gui($id, &$out, &$handled) {
340
                // Nothing
341
        }
342
 
343
        public function publicSitemap(&$out) {
344
                // Nothing
345
        }
346
 
347
        public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
348
                return false;
349
        }
350
 
351
        private static function convert_filesize($bytes, $decimals = 2){
352
                $size = array(_L('Bytes'),_L('KiB'),_L('MiB'),_L('GiB'),_L('TiB'),_L('PiB'),_L('EiB'),_L('ZiB'),_L('YiB'));
353
                $factor = floor((strlen($bytes) - 1) / 3);
354
                return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . @$size[$factor];
355
        }
356
 
357
        public function implementsFeature($id) {
358
                if (strtolower($id) == '1.3.6.1.4.1.37476.2.5.2.3.2') return true; // modifyContent
359
                if (strtolower($id) == '1.3.6.1.4.1.37476.2.5.2.3.3') return true; // beforeObject*, afterObject*
360
                if (strtolower($id) == '1.3.6.1.4.1.37476.2.5.2.3.4') return true; // whois*Attributes
361
                return false;
362
        }
363
 
364
        public function modifyContent($id, &$title, &$icon, &$text) {
365
                // Interface 1.3.6.1.4.1.37476.2.5.2.3.2
366
 
367
                $output = '';
368
                $doshow = false;
369
 
370
                try {
371
                        $upload_dir = self::getUploadDir($id);
719 daniel-mar 372
                        $files = @glob($upload_dir . DIRECTORY_SEPARATOR . '*');
635 daniel-mar 373
                        $found_files = false;
374
 
375
                        $obj = OIDplusObject::parse($id);
376
                        if ($obj === null) throw new OIDplusException(_L('Invalid object "%1"',$id));
377
                        $can_upload = OIDplus::authUtils()->isAdminLoggedIn() || ($this->raMayUpload() && $obj->userHasWriteRights());
378
                        $can_delete = OIDplus::authUtils()->isAdminLoggedIn() || ($this->raMayDelete() && $obj->userHasWriteRights());
379
 
380
                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
381
                                $output .= '<p>'._L('Admin info: The directory is %1','<b>'.htmlentities($upload_dir).'</b>').'</p>';
382
                                $doshow = true;
383
                        }
384
 
385
                        $output .= '<div id="fileattachments_table" class="table-responsive">';
386
                        $output .= '<table class="table table-bordered table-striped">';
387
                        $output .= '<tr>';
388
                        $output .= '<th>'._L('Filename').'</th>';
389
                        $output .= '<th>'._L('Size').'</th>';
390
                        $output .= '<th>'._L('File type').'</th>';
391
                        $output .= '<th>'._L('Download').'</th>';
392
                        if ($can_delete) $output .= '<th>'._L('Delete').'</th>';
393
                        $output .= '</tr>';
719 daniel-mar 394
                        if ($files) foreach ($files as $file) {
635 daniel-mar 395
                                if (is_dir($file)) continue;
396
 
397
                                $output .= '<tr>';
398
                                $output .= '<td>'.htmlentities(basename($file)).'</td>';
399
                                $output .= '<td>'.htmlentities(self::convert_filesize(filesize($file), 0)).'</td>';
400
                                $lookup_files = array(
401
                                        OIDplus::localpath().'userdata/attachments/filetypes$'.OIDplus::getCurrentLang().'.conf',
402
                                        OIDplus::localpath().'userdata/attachments/filetypes.conf',
403
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes$'.OIDplus::getCurrentLang().'.local', // not recommended
404
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes.local', // not recommended
405
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes$'.OIDplus::getCurrentLang().'.conf',
406
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes.conf'
407
                                );
1050 daniel-mar 408
                                $output .= '<td>'.htmlentities(\VtsFileTypeDetect::getDescription($file, $lookup_files)).'</td>';
635 daniel-mar 409
 
801 daniel-mar 410
                                $output .= '     <td><button type="button" name="download_'.md5($file).'" id="download_'.md5($file).'" class="btn btn-success btn-xs download" onclick="OIDplusPagePublicAttachments.downloadAttachment('.js_escape(OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE)).', current_node,'.js_escape(basename($file)).')">'._L('Download').'</button></td>';
635 daniel-mar 411
                                if ($can_delete) {
412
                                        $output .= '     <td><button type="button" name="delete_'.md5($file).'" id="delete_'.md5($file).'" class="btn btn-danger btn-xs delete" onclick="OIDplusPagePublicAttachments.deleteAttachment(current_node,'.js_escape(basename($file)).')">'._L('Delete').'</button></td>';
413
                                }
414
 
415
                                $output .= '</tr>';
416
                                $doshow = true;
417
                                $found_files = true;
418
                        }
419
 
420
                        if (!$found_files) $output .= '<tr><td colspan="'.($can_delete ? 5 : 4).'"><i>'._L('No attachments').'</i></td></tr>';
421
 
422
                        $output .= '</table></div>';
423
 
424
                        if ($can_upload) {
425
                                $output .= '<form action="javascript:void(0);" onsubmit="return OIDplusPagePublicAttachments.uploadAttachmentOnSubmit(this);" enctype="multipart/form-data" id="uploadAttachmentForm">';
426
                                $output .= '<input type="hidden" name="id" value="'.htmlentities($id).'">';
427
                                $output .= '<div>'._L('Add a file attachment').':<input type="file" name="userfile" value="" id="fileAttachment">';
428
                                $output .= '<br><input type="submit" value="'._L('Upload').'"></div>';
429
                                $output .= '</form>';
430
                                $doshow = true;
431
                        }
1050 daniel-mar 432
                } catch (\Exception $e) {
635 daniel-mar 433
                        $doshow = true;
434
                        $output = '<p>'.$e->getMessage().'</p>';
435
                }
436
 
437
                $output = '<h2>'._L('File attachments').'</h2>' .
438
                          '<div class="container box">' .
439
                          $output .
440
                          '</div>';
441
                if ($doshow) $text .= $output;
442
        }
443
 
444
        public function beforeObjectDelete($id) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
445
        public function afterObjectDelete($id) {
446
                // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
447
                // Delete the attachment folder including all files in it (note: Subfolders are not possible)
448
                $uploaddir = self::getUploadDir($id);
449
                if ($uploaddir != '') {
719 daniel-mar 450
                        $ary = @glob($uploaddir . DIRECTORY_SEPARATOR . '*');
451
                        if ($ary) foreach ($ary as $a) @unlink($a);
635 daniel-mar 452
                        @rmdir($uploaddir);
453
                        if (is_dir($uploaddir)) {
454
                                OIDplus::logger()->log("[WARN]OID($id)+[WARN]A!", "Attachment directory '$uploaddir' could not be deleted during the deletion of the OID");
455
                        }
456
                }
457
        }
458
        public function beforeObjectUpdateSuperior($id, &$params) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
459
        public function afterObjectUpdateSuperior($id, &$params) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
460
        public function beforeObjectUpdateSelf($id, &$params) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
461
        public function afterObjectUpdateSelf($id, &$params) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
462
        public function beforeObjectInsert($id, &$params) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
463
        public function afterObjectInsert($id, &$params) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.3
464
 
465
        public function tree_search($request) {
466
                return false;
467
        }
468
 
469
        public function whoisObjectAttributes($id, &$out) {
470
                // Interface 1.3.6.1.4.1.37476.2.5.2.3.4
471
 
899 daniel-mar 472
                $xmlns = 'oidplus-attachment-plugin';
473
                $xmlschema = 'urn:oid:1.3.6.1.4.1.37476.2.5.2.4.1.95.1';
474
                $xmlschemauri = OIDplus::webpath(__DIR__.'/attachments.xsd',OIDplus::PATH_ABSOLUTE);
475
 
719 daniel-mar 476
                $files = @glob(self::getUploadDir($id) . DIRECTORY_SEPARATOR . '*');
477
                if ($files) foreach ($files as $file) {
899 daniel-mar 478
                        $url = OIDplus::webpath(__DIR__,OIDplus::PATH_ABSOLUTE).'download.php?id='.urlencode($id).'&filename='.urlencode(basename($file));
479
 
480
                        $out[] = array(
481
                                'xmlns' => $xmlns,
482
                                'xmlschema' => $xmlschema,
483
                                'xmlschemauri' => $xmlschemauri,
484
                                'name' => 'attachment-name',
485
                                'value' => basename($file)
486
                        );
487
 
488
                        $out[] = array(
489
                                'xmlns' => $xmlns,
490
                                'xmlschema' => $xmlschema,
491
                                'xmlschemauri' => $xmlschemauri,
492
                                'name' => 'attachment-url',
493
                                'value' => $url
494
                        );
635 daniel-mar 495
                }
496
 
497
        }
498
        public function whoisRaAttributes($email, &$out) {} // Interface 1.3.6.1.4.1.37476.2.5.2.3.4
499
}