PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.21.4
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.21.4
V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 2.10.2 All 137 releases
bit-form / includes / Core / Util / FileHandler.php

FileHandler.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 2.21.4, at includes/Core/Util/FileHandler.php

700 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace BitCode\BitForm\Core\Util;
4
5 use BitCode\BitForm\Admin\Form\Helpers;
6 use BitCode\BitForm\Core\Form\FormManager;
7 use BitCode\BitForm\enshrined\svgSanitize\Sanitizer;
8
9 final class FileHandler
10 {
11 public function rmrf($dir)
12 {
13 if (is_dir($dir)) {
14 $objects = scandir($dir);
15 foreach ($objects as $object) {
16 if ('.' !== $object && '..' !== $object) {
17 if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . DIRECTORY_SEPARATOR . $object)) {
18 $this->rmrf($dir . DIRECTORY_SEPARATOR . $object);
19 } else {
20 wp_delete_file($dir . DIRECTORY_SEPARATOR . $object);
21 }
22 }
23 }
24 rmdir($dir);
25 } else {
26 wp_delete_file($dir);
27 }
28 }
29
30 public function cpyr($source, $destination)
31 {
32 if (is_dir($source)) {
33 mkdir($destination);
34 // chmod($destination, 0744);
35 $objects = scandir($source);
36 foreach ($objects as $object) {
37 if ('.' !== $object && '..' !== $object) {
38 if (is_dir($source . DIRECTORY_SEPARATOR . $object) && !is_link($source . DIRECTORY_SEPARATOR . $object)) {
39 cpyr($source . DIRECTORY_SEPARATOR . $object, $destination . DIRECTORY_SEPARATOR . $object);
40 } elseif (is_file($source . DIRECTORY_SEPARATOR . $object)) {
41 copy($source . DIRECTORY_SEPARATOR . $object, $destination . DIRECTORY_SEPARATOR . $object);
42 // chmod($destination. DIRECTORY_SEPARATOR .$object, 0644);
43 } else {
44 symlink($source . DIRECTORY_SEPARATOR . $object, $destination . DIRECTORY_SEPARATOR . $object);
45 }
46 }
47 }
48 } else {
49 copy($source, $destination);
50 }
51 }
52
53 public function moveUploadedFiles($file_details, $form_id, $entry_id)
54 {
55 $file_upoalded = [];
56 $_upload_dir = self::getEntriesFileUploadDir($form_id, $entry_id);
57 $this::createIndexFile($_upload_dir);
58 if (is_array($file_details['name'])) {
59 foreach ($file_details['name'] as $key => $value) {
60 //check accepted filetype in_array($file_details['name'][$key], $supported_files) else \
61 if (!empty($value)) {
62 $fileNameCount = 1;
63 // $file_upoalded[$key] = time()."_$value";
64 $file_upoalded[$key] = sanitize_file_name($value);
65 while (file_exists($_upload_dir . DIRECTORY_SEPARATOR . $file_upoalded[$key])) {
66 $fileNameWithSeparator = BITFORMS_BF_SEPARATOR . $fileNameCount;
67 $file_upoalded[$key] = sanitize_file_name(preg_replace('/(.[a-z A-Z 0-9]+)$/', "{$fileNameWithSeparator}$1", $value));
68 $fileNameCount = $fileNameCount + 1;
69 if (11 === $fileNameCount) {
70 break;
71 }
72 }
73 $move_status = \move_uploaded_file($file_details['tmp_name'][$key], $_upload_dir . DIRECTORY_SEPARATOR . $file_upoalded[$key]);
74 if (!$move_status) {
75 unset($file_upoalded[$key]);
76 }
77 }
78 }
79 } else {
80 if (!empty($file_details['name'])) {
81 $fileNameCount = 1;
82 $file_upoalded[0] = sanitize_file_name($file_details['name']);
83 while (file_exists($_upload_dir . DIRECTORY_SEPARATOR . $file_upoalded[0])) {
84 $fileNameWithSeparator = BITFORMS_BF_SEPARATOR . $fileNameCount;
85 $file_upoalded[0] = sanitize_file_name(preg_replace('/(.[a-z A-Z 0-9]+)$/', "{$fileNameWithSeparator}$1", $file_details['name']));
86 $fileNameCount = $fileNameCount + 1;
87 if (11 === $fileNameCount) {
88 break;
89 }
90 }
91 $move_status = \move_uploaded_file($file_details['tmp_name'], $_upload_dir . DIRECTORY_SEPARATOR . $file_upoalded[0]);
92 if (!$move_status) {
93 unset($file_upoalded[0]);
94 }
95 }
96 }
97 return $file_upoalded;
98 }
99
100 public function deleteFiles($form_id, $entry_id, $files)
101 {
102 $_upload_dir = self::getEntriesFileUploadDir($form_id, $entry_id);
103 foreach ($files as $name) {
104 wp_delete_file($_upload_dir . DIRECTORY_SEPARATOR . $name);
105 }
106 }
107
108 public static function getFileUploadError($code)
109 {
110 $errors = [
111 0 => __('Unknown upload error', 'bit-form'),
112 1 => __('The uploaded file exceeds the upload_max_filesize directive in php.ini.', 'bit-form'),
113 2 => __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', 'bit-form'),
114 3 => __('The uploaded file was only partially uploaded.', 'bit-form'),
115 4 => __('No file was uploaded.', 'bit-form'),
116 6 => __('Missing a temporary folder.', 'bit-form'),
117 7 => __('Failed to write file to disk.', 'bit-form'),
118 8 => __('A PHP extension stopped the file upload.', 'bit-form'),
119 ];
120 return $errors[$code];
121 }
122
123 public static function fileCopy($tmpdir, $destinationDir, $file)
124 {
125 $tmpFile = $tmpdir . DIRECTORY_SEPARATOR . $file;
126 $newFile = $destinationDir . DIRECTORY_SEPARATOR . $file;
127 if (file_exists($tmpFile)) {
128 copy($tmpFile, $newFile);
129 }
130 }
131
132 public static function tempDirToUploadDir($submitted_data, $fields, $formId, $entryID)
133 {
134 $upload_dir = wp_upload_dir();
135 $tempDir = $upload_dir['basedir'] . '/bitforms/temp';
136 $destinationDir = self::getEntriesFileUploadDir($formId, $entryID) . DIRECTORY_SEPARATOR;
137 self::createIndexFile($destinationDir);
138
139 foreach ($submitted_data as $key => $data) {
140 if (isset($fields[$key]) && 'advanced-file-up' === $fields[$key]['type']) {
141 $files = $data;
142 $fldData = $submitted_data[$key];
143 $files = explode(',', $fldData);
144 if (is_array($files) && count($files) > 0) {
145 foreach ($files as $file) {
146 self::fileCopy($tempDir, $destinationDir, trim($file));
147 }
148 } else {
149 self::fileCopy($tempDir, $destinationDir, trim($files));
150 }
151 if (!empty($files)) {
152 $submitted_data[$key] = $files;
153 }
154 }
155 }
156 array_map('unlink', array_filter(
157 (array) array_merge(glob("$tempDir/*"))
158 ));
159
160 return $submitted_data;
161 }
162
163 private function getByteSizeByUnit($sizeString)
164 {
165 // split 2MB into 2 and MB
166 $size = preg_replace('/[^0-9\.]/', '', $sizeString);
167 $unit = preg_replace('/[^a-zA-Z]/', '', $sizeString);
168 $unit = strtolower($unit);
169 if ('kb' === $unit) {
170 return $size * 1024;
171 } elseif ('mb' === $unit) {
172 return $size * 1024 * 1024;
173 } elseif ('gb' === $unit) {
174 return $size * 1024 * 1024 * 1024;
175 } else {
176 return $size;
177 }
178 }
179
180 public function validation($field_key, $file_details, $form_id)
181 {
182 if (!function_exists('wp_check_filetype_and_ext')) {
183 require_once ABSPATH . 'wp-admin/includes/file.php';
184 }
185
186 $formManager = FormManager::getInstance($form_id);
187 $form_contents = $formManager->getFormContent();
188 $field_content_details = $form_contents->fields;
189 $fieldDetail = $field_content_details->{$field_key};
190 $fieldType = $fieldDetail->typ;
191 $maxSizeDetails = [];
192 $allowFileTypes = [];
193 $maxSize = null;
194 if ('file-up' === $fieldType) {
195 $allowFileTypes = !empty($fieldDetail->config->allowedFileType) ? $fieldDetail->config->allowedFileType : [];
196 if (!empty($fieldDetail->config->allowMaxSize)) {
197 if (!empty($fieldDetail->config->maxSize)) {
198 $maxSizeDetails['maxSize'] = $fieldDetail->config->maxSize . $fieldDetail->config->sizeUnit;
199 }
200 if (!empty($fieldDetail->config->isItTotalMax)) {
201 $maxSizeDetails['maxTotalFileSize'] = $fieldDetail->config->maxSize . $fieldDetail->config->sizeUnit;
202 }
203 }
204 if (!empty($allowFileTypes)) {
205 $allowFileTypes = explode(',', $allowFileTypes);
206 }
207 } elseif ('advanced-file-up' === $fieldType) {
208 $allowFileTypes = !empty($fieldDetail->config->allowFileTypeValidation) ? $fieldDetail->config->acceptedFileTypes : [];
209 if (!empty($fieldDetail->config->allowFileSizeValidation)) {
210 if (!empty($fieldDetail->config->maxFileSize)) {
211 $maxSizeDetails['maxSize'] = $fieldDetail->config->maxFileSize;
212 }
213 if (!empty($fieldDetail->config->maxTotalFileSize)) {
214 $maxSizeDetails['maxTotalFileSize'] = $fieldDetail->config->maxTotalFileSize;
215 }
216 }
217 }
218 if (!empty($maxSizeDetails['maxSize'])) {
219 $maxSize = $this->getByteSizeByUnit($maxSizeDetails['maxSize']);
220 }
221 $maxTotalFileSize = null;
222 if (!empty($maxSizeDetails['maxTotalFileSize'])) {
223 $maxTotalFileSize = $this->getByteSizeByUnit($maxSizeDetails['maxTotalFileSize']);
224 }
225
226 if ($formManager->isRepeatedField($field_key)) {
227 foreach ($file_details['name'] as $rowIndex => $file) {
228 if (!empty($file)) {
229 $fileDetails = [
230 'name' => $file,
231 'type' => $file_details['type'][$rowIndex],
232 'tmp_name' => $file_details['tmp_name'][$rowIndex],
233 'error' => $file_details['error'][$rowIndex],
234 'size' => $file_details['size'][$rowIndex],
235 ];
236 $validateState = $this->validateFileInfo($fieldType, $fileDetails, $allowFileTypes, $maxSize, $maxTotalFileSize);
237 if (!empty($validateState) && !empty($validateState['message'])) {
238 return $validateState;
239 }
240 }
241 }
242 } else {
243 return $this->validateFileInfo($fieldType, $file_details, $allowFileTypes, $maxSize, $maxTotalFileSize);
244 }
245 return [];
246 }
247
248 private function validateFileInfo($fieldType, $file_details, $allowFileTypes, $maxSize, $maxTotalFileSize)
249 {
250 $errorMessage = [
251 'message' => '',
252 'error_type'=> '',
253 ];
254 if (is_array($file_details['name'])) {
255 $totalSize = 0;
256 foreach ($file_details['name'] as $key => $file) {
257 if (!empty($file)) {
258 $fileInfo = [
259 'name' => $file,
260 'type' => $file_details['type'][$key],
261 'tmp_name' => $file_details['tmp_name'][$key],
262 'error' => $file_details['error'][$key],
263 'size' => $file_details['size'][$key],
264 ];
265 $totalSize += $fileInfo['size'];
266 $validateState = $this->validateSingleFile($fieldType, $fileInfo, $allowFileTypes, $maxSize);
267 if (!empty($validateState)) {
268 return $validateState;
269 }
270 }
271 }
272 if (isset($maxTotalFileSize) && !is_null($maxTotalFileSize) && $totalSize > $maxTotalFileSize) {
273 $errorMessage['message'] = __('Total File size is too large', 'bit-form');
274 $errorMessage['error_type'] = 'file_size_error';
275 return $errorMessage;
276 }
277 } else {
278 $validateState = $this->validateSingleFile($fieldType, $file_details, $allowFileTypes, $maxSize);
279 if (!empty($validateState)) {
280 return $validateState;
281 }
282 }
283
284 return $errorMessage;
285 }
286
287 private function validateSingleFile($fieldType, &$file, $allowTypes, $maxSize = null)
288 {
289 // 0) Basic sanity & transport integrity
290 if (!is_array($file) || empty($file['tmp_name'])) {
291 // return ['message' => __('No file uploaded.', 'bit-form'), 'error_type' => 'file_missing'];
292 return null;
293 }
294 if (!isset($file['error']) || UPLOAD_ERR_OK !== $file['error']) {
295 return ['message' => __('Upload failed', 'bit-form'), 'error_type' => 'file_upload_error'];
296 }
297 if (!is_uploaded_file($file['tmp_name'])) {
298 return ['message' => __('Untrusted upload source', 'bit-form'), 'error_type' => 'file_upload_error'];
299 }
300 if (!is_file($file['tmp_name']) || !is_readable($file['tmp_name'])) {
301 return ['message' => __('Temporary file not accessible', 'bit-form'), 'error_type' => 'file_upload_error'];
302 }
303
304 $fileName = sanitize_file_name((string)($file['name'] ?? ''));
305 if ('' === $fileName) {
306 return ['message' => __('Empty filename', 'bit-form'), 'error_type' => 'file_type_error'];
307 }
308
309 // 1) Enforce max size (header + actual)
310 $onDiskSize = @filesize($file['tmp_name']);
311 if (false === $onDiskSize) {
312 return ['message' => __('Cannot read file size', 'bit-form'), 'error_type' => 'file_upload_error'];
313 }
314 if (!empty($maxSize) && $onDiskSize > $maxSize) {
315 return ['message' => __('File size is too large', 'bit-form'), 'error_type' => 'file_size_error'];
316 }
317
318 // 2) Determine ext + MIME using WP + finfo
319 $wpCheck = wp_check_filetype_and_ext($file['tmp_name'], $fileName); // ['ext'=>'jpg','type'=>'image/jpeg']
320 $fileExtension = strtolower((string)(empty($wpCheck['ext']) ? pathinfo($fileName, PATHINFO_EXTENSION) : $wpCheck['ext']));
321 $wpExt = strtolower((string)(empty($wpCheck['ext']) ? $fileExtension : $wpCheck['ext']));
322 $wpType = strtolower((string)($wpCheck['type'] ?? ''));
323 $fi = function_exists('finfo_open') ? @finfo_open(FILEINFO_MIME_TYPE) : false;
324 $detectedMime = $fi ? @finfo_file($fi, $file['tmp_name']) : false;
325 if ($fi) {
326 @finfo_close($fi);
327 }
328 if (!$detectedMime && function_exists('mime_content_type')) {
329 $detectedMime = @mime_content_type($file['tmp_name']);
330 }
331 if (!$detectedMime) {
332 $detectedMime = '' !== $wpType ? $wpType : 'application/octet-stream';
333 }
334 $detectedMime = strtolower(trim($detectedMime));
335
336 // Hard-block risky types regardless
337 // 3) Block obvious executable types regardless of allow list
338 $disallowedMimes = apply_filters('bitform_filter_upload_disallowed_mimes', [
339 'application/x-php', 'text/x-php', 'application/x-msdownload', 'application/x-msdos-program',
340 'application/x-sh', 'application/x-csh', 'text/x-shellscript', 'application/java-archive'
341 ]);
342 $denyExt = apply_filters('bitform_filter_upload_denied_extensions', ['php', 'phtml', 'phar', 'htaccess', 'html', 'js', 'exe', 'sh', 'bat', 'cmd']);
343 if (in_array($detectedMime, $disallowedMimes, true) || in_array($fileExtension, $denyExt, true)) {
344 return ['message' => __('This file type is not allowed', 'bit-form'), 'error_type' => 'file_type_error'];
345 }
346
347 // 4) Normalize allowlist: support both extensions (.jpg or jpg) and MIME types
348 // --- ALLOWLIST NORMALIZATION (extensions + MIME) ---
349 $normalizedAllow = array_values(array_unique(array_map(static function ($t) {
350 return strtolower(trim((string)$t));
351 }, (array)$allowTypes)));
352
353 $allowExts = [];
354 $allowMimes = [];
355 foreach ($normalizedAllow as $t) {
356 if ('' === $t) {
357 continue;
358 }
359 if (false !== strpos($t, '/')) {
360 // looks like a MIME
361 $allowMimes[] = $t;
362 } else {
363 // extension: may include leading dot; normalize without dot
364 $allowExts[] = ltrim($t, '.');
365 }
366 }
367
368 $allowExts = array_values(array_unique($allowExts));
369 $allowMimes = array_values(array_unique($allowMimes));
370
371 $hasAllowlist = (!empty($allowExts) || !empty($allowMimes));
372 $extMatch = in_array($fileExtension, $allowExts, true);
373 $mimeMatch = in_array($detectedMime, $allowMimes, true);
374
375 // 5) Require BOTH a legit WP mapping AND a match to the allowlist
376 $wpOk = ('' !== $wpExt && '' !== $wpType);
377
378 if ($hasAllowlist) {
379 if (!($extMatch || $mimeMatch)) {
380 return ['message' => __('File type is not allowed', 'bit-form'), 'error_type' => 'file_type_error'];
381 }
382 } else {
383 if (!$wpOk) {
384 return ['message' => __('File type is not allowed', 'bit-form'), 'error_type' => 'file_type_error'];
385 }
386 }
387
388 // 5) Special SVG handling (by MIME, not just extension)
389 if ('svg' === $fileExtension || 'image/svg+xml' === $detectedMime || 'image/svg+xml' === $wpType) {
390 if ('image/svg+xml' !== $detectedMime) {
391 return ['message' => __('Invalid SVG', 'bit-form'), 'error_type' => 'file_type_error'];
392 }
393
394 $dirty = file_get_contents($file['tmp_name']);
395 $svg_sanitizer = new Sanitizer();
396 $clean = $svg_sanitizer->sanitize($dirty);
397 if (false === $clean) {
398 return ['message' => __('SVG file is not valid', 'bit-form'), 'error_type' => 'file_type_error'];
399 }
400 file_put_contents($file['tmp_name'], $clean, LOCK_EX);
401 // Re-check size post-sanitize
402 if (!empty($maxSize) && filesize($file['tmp_name']) > $maxSize) {
403 return ['message' => __('File size is too large after sanitation', 'bit-form'), 'error_type' => 'file_size_error'];
404 }
405 }
406
407 // --- Allow developer to make a final decision override (optional) ---
408 $final = apply_filters('bit_form_upload_allow_file', true, [
409 'file_name' => $fileName,
410 'extension' => $fileExtension,
411 'detected_mime' => $detectedMime,
412 'wp_ext' => $wpExt,
413 'wp_type' => $wpType,
414 'allow_exts' => $allowExts,
415 'allow_mimes' => $allowMimes,
416 'has_allowlist' => $hasAllowlist,
417 ]);
418 if (true !== $final) {
419 // If a dev returns a WP_Error, you could extract message/type; here we just block.
420 return ['message' => __('File not allowed by policy', 'bit-form'), 'error_type' => 'file_policy_block'];
421 }
422 return null; // success
423 }
424
425 public static function deleteIsFileExists($path)
426 {
427 if (file_exists($path)) {
428 wp_delete_file($path);
429 }
430 }
431
432 public static function getEntriesFileUploadDir($form_id, $entry_id)
433 {
434 $uploadDir = rtrim(BITFORMS_UPLOAD_DIR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $form_id . DIRECTORY_SEPARATOR;
435 $previousEntryDirectory = $uploadDir . $entry_id;
436 if (is_dir($previousEntryDirectory)) {
437 return $previousEntryDirectory;
438 }
439 $encrypted_directory = Helpers::getEncryptedEntryId($entry_id);
440 return $uploadDir . $encrypted_directory;
441 }
442
443 private static function replaceDocumentRoot($path)
444 {
445 $relativePath = str_replace(ABSPATH, '', $path); // Remove absolute server path
446 return site_url($relativePath); // Prepend with domain
447 }
448
449 public static function getEntriesFileUploadURL($form_id, $entry_id)
450 {
451 $documentRoot = self::getEntriesFileUploadDir($form_id, $entry_id);
452 $url = self::replaceDocumentRoot($documentRoot);
453 return $url;
454 }
455
456 public static function createIndexFile($directory)
457 {
458 if (wp_mkdir_p($directory)) {
459 $indexFilePath = rtrim($directory, '/') . '/index.php';
460 if (!file_exists($indexFilePath)) {
461 try {
462 if (false === file_put_contents($indexFilePath, "<?php\n// No direct access allowed.")) {
463 throw new \Exception("Failed to create index.php in $directory");
464 }
465 } catch (\Exception $e) {
466 Log::debug_log('File creation Failed:' . $e->getMessage()); // Log the error for debugging
467 }
468 }
469 }
470 return false;
471 }
472
473 public static function processRepeaterAttachment($repeaterKey, $fileKey, $fieldValue, $basePath, &$attachments)
474 {
475 if (!isset($fieldValue[$repeaterKey]) || !is_array($fieldValue[$repeaterKey])) {
476 return;
477 }
478
479 foreach ($fieldValue[$repeaterKey] as $repeaterRow) {
480 if (!isset($repeaterRow[$fileKey]) || empty($repeaterRow[$fileKey])) {
481 continue;
482 }
483
484 $fileValue = $repeaterRow[$fileKey];
485 self::addAttachmentFiles($fileValue, $basePath, $attachments);
486 }
487 }
488
489 public static function processRegularAttachment($fileKey, $fieldValue, $basePath, &$attachments)
490 {
491 if (!isset($fieldValue[$fileKey]) || empty($fieldValue[$fileKey])) {
492 return;
493 }
494
495 $fileValue = $fieldValue[$fileKey];
496 self::addAttachmentFiles($fileValue, $basePath, $attachments);
497 }
498
499 private static function addAttachmentFiles($fileValue, $basePath, &$attachments)
500 {
501 if (is_array($fileValue)) {
502 foreach ($fileValue as $singleFile) {
503 $filePath = $basePath . $singleFile;
504 if (is_readable($filePath)) {
505 $attachments[] = $filePath;
506 }
507 }
508 } else {
509 $filePath = $basePath . $fileValue;
510 if (is_readable($filePath)) {
511 $attachments[] = $filePath;
512 }
513 }
514 }
515
516 /**
517 * Return file type by checking with mime type
518 * @param string $mime
519 * @return string
520 */
521 public static function getFileTypeByMime(string $mime)
522 {
523 $mime = strtolower($mime);
524
525 if (preg_match('/^image\//', $mime)) {
526 return 'image';
527 }
528
529 $compressed = [
530 'application/zip',
531 'application/x-rar-compressed',
532 'application/x-7z-compressed',
533 'application/gzip',
534 'application/x-tar',
535 'application/x-gtar',
536 'application/x-bzip2',
537 'application/x-archive',
538 'application/vnd.debian.binary-package',
539 ];
540 if (in_array($mime, $compressed, true)) {
541 return 'compressed';
542 }
543
544 $presentation = [
545 'application/vnd.ms-powerpoint',
546 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
547 'application/vnd.oasis.opendocument.presentation',
548 'application/vnd.apple.keynote',
549 ];
550 if (in_array($mime, $presentation, true)) {
551 return 'presentation';
552 }
553
554 $document = [
555 'application/pdf',
556 'application/msword',
557 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
558 'application/rtf',
559 'text/plain',
560 'application/vnd.oasis.opendocument.text',
561 'application/x-tex',
562 'text/rtf',
563 ];
564 if (in_array($mime, $document, true)) {
565 return 'document';
566 }
567
568 $data = [
569 'text/csv',
570 'application/xml',
571 'text/xml',
572 'application/sql',
573 'application/vnd.ms-excel',
574 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
575 'application/x-sqlite3',
576 'application/octet-stream', // generic binary (could be db files)
577 ];
578 if (in_array($mime, $data, true)) {
579 return 'data';
580 }
581
582 if (preg_match('/^audio\//', $mime)) {
583 return 'audio';
584 }
585
586 if (preg_match('/^video\//', $mime)) {
587 return 'video';
588 }
589
590 return 'other';
591 }
592
593 /**
594 * Return file type by checking with extension
595 * @param string $extension
596 * @return string
597 */
598 public static function getFileTypeByExtension($extension)
599 {
600 switch (strtolower($extension)) {
601 case 'xbm':
602 case 'tif':
603 case 'pjp':
604 case 'pjpeg':
605 case 'svgz':
606 case 'jpg':
607 case 'jpeg':
608 case 'ico':
609 case 'tiff':
610 case 'gif':
611 case 'svg':
612 case 'bmp':
613 case 'png':
614 case 'jfif':
615 case 'webp':
616 return 'image';
617
618 case '7z':
619 case 'arj':
620 case 'deb':
621 case 'pkg':
622 case 'rar':
623 case 'rpm':
624 case 'gz':
625 case 'z':
626 case 'zip':
627 return 'compressed';
628
629 case 'key':
630 case 'odp':
631 case 'pps':
632 case 'ppt':
633 case 'pptx':
634 return 'presentation';
635
636 case '_rf_':
637 case 'doc':
638 case 'docx':
639 case 'odt':
640 case 'pdf':
641 case 'rtf':
642 case 'tex':
643 case 'txt':
644 case 'wks':
645 case 'wps':
646 case 'wpd':
647 return 'document';
648
649 case 'csv':
650 case 'dat':
651 case 'db':
652 case 'dbf':
653 case 'log':
654 case 'mdb':
655 case 'sav':
656 case 'sql':
657 case 'tar':
658 case 'sqlite':
659 case 'xml':
660 return 'data';
661
662 case 'opus':
663 case 'flac':
664 case 'webm':
665 case 'weba':
666 case 'wav':
667 case 'ogg':
668 case 'm4a':
669 case 'mp3':
670 case 'oga':
671 case 'mid':
672 case 'amr':
673 case 'aiff':
674 case 'wma':
675 case 'au':
676 case 'acc':
677 case 'wpl':
678 return 'audio';
679
680 case 'ogm':
681 case 'wmv':
682 case 'mpg':
683 case 'ogv':
684 case 'mov':
685 case 'asx':
686 case 'mpeg':
687 case 'mp4':
688 case 'm4v':
689 case 'avi':
690 case '3gp':
691 case 'flv':
692 case 'mkv':
693 case 'swf':
694 return 'video';
695 default:
696 return 'other';
697 }
698 }
699 }
700