FileSystem::write()   D
last analyzed

Complexity

Conditions 10
Paths 37

Size

Total Lines 44
Code Lines 28

Duplication

Lines 16
Ratio 36.36 %
Metric Value
dl 16
loc 44
rs 4.8197
cc 10
eloc 28
nc 37
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Scabbia2 Helpers Component
4
 * https://github.com/eserozvataf/scabbia2
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 *
9
 * @link        https://github.com/eserozvataf/scabbia2-helpers for the canonical source repository
10
 * @copyright   2010-2016 Eser Ozvataf. (http://eser.ozvataf.com/)
11
 * @license     http://www.apache.org/licenses/LICENSE-2.0 - Apache License, Version 2.0
12
 */
13
14
namespace Scabbia\Helpers;
15
16
use DirectoryIterator;
17
use UnexpectedValueException;
18
19
/**
20
 * A bunch of utility methods for file system functionality
21
 *
22
 * @package     Scabbia\Helpers
23
 * @author      Eser Ozvataf <[email protected]>
24
 * @since       1.0.0
25
 *
26
 * #DISABLED# @scabbia-compile
27
 */
28
class FileSystem
29
{
30
    /** @type int NONE               no flag */
31
    const NONE = 0;
32
    /** @type int ENCRYPTION         use encryption */
33
    const ENCRYPTION = 1;
34
    /** @type int USE_JSON           use json for serialization */
35
    const USE_JSON = 2;
36
    /** @type int APPEND             append to file */
37
    const APPEND = 4;
38
    /** @type int LOCK_NONBLOCKING   lock file with nonblocking lock */
39
    const LOCK_NONBLOCKING = 8;
40
    /** @type int LOCK_SHARE         lock file with share lock */
41
    const LOCK_SHARE = 16;
42
    /** @type int LOCK_EXCLUSIVE     lock file with exclusive lock */
43
    const LOCK_EXCLUSIVE = 32;
44
45
46
    /**
47
     * Default variables for io functionality
48
     *
49
     * @type array $defaults array of default variables
50
     */
51
    public static $defaults = [
52
        "pathSeparator" => DIRECTORY_SEPARATOR,
53
        "fileReadBuffer" => 4096,
54
        "keyphase" => "scabbia_default"
55
    ];
56
57
58
    /**
59
     * Constructor to prevent new instances of FileSystem class
60
     *
61
     * @return FileSystem
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
62
     */
63
    final private function __construct()
64
    {
65
    }
66
67
    /**
68
     * Clone method to prevent duplication of FileSystem class
69
     *
70
     * @return FileSystem
71
     */
72
    final private function __clone()
73
    {
74
    }
75
76
    /**
77
     * Unserialization method to prevent restoration of FileSystem class
78
     *
79
     * @return FileSystem
80
     */
81
    final private function __wakeup()
82
    {
83
    }
84
85
    /**
86
     * Sets the default variables
87
     *
88
     * @param array $uDefaults variables to be set
89
     *
90
     * @return void
91
     */
92
    public static function setDefaults($uDefaults)
93
    {
94
        self::$defaults = $uDefaults + self::$defaults;
95
    }
96
97
    /**
98
     * Encrypts the plaintext with the given key
99
     *
100
     * @param string    $uString    the plaintext
101
     * @param string    $uKey       the key
102
     *
103
     * @return string   ciphertext
104
     */
105 View Code Duplication
    public static function encrypt($uString, $uKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
    {
107
        $tResult = "";
108
109
        for ($i = 1, $tCount = strlen($uString); $i <= $tCount; $i++) {
110
            $tChar = substr($uString, $i - 1, 1);
111
            $tKeyChar = substr($uKey, ($i % strlen($uKey)) - 1, 1);
112
            $tResult .= chr(ord($tChar) + ord($tKeyChar));
113
        }
114
115
        return $tResult;
116
    }
117
118
    /**
119
     * Decrypts the ciphertext with the given key
120
     *
121
     * @param string    $uString    the ciphertext
122
     * @param string    $uKey       the key
123
     *
124
     * @return string   plaintext
125
     */
126 View Code Duplication
    public static function decrypt($uString, $uKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
127
    {
128
        $tResult = "";
129
130
        for ($i = 1, $tCount = strlen($uString); $i <= $tCount; $i++) {
131
            $tChar = substr($uString, $i - 1, 1);
132
            $tKeyChar = substr($uKey, ($i % strlen($uKey)) - 1, 1);
133
            $tResult .= chr(ord($tChar) - ord($tKeyChar));
134
        }
135
136
        return $tResult;
137
    }
138
139
    /**
140
     * Reads from a file
141
     *
142
     * @param string    $uPath      the file path
143
     * @param int       $uFlags     flags
144
     *
145
     * @return bool|string the file content
146
     */
147
    public static function read($uPath, $uFlags = self::LOCK_SHARE)
148
    {
149
        $tHandle = fopen($uPath, "r", false);
150
        if ($tHandle === false) {
151
            return false;
152
        }
153
154 View Code Duplication
        if (($uFlags & self::LOCK_NONBLOCKING) === self::LOCK_NONBLOCKING) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
            $tLockFlag = LOCK_NB;
156
        } elseif (($uFlags & self::LOCK_SHARE) === self::LOCK_SHARE) {
157
            $tLockFlag = LOCK_SH;
158
        } elseif (($uFlags & self::LOCK_EXCLUSIVE) === self::LOCK_EXCLUSIVE) {
159
            $tLockFlag = LOCK_EX;
160
        } else {
161
            $tLockFlag = false;
162
        }
163
164 View Code Duplication
        if ($tLockFlag !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
            if (flock($tHandle, $tLockFlag) === false) {
166
                fclose($tHandle);
167
168
                return false;
169
            }
170
        }
171
172
        $tContent = stream_get_contents($tHandle);
173
        if ($tLockFlag !== false) {
174
            flock($tHandle, LOCK_UN);
175
        }
176
177
        fclose($tHandle);
178
179
        if (($uFlags & self::ENCRYPTION) === self::ENCRYPTION) {
180
            return self::decrypt($tContent, self::$defaults["keyphase"]);
181
        }
182
183
        return $tContent;
184
    }
185
186
    /**
187
     * Writes to a file
188
     *
189
     * @param string    $uPath      the file path
190
     * @param string    $uContent   the file content
191
     * @param int       $uFlags     flags
192
     *
193
     * @return bool
194
     */
195
    public static function write($uPath, $uContent, $uFlags = self::LOCK_EXCLUSIVE)
196
    {
197
        $tHandle = fopen(
198
            $uPath,
199
            (($uFlags & self::APPEND) === self::APPEND) ? "a" : "w",
200
            false
201
        );
202
        if ($tHandle === false) {
203
            return false;
204
        }
205
206 View Code Duplication
        if (($uFlags & self::LOCK_NONBLOCKING) === self::LOCK_NONBLOCKING) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
207
            $tLockFlag = LOCK_NB;
208
        } elseif (($uFlags & self::LOCK_SHARE) === self::LOCK_SHARE) {
209
            $tLockFlag = LOCK_SH;
210
        } elseif (($uFlags & self::LOCK_EXCLUSIVE) === self::LOCK_EXCLUSIVE) {
211
            $tLockFlag = LOCK_EX;
212
        } else {
213
            $tLockFlag = false;
214
        }
215
216 View Code Duplication
        if ($tLockFlag !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
            if (flock($tHandle, $tLockFlag) === false) {
218
                fclose($tHandle);
219
220
                return false;
221
            }
222
        }
223
224
        if (($uFlags & self::ENCRYPTION) === self::ENCRYPTION) {
225
            fwrite($tHandle, self::encrypt($tContent, self::$defaults["keyphase"]));
0 ignored issues
show
Bug introduced by
The variable $tContent does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
226
        } else {
227
            fwrite($tHandle, $uContent);
228
        }
229
230
        fflush($tHandle);
231
        if ($tLockFlag !== false) {
232
            flock($tHandle, LOCK_UN);
233
        }
234
235
        fclose($tHandle);
236
237
        return true;
238
    }
239
240
    /**
241
     * Reads from a serialized file
242
     *
243
     * @param string    $uPath      the file path
244
     * @param int       $uFlags     flags
245
     *
246
     * @return bool|mixed   the unserialized object
247
     */
248
    public static function readSerialize($uPath, $uFlags = self::LOCK_SHARE)
249
    {
250
        $tContent = self::read($uPath, $uFlags);
251
252
        //! ambiguous return value
253
        if ($tContent === false) {
254
            return false;
255
        }
256
257
        if (($uFlags & self::USE_JSON) === self::USE_JSON) {
258
            return json_decode($tContent);
259
        }
260
261
        return unserialize($tContent);
262
    }
263
264
    /**
265
     * Serializes an object into a file
266
     *
267
     * @param string        $uPath      the file path
268
     * @param string        $uContent   the file content
269
     * @param int           $uFlags     flags
270
     *
271
     * @return bool
272
     */
273
    public static function writeSerialize($uPath, $uContent, $uFlags = self::LOCK_EXCLUSIVE)
274
    {
275
        if (($uFlags & self::USE_JSON) === self::USE_JSON) {
276
            return self::write($uPath, json_encode($uContent), $uFlags);
277
        }
278
279
        return self::write($uPath, serialize($uContent), $uFlags);
280
    }
281
282
    /**
283
     * Exports an object into a php file
284
     *
285
     * @param string        $uPath      the file path
286
     * @param string        $uContent   the file content
287
     *
288
     * @return bool
289
     */
290
    public static function writePhpFile($uPath, $uContent)
291
    {
292
        return self::write(
293
            $uPath,
294
            "<" . "?php return " . var_export($uContent, true) . ";\n"
295
        );
296
    }
297
298
    /**
299
     * Checks the path contains invalid chars or not
300
     *
301
     * @param string $uPath the path
302
     *
303
     * @return bool true if the path contains invalid chars
304
     */
305
    public static function checkInvalidPathChars($uPath)
306
    {
307
        if (strncasecmp(PHP_OS, "WIN", 3) !== 0) {
308
            if (strncasecmp($uPath, "\\\\", 2) === 0) {
309
                return false;
310
            }
311
        }
312
313
        for ($i = strlen($uPath) - 1; $i >= 0; $i--) {
314
            if (ord($uPath[$i]) < 32 || $uPath[$i] === "<" || $uPath[$i] === ">" || $uPath[$i] === "|" ||
315
                $uPath[$i] === "\"") {
316
                return false;
317
            }
318
        }
319
320
        return true;
321
    }
322
323
    /**
324
     * Checks the path is path rooted or not
325
     *
326
     * @param string $uPath the path
327
     *
328
     * @throws UnexpectedValueException if path contains invalid chars
329
     * @return bool true if the path is rooted
330
     */
331
    public static function isPathRooted($uPath)
332
    {
333
        if (!self::checkInvalidPathChars($uPath)) {
334
            // TODO exception
335
            throw new UnexpectedValueException("");
336
        }
337
338
        $tLength = strlen($uPath);
339
        if (strncasecmp(PHP_OS, "WIN", 3) === 0) {
340 View Code Duplication
            if (($tLength >= 1 && ($uPath[0] === "\\" || $uPath[0] === "/")) ||
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
341
                ($tLength >= 2 && $uPath[1] === ":")) {
342
                return true;
343
            }
344
        } else {
345
            if ($tLength >= 1 && $uPath[0] === "/") {
346
                return true;
347
            }
348
        }
349
350
        return false;
351
    }
352
353
    /**
354
     * Checks the path is path relative or not
355
     *
356
     * @param string $uPath the path
357
     *
358
     * @throws UnexpectedValueException if path contains invalid chars
359
     * @return bool true if the path is relative
360
     */
361
    public static function isPathRelative($uPath)
362
    {
363
        if (!self::checkInvalidPathChars($uPath)) {
364
            // TODO exception
365
            throw new UnexpectedValueException("");
366
        }
367
368
        $tLength = strlen($uPath);
369
        if (strncasecmp(PHP_OS, "WIN", 3) === 0) {
370
            if (strncasecmp($uPath, "\\\\", 2) === 0) {
371
                return false;
372
            }
373
374 View Code Duplication
            if ($tLength >= 3 && ctype_alpha($uPath[0]) && $uPath[1] === ":" &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
375
                ($uPath[2] === "\\" || $uPath[2] === "/")) {
376
                return false;
377
            }
378
        } else {
379
            if ($tLength >= 1 && $uPath[0] === "/") {
380
                return false;
381
            }
382
        }
383
384
        return true;
385
    }
386
387
    /**
388
     * Combines given paths into a single path string
389
     *
390
     * @param array $uPaths paths
391
     *
392
     * @return null|string combined path
393
     */
394
    public static function combinePaths(...$uPaths)
395
    {
396
        $tCombinedPath = null;
397
        $tTrimChars = (strncasecmp(PHP_OS, "WIN", 3) === 0) ? "\\/" : "/";
398
399
        for ($i = count($uPaths) - 1; $i >= 0; $i--) {
400
            $tPath = $uPaths[$i];
401
402
            if (($tPathLength = strlen($tPath)) === 0) {
403
                continue;
404
            }
405
406
            if ($tCombinedPath === null) {
407
                $tCombinedPath = $tPath;
408
            } elseif (strpos($tTrimChars, $tPath[$tPathLength - 1]) === false) {
409
                $tCombinedPath = $tPath . self::$defaults["pathSeparator"] . $tCombinedPath;
410
            } else {
411
                $tCombinedPath = $tPath . $tCombinedPath;
412
            }
413
414
            if (self::isPathRooted($tPath)) {
0 ignored issues
show
Documentation introduced by
$tPath is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
415
                break;
416
            }
417
        }
418
419
        return $tCombinedPath;
420
    }
421
422
    /**
423
     * Gets the number of lines of given file
424
     *
425
     * @param string $uPath the path
426
     *
427
     * @return int|bool line count
428
     */
429
    public static function getFileLineCount($uPath)
430
    {
431
        $tLineCount = 1;
432
433
        if (!is_readable($uPath) || ($tFileHandle = fopen($uPath, "r")) === false) {
434
            return false;
435
        }
436
437
        while (!feof($tFileHandle)) {
438
            $tLineCount += substr_count(fgets($tFileHandle, self::$defaults["fileReadBuffer"]), "\n");
439
        }
440
441
        fclose($tFileHandle);
442
443
        return $tLineCount;
444
    }
445
446
    /**
447
     * Determines the file is if readable and not expired
448
     *
449
     * @param string $uPath    the relative path
450
     * @param array  $uOptions options
451
     *
452
     * @return bool the result
453
     */
454
    public static function isReadable($uPath, array $uOptions = [])
455
    {
456
        if (!file_exists($uPath)) {
457
            return false;
458
        }
459
460
        $tLastMod = filemtime($uPath);
461
        if (isset($uOptions["ttl"]) && time() - $tLastMod > $uOptions["ttl"]) {
462
            return false;
463
        }
464
465
        if (isset($uOptions["newerthan"]) && $tLastMod >= $uOptions["newerthan"]) {
466
            return false;
467
        }
468
469
        return true;
470
    }
471
472
    /**
473
     * Reads the contents from cache file as long as it is not expired
474
     * If the file is expired, invokes callback method and caches output
475
     *
476
     * @param string      $uPath         the relative path
477
     * @param mixed       $uDefaultValue the default value
478
     * @param array       $uOptions      options
479
     *
480
     * @return mixed the result
481
     */
482
    public static function readFromCacheFile($uPath, $uDefaultValue, array $uOptions = [])
483
    {
484
        if (self::isReadable($uPath, $uOptions)) {
485
            return self::readSerialize($uPath);
486
        }
487
488
        if (is_a($uDefaultValue, "Closure")) {
489
            $uDefaultValue = call_user_func($uDefaultValue);
490
        }
491
492
        self::writeSerialize($uPath, $uDefaultValue);
493
        return $uDefaultValue;
494
    }
495
496
    /**
497
     * Gets the list of files matching the given pattern
498
     *
499
     * @param string        $uPath       path to be searched
500
     * @param string|null   $uPattern    pattern of files will be in the list
501
     * @param bool          $uRecursive  recursive search
502
     * @param bool          $uBasenames  use basenames only
503
     *
504
     * @return array the list of files
505
     */
506
    public static function getFiles($uPath, $uPattern = null, $uRecursive = true, $uBasenames = false)
507
    {
508
        $tArray = ["." => []];
509
        $tDir = new DirectoryIterator($uPath);
510
511
        foreach ($tDir as $tFile) {
512
            $tFileName = $tFile->getFilename();
513
514
            // $tFile->isDot()
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
515
            if ($tFileName[0] === ".") {
516
                continue;
517
            }
518
519
            if ($tFile->isDir()) {
520
                if ($uRecursive) {
521
                    $tArray[$tFileName] = self::getFiles("{$uPath}/{$tFileName}", $uPattern, true, $uBasenames);
522
                    continue;
523
                }
524
525
                $tArray[$tFileName] = null;
526
                continue;
527
            }
528
529
            if ($tFile->isFile() && ($uPattern === null || fnmatch($uPattern, $tFileName))) {
530
                if ($uBasenames) {
531
                    $tArray["."][] = pathinfo($tFileName, PATHINFO_FILENAME);
532
                } else {
533
                    $tArray["."][] = $tFileName;
534
                }
535
            }
536
        }
537
538
        return $tArray;
539
    }
540
541
    /**
542
     * Garbage collects the given path
543
     *
544
     * @param string  $uPath    path
545
     * @param array   $uOptions options
546
     *
547
     * @return void
548
     */
549
    public static function garbageCollect($uPath, array $uOptions = [])
550
    {
551
        $tDirectory = new DirectoryIterator($uPath);
552
553
        clearstatcache();
554
        foreach ($tDirectory as $tFile) {
555
            if (!$tFile->isFile()) {
556
                continue;
557
            }
558
559
            $tFileName = $tFile->getFilename();
560
561
            if (isset($uOptions["dotFiles"]) && $uOptions["dotFiles"] === false && $tFileName[0] === ".") {
562
                // $tFile->isDot()
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
563
                continue;
564
            }
565
566
            $tLastMod = $tFile->getMTime();
567
            if (isset($uOptions["ttl"]) && time() - $tLastMod <= $uOptions["ttl"]) {
568
                continue;
569
            }
570
571
            if (isset($uOptions["newerthan"]) && $tLastMod < $uOptions["newerthan"]) {
572
                continue;
573
            }
574
575
            unlink($tFile->getPathname());
576
        }
577
    }
578
579
    /**
580
     * Apply a function/method to every file matching the given pattern
581
     *
582
     * @param string        $uPath         path to be searched
583
     * @param string|null   $uPattern      pattern of files will be in the list
584
     * @param bool          $uRecursive    recursive search
585
     * @param callable      $uCallback     callback function/method
586
     * @param mixed         $uStateObject  parameters will be passed to function
587
     *
588
     * @return void
589
     */
590
    public static function getFilesWalk($uPath, $uPattern, $uRecursive, /* callable */ $uCallback, $uStateObject = null)
591
    {
592
        $tDir = new DirectoryIterator($uPath);
593
594
        foreach ($tDir as $tFile) {
595
            $tFileName = $tFile->getFilename();
596
597
            // $tFile->isDot()
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
598
            if ($tFileName[0] === ".") {
599
                continue;
600
            }
601
602
            if ($uRecursive && $tFile->isDir()) {
603
                self::getFilesWalk("{$uPath}/{$tFileName}", $uPattern, true, $uCallback, $uStateObject);
604
                continue;
605
            }
606
607
            if ($tFile->isFile() && ($uPattern === null || fnmatch($uPattern, $tFileName))) {
608
                call_user_func($uCallback, "{$uPath}/{$tFileName}", $uStateObject);
609
            }
610
        }
611
    }
612
613
    /**
614
     * Returns the mimetype of given extension
615
     *
616
     * @param string $uExtension extension of the file
617
     * @param string $uDefault   default mimetype if nothing found
618
     *
619
     * @return string
620
     */
621
    public static function getMimetype($uExtension, $uDefault = "application/octet-stream")
622
    {
623
        $tExtension = String::toLower($uExtension);
624
625
        if ($tExtension === "pdf") {
626
            return "application/pdf";
627
        } elseif ($tExtension === "exe") {
628
            return "application/octet-stream";
629
        } elseif ($tExtension === "dll") {
630
            return "application/x-msdownload";
631
        } elseif ($tExtension === "zip") {
632
            return "application/zip";
633
        } elseif ($tExtension === "rar") {
634
            return "application/x-rar-compressed";
635
        } elseif ($tExtension === "gz" || $tExtension === "gzip" || $tExtension === "tgz") {
636
            return "application/gzip";
637
        } elseif ($tExtension === "7z") {
638
            return "application/x-7z-compressed";
639
        } elseif ($tExtension === "tar") {
640
            return "application/x-tar";
641
        } elseif ($tExtension === "jar") {
642
            return "application/java-archive";
643
        } elseif ($tExtension === "deb") {
644
            return "application/x-deb";
645
        } elseif ($tExtension === "img") {
646
            return "application/x-apple-diskimage";
647
        } elseif ($tExtension === "csv") {
648
            return "text/csv";
649
        } elseif ($tExtension === "txt" || $tExtension === "text" || $tExtension === "log" || $tExtension === "ini") {
650
            return "text/plain";
651
        } elseif ($tExtension === "md") {
652
            return "text/x-markdown";
653
        } elseif ($tExtension === "rtf") {
654
            return "text/rtf";
655
        } elseif ($tExtension === "odt") {
656
            return "application/vnd.oasis.opendocument.text";
657
        } elseif ($tExtension === "ods") {
658
            return "application/vnd.oasis.opendocument.spreadsheet";
659
        } elseif ($tExtension === "smil") {
660
            return "application/smil";
661
        } elseif ($tExtension === "eml") {
662
            return "message/rfc822";
663
        } elseif ($tExtension === "xml" || $tExtension === "xsl") {
664
            return "text/xml";
665
        } elseif ($tExtension === "doc" || $tExtension === "dot" || $tExtension === "word") {
666
            return "application/msword";
667
        } elseif ($tExtension === "docx" || $tExtension === "dotx") {
668
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
669
        } elseif ($tExtension === "xls") {
670
            return "application/vnd.ms-excel";
671
        } elseif ($tExtension === "xl") {
672
            return "application/excel";
673
        } elseif ($tExtension === "xlsx") {
674
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
675
        } elseif ($tExtension === "ppt" || $tExtension === "pps") {
676
            return "application/vnd.ms-powerpoint";
677
        } elseif ($tExtension === "pptx") {
678
            return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
679
        } elseif ($tExtension === "ppsx") {
680
            return "application/vnd.openxmlformats-officedocument.presentationml.slideshow";
681
        } elseif ($tExtension === "ics") {
682
            return "text/calendar";
683
        } elseif ($tExtension === "vcf" || $tExtension === "vcard") {
684
            return "text/vcard";
685
        } elseif ($tExtension === "bmp") {
686
            return "image/x-ms-bmp";
687
        } elseif ($tExtension === "gif") {
688
            return "image/gif";
689
        } elseif ($tExtension === "png") {
690
            return "image/png";
691
        } elseif ($tExtension === "jpeg" || $tExtension === "jpe" || $tExtension === "jpg") {
692
            return "image/jpeg";
693
        } elseif ($tExtension === "webp") {
694
            return "image/webp";
695
        } elseif ($tExtension === "tif" || $tExtension === "tiff") {
696
            return "image/tiff";
697
        } elseif ($tExtension === "psd") {
698
            return "image/vnd.adobe.photoshop";
699
        } elseif ($tExtension === "ai" || $tExtension === "eps" || $tExtension === "ps") {
700
            return "application/postscript";
701
        } elseif ($tExtension === "cdr") {
702
            return "application/cdr";
703
        } elseif ($tExtension === "mid" || $tExtension === "midi") {
704
            return "audio/midi";
705
        } elseif ($tExtension === "mpga" || $tExtension === "mp2" || $tExtension === "mp3") {
706
            return "audio/mpeg";
707
        } elseif ($tExtension === "aif" || $tExtension === "aiff" || $tExtension === "aifc") {
708
            return "audio/x-aiff";
709
        } elseif ($tExtension === "wav") {
710
            return "audio/x-wav";
711
        } elseif ($tExtension === "aac") {
712
            return "audio/aac";
713
        } elseif ($tExtension === "ogg") {
714
            return "application/ogg";
715
        } elseif ($tExtension === "wma") {
716
            return "audio/x-ms-wma";
717
        } elseif ($tExtension === "m4a") {
718
            return "audio/x-m4a";
719
        } elseif ($tExtension === "mpeg" || $tExtension === "mpg" || $tExtension === "mpe") {
720
            return "video/mpeg";
721
        } elseif ($tExtension === "mp4" || $tExtension === "f4v") {
722
            return "application/mp4";
723
        } elseif ($tExtension === "qt" || $tExtension === "mov") {
724
            return "video/quicktime";
725
        } elseif ($tExtension === "avi") {
726
            return "video/x-msvideo";
727
        } elseif ($tExtension === "wmv") {
728
            return "video/x-ms-wmv";
729
        } elseif ($tExtension === "webm") {
730
            return "video/webm";
731
        } elseif ($tExtension === "swf") {
732
            return "application/x-shockwave-flash";
733
        } elseif ($tExtension === "flv") {
734
            return "video/x-flv";
735
        } elseif ($tExtension === "mkv") {
736
            return "video/x-matroska";
737
        } elseif ($tExtension === "htm" || $tExtension === "html" || $tExtension === "shtm" ||
738
            $tExtension === "shtml") {
739
            return "text/html";
740
        } elseif ($tExtension === "php") {
741
            return "application/x-httpd-php";
742
        } elseif ($tExtension === "phps") {
743
            return "application/x-httpd-php-source";
744
        } elseif ($tExtension === "css") {
745
            return "text/css";
746
        } elseif ($tExtension === "js") {
747
            return "application/x-javascript";
748
        } elseif ($tExtension === "json") {
749
            return "application/json";
750
        } elseif ($tExtension === "c" || $tExtension === "h") {
751
            return "text/x-c";
752
        } elseif ($tExtension === "py") {
753
            return "application/x-python";
754
        } elseif ($tExtension === "sh") {
755
            return "text/x-shellscript";
756
        } elseif ($tExtension === "pem") {
757
            return "application/x-x509-user-cert";
758
        } elseif ($tExtension === "crt" || $tExtension === "cer") {
759
            return "application/x-x509-ca-cert";
760
        } elseif ($tExtension === "pgp") {
761
            return "application/pgp";
762
        } elseif ($tExtension === "gpg") {
763
            return "application/gpg-keys";
764
        } elseif ($tExtension === "svg") {
765
            return "image/svg+xml";
766
        } elseif ($tExtension === "ttf") {
767
            return "application/x-font-ttf:";
768
        } elseif ($tExtension === "woff") {
769
            return "application/x-font-woff";
770
        }
771
772
        if (function_exists("finfo_open")) {
773
            $tFinfo = finfo_open(FILEINFO_MIME);
774
            $tMimetype = finfo_file($tFinfo, "test.{$uExtension}");
775
            finfo_close($tFinfo);
776
777
            return $tMimetype;
778
        }
779
780
        return $uDefault;
781
    }
782
}
783