Subversion Repositories oidplus

Rev

Rev 1143 | Rev 1180 | 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
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
635 daniel-mar 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
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
1131 daniel-mar 26
class OIDplusPagePublicAttachments extends OIDplusPagePluginPublic
27
        implements INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_2, /* modifyContent */
28
                   INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3, /* beforeObject*, afterObject* */
29
                   INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4  /* whois*Attributes */
30
{
635 daniel-mar 31
 
1130 daniel-mar 32
        /**
33
         * @param string $dir
1116 daniel-mar 34
         * @return void
35
         * @throws OIDplusException
36
         */
1130 daniel-mar 37
        private static function checkUploadDir(string $dir) {
635 daniel-mar 38
                if (!is_dir($dir)) {
39
                        throw new OIDplusException(_L('The attachment directory "%1" is not existing.', $dir));
40
                }
41
 
42
                $realdir = realpath($dir);
43
                if ($realdir === false) {
44
                        throw new OIDplusException(_L('The attachment directory "%1" cannot be resolved (realpath).', $dir));
45
                }
46
 
1175 daniel-mar 47
                // Check for critical directories
635 daniel-mar 48
                if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
49
                        if (self::isCriticalLinuxDirectory($realdir)) {
50
                                throw new OIDplusException(_L('The attachment directory must not be inside a critical system directory!'));
51
                        }
52
                } else {
53
                        if (self::isCriticalWindowsDirectory($realdir)) {
54
                                throw new OIDplusException(_L('The attachment directory must not be inside a critical system directory!'));
55
                        }
56
                }
57
        }
58
 
1116 daniel-mar 59
        /**
1130 daniel-mar 60
         * @param string $dir
1116 daniel-mar 61
         * @return bool
62
         */
1130 daniel-mar 63
        private static function isCriticalWindowsDirectory(string $dir): bool {
1175 daniel-mar 64
                $dir = rtrim(str_replace('/', '\\', $dir),'\\').'\\';
65
                $windir = isset($_SERVER['SystemRoot']) ? rtrim($_SERVER['SystemRoot'],'\\').'\\' : 'C:\\Windows\\';
635 daniel-mar 66
                if (stripos($dir,$windir) === 0) return true;
67
                return false;
68
        }
69
 
1116 daniel-mar 70
        /**
1130 daniel-mar 71
         * @param string $dir
1116 daniel-mar 72
         * @return bool
73
         */
1130 daniel-mar 74
        private static function isCriticalLinuxDirectory(string $dir): bool {
635 daniel-mar 75
                if ($dir == '/') return true;
1175 daniel-mar 76
                $dir = rtrim($dir,'/').'/';
635 daniel-mar 77
                if (strpos($dir,'/bin/') === 0) return true;
78
                if (strpos($dir,'/boot/') === 0) return true;
79
                if (strpos($dir,'/dev/') === 0) return true;
80
                if (strpos($dir,'/etc/') === 0) return true;
81
                if (strpos($dir,'/lib') === 0) return true;
82
                if (strpos($dir,'/opt/') === 0) return true;
83
                if (strpos($dir,'/proc/') === 0) return true;
84
                if (strpos($dir,'/root/') === 0) return true;
85
                if (strpos($dir,'/run/') === 0) return true;
86
                if (strpos($dir,'/sbin/') === 0) return true;
87
                if (strpos($dir,'/sys/') === 0) return true;
88
                if (strpos($dir,'/tmp/') === 0) return true;
89
                if (strpos($dir,'/usr/bin/') === 0) return true;
90
                if (strpos($dir,'/usr/include/') === 0) return true;
91
                if (strpos($dir,'/usr/lib') === 0) return true;
92
                if (strpos($dir,'/usr/sbin/') === 0) return true;
93
                if (strpos($dir,'/usr/src/') === 0) return true;
94
                if (strpos($dir,'/var/cache/') === 0) return true;
95
                if (strpos($dir,'/var/lib') === 0) return true;
96
                if (strpos($dir,'/var/lock/') === 0) return true;
97
                if (strpos($dir,'/var/log/') === 0) return true;
98
                if (strpos($dir,'/var/mail/') === 0) return true;
99
                if (strpos($dir,'/var/opt/') === 0) return true;
100
                if (strpos($dir,'/var/run/') === 0) return true;
101
                if (strpos($dir,'/var/spool/') === 0) return true;
102
                if (strpos($dir,'/var/tmp/') === 0) return true;
103
                return false;
104
        }
105
 
1116 daniel-mar 106
        /**
1130 daniel-mar 107
         * @param string|null $id
1116 daniel-mar 108
         * @return string
109
         * @throws OIDplusException
110
         */
1130 daniel-mar 111
        public static function getUploadDir(string $id=null): string {
635 daniel-mar 112
                // Get base path
113
                $cfg = OIDplus::config()->getValue('attachment_upload_dir', '');
114
                $cfg = trim($cfg);
115
                if ($cfg === '') {
116
                        $basepath = OIDplus::localpath() . 'userdata' . DIRECTORY_SEPARATOR . 'attachments';
117
                } else {
118
                        $basepath = $cfg;
119
                }
120
 
121
                try {
122
                        self::checkUploadDir($basepath);
1050 daniel-mar 123
                } catch (\Exception $e) {
635 daniel-mar 124
                        $error = _L('This functionality is not available due to a misconfiguration');
125
                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
126
                                $error .= ': '.$e->getMessage();
127
                        } else {
128
                                $error .= '. '._L('Please notify the system administrator. After they log-in, they can see the reason at this place.');
129
                        }
130
                        throw new OIDplusException($error);
131
                }
132
 
133
                // Get object-specific path
134
                if (!is_null($id)) {
135
                        $obj = OIDplusObject::parse($id);
1116 daniel-mar 136
                        if (!$obj) throw new OIDplusException(_L('Invalid object "%1"',$id));
635 daniel-mar 137
 
138
                        $path_v1 = $basepath . DIRECTORY_SEPARATOR . $obj->getLegacyDirectoryName();
139
                        $path_v1_bug = $basepath . $obj->getLegacyDirectoryName();
140
                        $path_v2 = $basepath . DIRECTORY_SEPARATOR . $obj->getDirectoryName();
141
 
142
                        if (is_dir($path_v1)) return $path_v1; // backwards compatibility
143
                        if (is_dir($path_v1_bug)) return $path_v1_bug; // backwards compatibility
144
                        return $path_v2;
145
                } else {
146
                        return $basepath;
147
                }
148
        }
149
 
1116 daniel-mar 150
        /**
151
         * @return mixed|null
152
         * @throws OIDplusException
153
         */
635 daniel-mar 154
        private function raMayDelete() {
155
                return OIDplus::config()->getValue('attachments_allow_ra_delete', 0);
156
        }
157
 
1116 daniel-mar 158
        /**
159
         * @return mixed|null
160
         * @throws OIDplusException
161
         */
635 daniel-mar 162
        private function raMayUpload() {
163
                return OIDplus::config()->getValue('attachments_allow_ra_upload', 0);
164
        }
165
 
1116 daniel-mar 166
        /**
167
         * @param string $actionID
168
         * @param array $params
1143 daniel-mar 169
         * @return array
1116 daniel-mar 170
         * @throws OIDplusException
171
         */
172
        public function action(string $actionID, array $params): array {
635 daniel-mar 173
 
174
                if ($actionID == 'deleteAttachment') {
175
                        _CheckParamExists($params, 'id');
176
                        $id = $params['id'];
177
                        $obj = OIDplusObject::parse($id);
1116 daniel-mar 178
                        if (!$obj) throw new OIDplusException(_L('Invalid object "%1"',$id));
635 daniel-mar 179
                        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));
180
 
181
                        if (!OIDplus::authUtils()->isAdminLoggedIn() && !$this->raMayDelete()) {
182
                                throw new OIDplusException(_L('The administrator has disabled deleting attachments by RAs.'));
183
                        }
184
 
185
                        _CheckParamExists($params, 'filename');
186
                        $req_filename = $params['filename'];
187
                        if (strpos($req_filename, '/') !== false) throw new OIDplusException(_L('Illegal file name'));
188
                        if (strpos($req_filename, '\\') !== false) throw new OIDplusException(_L('Illegal file name'));
189
                        if (strpos($req_filename, '..') !== false) throw new OIDplusException(_L('Illegal file name'));
190
                        if (strpos($req_filename, chr(0)) !== false) throw new OIDplusException(_L('Illegal file name'));
191
 
192
                        $uploaddir = self::getUploadDir($id);
193
                        $uploadfile = $uploaddir . DIRECTORY_SEPARATOR . basename($req_filename);
194
 
195
                        if (!file_exists($uploadfile)) throw new OIDplusException(_L('File does not exist'));
196
                        @unlink($uploadfile);
197
                        if (file_exists($uploadfile)) {
198
                                OIDplus::logger()->log("[ERR]OID($id)+[ERR]A!", "Attachment file '".basename($uploadfile)."' could not be deleted from object '$id' (problem with permissions?)");
199
                                $msg = _L('Attachment file "%1" could not be deleted from object "%2" (problem with permissions?)',basename($uploadfile),$id);
200
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
201
                                        throw new OIDplusException($msg);
202
                                } else {
203
                                        throw new OIDplusException($msg.'. '._L('Please contact the system administrator.'));
204
                                }
205
                        } else {
206
                                // If it was the last file, delete the empty directory
719 daniel-mar 207
                                $ary = @glob($uploaddir . DIRECTORY_SEPARATOR . '*');
208
                                if (is_array($ary) && (count($ary) == 0)) @rmdir($uploaddir);
635 daniel-mar 209
                        }
210
 
211
                        OIDplus::logger()->log("[OK]OID($id)+[?INFO/!OK]OIDRA($id)?/[?INFO/!OK]A?", "Deleted attachment '".basename($uploadfile)."' from object '$id'");
212
 
213
                        return array("status" => 0);
214
 
215
                } else if ($actionID == 'uploadAttachment') {
216
                        _CheckParamExists($params, 'id');
217
                        $id = $params['id'];
218
                        $obj = OIDplusObject::parse($id);
1116 daniel-mar 219
                        if (!$obj) throw new OIDplusException(_L('Invalid object "%1"',$id));
635 daniel-mar 220
                        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));
221
 
222
                        if (!OIDplus::authUtils()->isAdminLoggedIn() && !$this->raMayUpload()) {
223
                                throw new OIDplusException(_L('The administrator has disabled uploading attachments by RAs.'));
224
                        }
225
 
226
                        if (!isset($_FILES['userfile'])) {
227
                                throw new OIDplusException(_L('Please choose a file.'));
228
                        }
229
 
230
                        if (!OIDplus::authUtils()->isAdminLoggedIn()) {
836 daniel-mar 231
                                $fname = basename($_FILES['userfile']['name']);
232
 
834 daniel-mar 233
                                // 1. If something is on the blacklist, we always block it, even if it is on the whitelist, too
635 daniel-mar 234
                                $banned = explode(',', OIDplus::config()->getValue('attachments_block_extensions', ''));
235
                                foreach ($banned as $ext) {
236
                                        $ext = trim($ext);
237
                                        if ($ext == '') continue;
836 daniel-mar 238
                                        if (strtolower(substr($fname, -strlen($ext)-1)) == strtolower('.'.$ext)) {
635 daniel-mar 239
                                                throw new OIDplusException(_L('The file extension "%1" is banned by the administrator (it can be uploaded by the administrator though)',$ext));
240
                                        }
241
                                }
834 daniel-mar 242
 
243
                                // 2. Something on the whitelist is always OK
244
                                $allowed = explode(',', OIDplus::config()->getValue('attachments_allow_extensions', ''));
245
                                $is_whitelisted = false;
246
                                foreach ($allowed as $ext) {
247
                                        $ext = trim($ext);
248
                                        if ($ext == '') continue;
836 daniel-mar 249
                                        if (strtolower(substr($fname, -strlen($ext)-1)) == strtolower('.'.$ext)) {
834 daniel-mar 250
                                                $is_whitelisted = true;
251
                                                break;
252
                                        }
253
                                }
254
 
255
                                // 3. For everything that is neither whitelisted, nor blacklisted, the admin can decide if these grey zone is allowed or blocked
256
                                if (!$is_whitelisted) {
257
                                        if (!OIDplus::config()->getValue('attachments_allow_grey_extensions', '1')) {
836 daniel-mar 258
                                                $tmp = explode('.', $fname);
259
                                                $ext = array_pop($tmp);
834 daniel-mar 260
                                                throw new OIDplusException(_L('The file extension "%1" is not on the whitelist (it can be uploaded by the administrator though)',$ext));
261
                                        }
262
                                }
635 daniel-mar 263
                        }
264
 
265
                        $req_filename = $_FILES['userfile']['name'];
266
                        if (strpos($req_filename, '/') !== false) throw new OIDplusException(_L('Illegal file name'));
267
                        if (strpos($req_filename, '\\') !== false) throw new OIDplusException(_L('Illegal file name'));
268
                        if (strpos($req_filename, '..') !== false) throw new OIDplusException(_L('Illegal file name'));
269
                        if (strpos($req_filename, chr(0)) !== false) throw new OIDplusException(_L('Illegal file name'));
270
 
271
                        $uploaddir = self::getUploadDir($id);
272
                        $uploadfile = $uploaddir . DIRECTORY_SEPARATOR . basename($req_filename);
273
 
274
                        if (!is_dir($uploaddir)) {
275
                                @mkdir($uploaddir, 0777, true);
276
                                if (!is_dir($uploaddir)) {
277
                                        OIDplus::logger()->log("[ERR]OID($id)+[ERR]A!", "Upload attachment '".basename($uploadfile)."' to object '$id' failed: Cannot create directory '".basename($uploaddir)."' (problem with permissions?)");
278
                                        $msg = _L('Upload attachment "%1" to object "%2" failed',basename($uploadfile),$id).': '._L('Cannot create directory "%1" (problem with permissions?)',basename($uploaddir));
279
                                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
280
                                                throw new OIDplusException($msg);
281
                                        } else {
282
                                                throw new OIDplusException($msg.'. '._L('Please contact the system administrator.'));
283
                                        }
284
                                }
285
                        }
286
 
287
                        if (!@move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
288
                                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?)");
289
                                $msg = _L('Upload attachment "%1" to object "%2" failed',basename($uploadfile),$id).': '._L('Cannot move uploaded file into directory (problem with permissions?)');
290
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
291
                                        throw new OIDplusException($msg);
292
                                } else {
293
                                        throw new OIDplusException($msg.'. '._L('Please contact the system administrator.'));
294
                                }
295
                        }
296
 
297
                        OIDplus::logger()->log("[OK]OID($id)+[?INFO/!OK]OIDRA($id)?/[?INFO/!OK]A?", "Uploaded attachment '".basename($uploadfile)."' to object '$id'");
298
 
299
                        return array("status" => 0);
300
                } else {
1116 daniel-mar 301
                        return parent::action($actionID, $params);
635 daniel-mar 302
                }
303
        }
304
 
1116 daniel-mar 305
        /**
306
         * @param bool $html
307
         * @return void
308
         * @throws OIDplusException
309
         */
310
        public function init(bool $html=true) {
635 daniel-mar 311
                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 312
                        // TODO: check if a blacklist entry is also on the whitelist (which is not allowed)
635 daniel-mar 313
                });
834 daniel-mar 314
                OIDplus::config()->prepareConfigKey('attachments_allow_extensions', 'Allow (whitelist) file name extensions being used in file attachments (comma separated)', '', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
315
                        // TODO: check if a whitelist entry is also on the blacklist (which is not allowed)
316
                });
317
                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) {
318
                        if (!is_numeric($value) || ($value < 0) || ($value > 1)) {
319
                                throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
320
                        }
321
                });
635 daniel-mar 322
                OIDplus::config()->prepareConfigKey('attachments_allow_ra_delete', 'Allow that RAs delete file attachments? (0=no, 1=yes)', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
323
                        if (!is_numeric($value) || ($value < 0) || ($value > 1)) {
324
                                throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
325
                        }
326
                });
327
                OIDplus::config()->prepareConfigKey('attachments_allow_ra_upload', 'Allow that RAs upload file attachments? (0=no, 1=yes)', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
328
                        if (!is_numeric($value) || ($value < 0) || ($value > 1)) {
329
                                throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
330
                        }
331
                });
1175 daniel-mar 332
                OIDplus::config()->prepareConfigKey('attachment_upload_dir', 'Alternative directory for attachments. If this setting is empty, then the userdata directory is used.', '', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
635 daniel-mar 333
                        if (trim($value) !== '') {
334
                                self::checkUploadDir($value);
335
                        }
336
                });
337
        }
338
 
1116 daniel-mar 339
        /**
340
         * @param string $id
341
         * @param array $out
342
         * @param bool $handled
343
         * @return void
344
         */
345
        public function gui(string $id, array &$out, bool &$handled) {
635 daniel-mar 346
                // Nothing
347
        }
348
 
1116 daniel-mar 349
        /**
350
         * @param array $out
351
         * @return void
352
         */
353
        public function publicSitemap(array &$out) {
635 daniel-mar 354
                // Nothing
355
        }
356
 
1116 daniel-mar 357
        /**
358
         * @param array $json
359
         * @param string|null $ra_email
360
         * @param bool $nonjs
361
         * @param string $req_goto
362
         * @return bool
363
         */
364
        public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
635 daniel-mar 365
                return false;
366
        }
367
 
1116 daniel-mar 368
        /**
369
         * Convert amount of bytes to human-friendly name
1175 daniel-mar 370
         *
1116 daniel-mar 371
         * @param int $bytes
372
         * @param int $decimals
373
         * @return string
1175 daniel-mar 374
         * @throws OIDplusConfigInitializationException
375
         * @throws OIDplusException
1116 daniel-mar 376
         */
377
        private static function convert_filesize(int $bytes, int $decimals = 2): string {
635 daniel-mar 378
                $size = array(_L('Bytes'),_L('KiB'),_L('MiB'),_L('GiB'),_L('TiB'),_L('PiB'),_L('EiB'),_L('ZiB'),_L('YiB'));
1116 daniel-mar 379
                $factor = floor((strlen("$bytes") - 1) / 3);
635 daniel-mar 380
                return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . @$size[$factor];
381
        }
382
 
1116 daniel-mar 383
        /**
1131 daniel-mar 384
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_2
1175 daniel-mar 385
         *
1116 daniel-mar 386
         * @param string $id
387
         * @param string $title
388
         * @param string $icon
389
         * @param string $text
390
         * @return void
1175 daniel-mar 391
         * @throws OIDplusConfigInitializationException
392
         * @throws OIDplusException
1116 daniel-mar 393
         */
394
        public function modifyContent(string $id, string &$title, string &$icon, string &$text) {
635 daniel-mar 395
                $output = '';
396
                $doshow = false;
397
 
398
                try {
399
                        $upload_dir = self::getUploadDir($id);
719 daniel-mar 400
                        $files = @glob($upload_dir . DIRECTORY_SEPARATOR . '*');
635 daniel-mar 401
                        $found_files = false;
402
 
403
                        $obj = OIDplusObject::parse($id);
1116 daniel-mar 404
                        if (!$obj) throw new OIDplusException(_L('Invalid object "%1"',$id));
635 daniel-mar 405
                        $can_upload = OIDplus::authUtils()->isAdminLoggedIn() || ($this->raMayUpload() && $obj->userHasWriteRights());
406
                        $can_delete = OIDplus::authUtils()->isAdminLoggedIn() || ($this->raMayDelete() && $obj->userHasWriteRights());
407
 
408
                        if (OIDplus::authUtils()->isAdminLoggedIn()) {
409
                                $output .= '<p>'._L('Admin info: The directory is %1','<b>'.htmlentities($upload_dir).'</b>').'</p>';
410
                                $doshow = true;
411
                        }
412
 
413
                        $output .= '<div id="fileattachments_table" class="table-responsive">';
414
                        $output .= '<table class="table table-bordered table-striped">';
1138 daniel-mar 415
                        $output .= '<thead>';
635 daniel-mar 416
                        $output .= '<tr>';
417
                        $output .= '<th>'._L('Filename').'</th>';
418
                        $output .= '<th>'._L('Size').'</th>';
419
                        $output .= '<th>'._L('File type').'</th>';
420
                        $output .= '<th>'._L('Download').'</th>';
421
                        if ($can_delete) $output .= '<th>'._L('Delete').'</th>';
422
                        $output .= '</tr>';
1138 daniel-mar 423
                        $output .= '</thead>';
424
                        $output .= '<tbody>';
719 daniel-mar 425
                        if ($files) foreach ($files as $file) {
635 daniel-mar 426
                                if (is_dir($file)) continue;
427
 
428
                                $output .= '<tr>';
429
                                $output .= '<td>'.htmlentities(basename($file)).'</td>';
430
                                $output .= '<td>'.htmlentities(self::convert_filesize(filesize($file), 0)).'</td>';
431
                                $lookup_files = array(
432
                                        OIDplus::localpath().'userdata/attachments/filetypes$'.OIDplus::getCurrentLang().'.conf',
433
                                        OIDplus::localpath().'userdata/attachments/filetypes.conf',
434
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes$'.OIDplus::getCurrentLang().'.local', // not recommended
435
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes.local', // not recommended
436
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes$'.OIDplus::getCurrentLang().'.conf',
437
                                        OIDplus::localpath().'vendor/danielmarschall/fileformats/filetypes.conf'
438
                                );
1050 daniel-mar 439
                                $output .= '<td>'.htmlentities(\VtsFileTypeDetect::getDescription($file, $lookup_files)).'</td>';
635 daniel-mar 440
 
801 daniel-mar 441
                                $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 442
                                if ($can_delete) {
443
                                        $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>';
444
                                }
445
 
446
                                $output .= '</tr>';
447
                                $doshow = true;
448
                                $found_files = true;
449
                        }
1138 daniel-mar 450
                        $output .= '</tbody>';
635 daniel-mar 451
 
1138 daniel-mar 452
                        if (!$found_files) {
453
                                $output .= '<tfoor>';
454
                                $output .= '<tr><td colspan="' . ($can_delete ? 5 : 4) . '"><i>' . _L('No attachments') . '</i></td></tr>';
455
                                $output .= '</tfoot>';
456
                        }
635 daniel-mar 457
 
458
                        $output .= '</table></div>';
459
 
460
                        if ($can_upload) {
461
                                $output .= '<form action="javascript:void(0);" onsubmit="return OIDplusPagePublicAttachments.uploadAttachmentOnSubmit(this);" enctype="multipart/form-data" id="uploadAttachmentForm">';
462
                                $output .= '<input type="hidden" name="id" value="'.htmlentities($id).'">';
463
                                $output .= '<div>'._L('Add a file attachment').':<input type="file" name="userfile" value="" id="fileAttachment">';
464
                                $output .= '<br><input type="submit" value="'._L('Upload').'"></div>';
465
                                $output .= '</form>';
466
                                $doshow = true;
467
                        }
1050 daniel-mar 468
                } catch (\Exception $e) {
635 daniel-mar 469
                        $doshow = true;
470
                        $output = '<p>'.$e->getMessage().'</p>';
471
                }
472
 
473
                $output = '<h2>'._L('File attachments').'</h2>' .
474
                          '<div class="container box">' .
475
                          $output .
476
                          '</div>';
477
                if ($doshow) $text .= $output;
478
        }
479
 
1116 daniel-mar 480
        /**
1131 daniel-mar 481
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 482
         * @param string $id
1116 daniel-mar 483
         * @return void
484
         */
1130 daniel-mar 485
        public function beforeObjectDelete(string $id) {}
1116 daniel-mar 486
 
487
        /**
1131 daniel-mar 488
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 489
         * @param string $id
1116 daniel-mar 490
         * @return void
491
         * @throws OIDplusException
492
         */
1130 daniel-mar 493
        public function afterObjectDelete(string $id) {
1131 daniel-mar 494
                // Delete the attachment folder including all files in it (note: Subfolders are not possible)
635 daniel-mar 495
                $uploaddir = self::getUploadDir($id);
496
                if ($uploaddir != '') {
719 daniel-mar 497
                        $ary = @glob($uploaddir . DIRECTORY_SEPARATOR . '*');
498
                        if ($ary) foreach ($ary as $a) @unlink($a);
635 daniel-mar 499
                        @rmdir($uploaddir);
500
                        if (is_dir($uploaddir)) {
501
                                OIDplus::logger()->log("[WARN]OID($id)+[WARN]A!", "Attachment directory '$uploaddir' could not be deleted during the deletion of the OID");
502
                        }
503
                }
504
        }
505
 
1116 daniel-mar 506
        /**
1131 daniel-mar 507
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 508
         * @param string $id
509
         * @param array $params
1116 daniel-mar 510
         * @return void
511
         */
1130 daniel-mar 512
        public function beforeObjectUpdateSuperior(string $id, array &$params) {}
1116 daniel-mar 513
 
514
        /**
1131 daniel-mar 515
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 516
         * @param string $id
517
         * @param array $params
1116 daniel-mar 518
         * @return void
519
         */
1130 daniel-mar 520
        public function afterObjectUpdateSuperior(string $id, array &$params) {}
1116 daniel-mar 521
 
522
        /**
1131 daniel-mar 523
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 524
         * @param string $id
525
         * @param array $params
1116 daniel-mar 526
         * @return void
527
         */
1130 daniel-mar 528
        public function beforeObjectUpdateSelf(string $id, array &$params) {}
1116 daniel-mar 529
 
530
        /**
1131 daniel-mar 531
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 532
         * @param string $id
533
         * @param array $params
1116 daniel-mar 534
         * @return void
535
         */
1130 daniel-mar 536
        public function afterObjectUpdateSelf(string $id, array &$params) {}
1116 daniel-mar 537
 
538
        /**
1131 daniel-mar 539
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 540
         * @param string $id
541
         * @param array $params
1116 daniel-mar 542
         * @return void
543
         */
1130 daniel-mar 544
        public function beforeObjectInsert(string $id, array &$params) {}
1116 daniel-mar 545
 
546
        /**
1131 daniel-mar 547
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_3
1130 daniel-mar 548
         * @param string $id
549
         * @param array $params
1116 daniel-mar 550
         * @return void
551
         */
1130 daniel-mar 552
        public function afterObjectInsert(string $id, array &$params) {}
1116 daniel-mar 553
 
554
        /**
555
         * @param string $request
556
         * @return array|false
557
         */
558
        public function tree_search(string $request) {
635 daniel-mar 559
                return false;
560
        }
561
 
1116 daniel-mar 562
        /**
1131 daniel-mar 563
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4
1130 daniel-mar 564
         * @param string $id
565
         * @param array $out
1116 daniel-mar 566
         * @return void
567
         * @throws OIDplusException
568
         */
1130 daniel-mar 569
        public function whoisObjectAttributes(string $id, array &$out) {
899 daniel-mar 570
                $xmlns = 'oidplus-attachment-plugin';
571
                $xmlschema = 'urn:oid:1.3.6.1.4.1.37476.2.5.2.4.1.95.1';
572
                $xmlschemauri = OIDplus::webpath(__DIR__.'/attachments.xsd',OIDplus::PATH_ABSOLUTE);
573
 
719 daniel-mar 574
                $files = @glob(self::getUploadDir($id) . DIRECTORY_SEPARATOR . '*');
575
                if ($files) foreach ($files as $file) {
899 daniel-mar 576
                        $url = OIDplus::webpath(__DIR__,OIDplus::PATH_ABSOLUTE).'download.php?id='.urlencode($id).'&filename='.urlencode(basename($file));
577
 
578
                        $out[] = array(
579
                                'xmlns' => $xmlns,
580
                                'xmlschema' => $xmlschema,
581
                                'xmlschemauri' => $xmlschemauri,
582
                                'name' => 'attachment-name',
583
                                'value' => basename($file)
584
                        );
585
 
586
                        $out[] = array(
587
                                'xmlns' => $xmlns,
588
                                'xmlschema' => $xmlschema,
589
                                'xmlschemauri' => $xmlschemauri,
590
                                'name' => 'attachment-url',
591
                                'value' => $url
592
                        );
635 daniel-mar 593
                }
594
 
595
        }
1116 daniel-mar 596
 
597
        /**
1131 daniel-mar 598
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4
1130 daniel-mar 599
         * @param string $email
600
         * @param array $out
1116 daniel-mar 601
         * @return void
602
         */
1130 daniel-mar 603
        public function whoisRaAttributes(string $email, array &$out) {}
635 daniel-mar 604
}