PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.1.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.1.0
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
← All changes | app/Services/UploadService.php +71 -16 1.122.1.0 View file →
@@ -7,13 +7,14 @@
7 7 use FluentBoards\Framework\Support\Arr;
8 8
9 9 class UploadService
10 10 {
11 + const MAX_FILE_UPLOAD_BYTES = 104857600;
11 12
12 13 /**
13 14 * @throws \Exception
14 15 */
15 - public static function handleFileUpload($file, $boardId, $taskId)
16 + public static function handleFileUpload($file, $boardId, $taskId = null)
16 17 {
17 18 $uploadInfo = FileSystem::setSubDir('board_'.$boardId)->put($file);
18 19
19 20 if (!empty($uploadInfo) && is_array($uploadInfo)) {
@@ -25,32 +26,86 @@
25 26
26 27 public function validateFile($file)
27 28 {
28 29 if (!$file) {
29 - throw new \Exception('File is empty.');
30 + throw new \Exception(esc_html__('File is empty.', 'fluent-boards'));
30 31 }
31 32 if (!$this->isFileTypeSupported($file)) {
32 - throw new \Exception('File type not supported');
33 + throw new \Exception(esc_html__('File type not supported', 'fluent-boards'));
33 34 }
34 - if ($file['size'] > $this->getFileUploadLimit()) {
35 - throw new \Exception('File size is too large');
35 + if ($file['size_in_bytes'] > $this->getFileUploadLimit()) {
36 + throw new \Exception(esc_html__('File size is too large', 'fluent-boards'));
36 37 }
37 38 }
38 39
39 40 public function getFileUploadLimit() {
40 - // Logic for calculating file upload limit as in your original code
41 - return min(
42 - wp_convert_hr_to_bytes(ini_get('upload_max_filesize')),
43 - wp_convert_hr_to_bytes(ini_get('post_max_size')),
44 - wp_max_upload_size()
45 - );
41 + return (int) apply_filters('fluent_boards/upload_file_size_limit', self::MAX_FILE_UPLOAD_BYTES);
46 42 }
47 43
48 44 public function isFileTypeSupported($file)
49 45 {
50 - // Define supported file types that are generally allowed by user
51 - $allowedMimeTypes = get_allowed_mime_types();
52 - // Check if the file type is supported
53 - return in_array(strtolower($file['type']), $allowedMimeTypes);
46 + // Validate by extension against our allow-list. This is more reliable than the
47 + // browser-provided mime, which is empty/inconsistent for types like .json and .md.
48 + $extension = strtolower(pathinfo(Arr::get($file, 'name', ''), PATHINFO_EXTENSION));
49 + if (!$extension) {
50 + return false;
51 + }
52 +
53 + foreach (array_keys(self::getAllowedMimeMap()) as $extensionPattern) {
54 + if (in_array($extension, explode('|', $extensionPattern), true)) {
55 + return true;
56 + }
57 + }
58 +
59 + return false;
54 60 }
55 61
56 -}
62 + /**
63 + * Allow-list of upload types as an extension => mime map (WordPress defaults plus
64 + * common developer/document formats). Shared by validateFile() and wp_handle_upload()
65 + * so both agree. Executable/script types are intentionally excluded.
66 + *
67 + * @return array
68 + */
69 + public static function getAllowedMimeMap()
70 + {
71 + $extraMimes = [
72 + 'json' => 'application/json',
73 + 'md' => 'text/markdown',
74 + 'markdown' => 'text/markdown',
75 + 'csv' => 'text/csv',
76 + 'txt' => 'text/plain',
77 + 'log' => 'text/plain',
78 + 'xml' => 'text/xml',
79 + 'yaml|yml' => 'text/yaml',
80 + 'webp' => 'image/webp',
81 + 'avif' => 'image/avif',
82 + 'heic' => 'image/heic',
83 + 'zip' => 'application/zip',
84 + 'rar' => 'application/vnd.rar',
85 + '7z' => 'application/x-7z-compressed',
86 + 'tar' => 'application/x-tar',
87 + 'gz|gzip' => 'application/gzip',
88 + ];
89 +
90 + $map = array_merge(get_allowed_mime_types(), $extraMimes);
91 + $map = apply_filters('fluent_boards/upload_allowed_mimes', $map);
92 +
93 + // Never allow executable or browser-active formats through plugin filters.
94 + $blockedExtensions = [
95 + 'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'phar',
96 + 'html', 'htm', 'shtml', 'xhtml', 'xht',
97 + 'js', 'mjs', 'svg', 'svgz', 'xml', 'xsl', 'xslt', 'swf', 'htaccess',
98 + ];
99 + $safeMap = [];
100 +
101 + foreach ($map as $extensionPattern => $mimeType) {
102 + $extensions = array_diff(explode('|', strtolower($extensionPattern)), $blockedExtensions);
103 + if ($extensions) {
104 + $safeMap[implode('|', $extensions)] = $mimeType;
105 + }
106 + }
107 +
108 + return $safeMap;
109 + }
110 +
111 +}