FileHelper::findFiles()   C
last analyzed

Complexity

Conditions 13
Paths 42

Size

Total Lines 43
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 5.1234
c 0
b 0
f 0
cc 13
eloc 22
nc 42
nop 2

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
namespace Padosoft\Io;
4
5
/**
6
 * Helper Class FileHelper
7
 * @package Padosoft\Io
8
 */
9
class FileHelper
10
{
11
    public static $arrMimeType = array(
12
13
        'txt' => 'text/plain',
14
        'htm' => 'text/html',
15
        'html' => 'text/html',
16
        'php' => 'text/html',
17
        'css' => 'text/css',
18
        'js' => 'application/javascript',
19
        'json' => 'application/json',
20
        'xml' => 'application/xml',
21
        'swf' => 'application/x-shockwave-flash',
22
        'flv' => 'video/x-flv',
23
24
        // images
25
        'png' => 'image/png',
26
        'jpe' => 'image/jpeg',
27
        'jpeg' => 'image/jpeg',
28
        'jpg' => 'image/jpeg',
29
        'gif' => 'image/gif',
30
        'bmp' => 'image/bmp',
31
        'ico' => 'image/vnd.microsoft.icon',
32
        'tiff' => 'image/tiff',
33
        'tif' => 'image/tiff',
34
        'svg' => 'image/svg+xml',
35
        'svgz' => 'image/svg+xml',
36
37
        // archives
38
        'zip' => 'application/zip',
39
        'rar' => 'application/x-rar-compressed',
40
        'exe' => 'application/x-msdownload',
41
        'msi' => 'application/x-msdownload',
42
        'cab' => 'application/vnd.ms-cab-compressed',
43
44
        // audio/video
45
        'mp3' => 'audio/mpeg',
46
        'qt' => 'video/quicktime',
47
        'mov' => 'video/quicktime',
48
49
        // adobe
50
        'pdf' => 'application/pdf',
51
        'psd' => 'image/vnd.adobe.photoshop',
52
        'ai' => 'application/postscript',
53
        'eps' => 'application/postscript',
54
        'ps' => 'application/postscript',
55
56
        // ms office
57
        'doc' => 'application/msword',
58
        'rtf' => 'application/rtf',
59
        'xls' => 'application/vnd.ms-excel',
60
        'ppt' => 'application/vnd.ms-powerpoint',
61
62
        // open office
63
        'odt' => 'application/vnd.oasis.opendocument.text',
64
        'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
65
    );
66
67
    /**
68
     * Simple pathinfo wrapper.
69
     * @param string $filePath
70
     * @param int $fileInfOoptions
71
     * @return string
72
     * @see http://php.net/manual/en/function.pathinfo.php
73
     */
74
    public static function getPathinfoPart(string $filePath, int $fileInfOoptions) : string
75
    {
76
        if ($filePath == '' || is_dir($filePath) || DirHelper::endsWithSlash($filePath)) {
77
            return '';
78
        }
79
80
        $info = pathinfo($filePath, $fileInfOoptions);
81
82
        if ($info == '.' && $fileInfOoptions == PATHINFO_DIRNAME) {
83
            return '';
84
        }
85
        return ($info !== null && $info != '') ? $info : '';
86
    }
87
88
    /**
89
     * Return the file name of file (without path and without extension).
90
     * Return empty string if $filePath is null, empty or is a directory.
91
     * Ex.: /public/upload/pippo.txt return '/public/upload'
92
     * @param string $filePath
93
     * @return string
94
     */
95
    public static function getDirname(string $filePath) : string
96
    {
97
        return self::getPathinfoPart($filePath, PATHINFO_DIRNAME);
98
    }
99
100
    /**
101
     * Return the file name of file (without path and with extension).
102
     * Return empty string if $filePath is null, empty or is a directory.
103
     * Ex.: /public/upload/pippo.txt return 'pippo.txt'
104
     * @param string $filePath
105
     * @return string
106
     */
107
    public static function getFilename(string $filePath) : string
108
    {
109
        return self::getPathinfoPart($filePath, PATHINFO_BASENAME);
110
    }
111
112
    /**
113
     * Return the file name of file (without path and without extension).
114
     * Return empty string if $filePath is null, empty or is a directory.
115
     * Ex.: /public/upload/pippo.txt return 'pippo'
116
     * @param string $filePath
117
     * @return string
118
     */
119
    public static function getFilenameWithoutExtension(string $filePath) : string
120
    {
121
        return self::getPathinfoPart($filePath, PATHINFO_FILENAME);
122
    }
123
124
    /**
125
     * Return the file name of file (without path and without extension).
126
     * Return empty string if $filePath is null, empty or is a directory.
127
     * Ex.: /public/upload/pippo.txt return '.txt'
128
     * @param string $filePath
129
     * @param bool $ignoreCase if set to true return lowercase extension
130
     * (Requires mbstring extension for correct multi-byte character handling in extension)
131
     *
132
     * @return string
133
     */
134
    public static function getFilenameExtension(string $filePath, bool $ignoreCase = false) : string
135
    {
136
        $ext = self::getPathinfoPart($filePath, PATHINFO_EXTENSION);
137
        return $ignoreCase ? self::toLower($ext) : $ext;
138
    }
139
140
    /**
141
     * Returns whether the path has an extension.
142
     *
143
     * @param string $path The path string
144
     * @param string|array|null $extensions If null or not provided, checks if an
145
     *                                       extension exists, otherwise checks for
146
     *                                       the specified extension or array of extensions
147
     *                                       (with or without leading dot)
148
     * @param bool $ignoreCase Whether to ignore case-sensitivity
149
     *                                       (Requires mbstring extension for correct
150
     *                                       multi-byte character handling in extension)
151
     *
152
     * @return bool true if the path has an (or the specified) extension, otherwise false
153
     *
154
     * @see https://github.com/laradic/support/blob/master/src/Path.php
155
     */
156
    public static function hasExtension(string $path, $extensions = null, bool $ignoreCase = false) : bool
157
    {
158
        $actualExtension = self::getFilenameExtension($path, $ignoreCase);
159
160
        // Only check if path has any extension
161
        if (null === $extensions) {
162
            return !empty($actualExtension);
163
        }
164
165
        // Make an array of extensions
166
        $extensions = self::variable2Array($extensions);
167
168
        foreach ($extensions as $key => $extension) {
169
            if ($ignoreCase) {
170
                $extension = self::toLower($extension);
171
            }
172
            // remove leading '.' in extensions array
173
            $extensions[$key] = ltrim($extension, '.');
174
        }
175
176
        return in_array($actualExtension, $extensions);
177
    }
178
179
    /**
180
     * if $extensions is not an array, return [$extensions].
181
     * @param $extensions
182
     * @return array
183
     */
184
    protected static function variable2Array($extensions) : array
185
    {
186
        if (is_array($extensions)) {
187
            return $extensions;
188
        }
189
        return [$extensions];
190
    }
191
192
    /**
193
     * Changes the extension of a path string.
194
     *
195
     * @param string $path The path string with filename.ext to change
196
     * @param string $extension New extension (with or without leading dot)
197
     *
198
     * @return string The path string with new file extension
199
     *
200
     * @see https://github.com/laradic/support/blob/master/src/Path.php
201
     */
202
    public static function changeExtension($path, $extension)
203
    {
204
        if ('' === $path) {
205
            return '';
206
        }
207
        $actualExtension = self::getFilenameExtension($path);
208
        $extension = ltrim($extension, '.');
209
        // No extension for paths
210
        if ('/' == substr($path, -1)) {
211
            return $path;
212
        }
213
        // No actual extension in path
214
        if (empty($actualExtension)) {
215
            return $path . ('.' == substr($path, -1) ? '' : '.') . $extension;
216
        }
217
        return substr($path, 0, -strlen($actualExtension)) . $extension;
218
    }
219
220
    /**
221
     * unlink file if exists.
222
     * Return false if exists and unlink fails or if filePath is a dir.
223
     * @param string $filePath
224
     * @return bool
225
     */
226
    public static function unlinkSafe(string $filePath) : bool
227
    {
228
        if (!FileHelper::fileExistsSafe($filePath)) {
229
            return false;
230
        }
231
232
        if (DirHelper::isDirSafe($filePath)) {
233
            return false;
234
        }
235
236
        return unlink($filePath);
237
    }
238
239
    /**
240
     * Check if passed file exists or not.
241
     * If dir passed return false.
242
     * @param string $filePath
243
     * @return bool
244
     */
245
    public static function fileExistsSafe(string $filePath) : bool
246
    {
247
        if ($filePath == '') {
248
            return false;
249
        }
250
251
        if (DirHelper::isDirSafe($filePath)) {
252
            return false;
253
        }
254
255
        return file_exists($filePath);
256
    }
257
258
    /**
259
     * Find files matching a pattern (recursive with matched files in subdirs).
260
     * Returns an array containing the matched files (full path and not directories),
261
     * an empty array if no file matched or on error.
262
     * @param string $fileNamePattern if is null it set to base_path()/* if exists otherwise __DIR__/* . It support glob() string pattern.
263
     * @param int $flags glob() Valid flags
264
     * @return array of files (full path)
265
     */
266
    public static function findFiles(string $fileNamePattern, int $flags = 0)
267
    {
268
        $fallback = [];
269
270
        if (($fileNamePattern === null || $fileNamePattern == '') && function_exists('base_path')) {
271
            $fileNamePattern = DirHelper::addFinalSlash(base_path()) . '*';
272
        } elseif ($fileNamePattern === null || $fileNamePattern == '') {
273
            $fileNamePattern = __DIR__ . '/*';
274
        }
275
276
        if (DirHelper::endsWithSlash($fileNamePattern)) {
277
            $fileNamePattern .= '*';
278
        }
279
280
        $files = glob($fileNamePattern, $flags);
281
282
        //remove array of empty string
283
        $files = array_filter($files, function ($k) {
284
            return ($k !== null && $k != '');
285
        });
286
287
        if (empty($files)) {
288
            return $fallback;
289
        }
290
291
        foreach (glob(dirname($fileNamePattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
292
293
            if (empty($dir)) {
294
                continue;
295
            }
296
297
            $files = array_merge($files, self::findFiles($dir . '/' . basename($fileNamePattern), $flags));
298
            $files = array_filter($files, function ($k) {
299
                return ($k !== null && $k != '');
300
            });
301
        }
302
303
        $files = array_filter($files, function ($k) {
304
            return (!is_dir($k));
305
        });
306
307
        return $files === false ? $fallback : $files;
308
    }
309
310
    /**
311
     * Equals to file_put_contents but safe, i.e.
312
     * accept empty string and return false without raise an error,
313
     * accept a directory and return false without raise an error,
314
     * and if $forceCreateDirIfNotExists is set to true and path doesn't exists, file_put_contents fails
315
     * so, this class, try to create the complete path before save file.
316
     * @param string $filename file name including folder.
317
     * example :: /path/to/file/filename.ext or filename.ext
318
     * @param string $data The data to write.
319
     * @param bool $forceCreateDirIfNotExists if true and path not exists, try to create it.
320
     * @param string $modeMask The mask applied to dir if need to create some dir.
321
     * @param int $flags same flags used for file_put_contents.
322
     * @see more info: http://php.net/manual/en/function.file-put-contents.php
323
     * @return bool TRUE file created succesfully, return FALSE if failed to create file.
324
     */
325
    public static function filePutContentsSafe(
326
        string $filename,
327
        string $data,
328
        bool $forceCreateDirIfNotExists = true,
329
        string $modeMask = '0755',
330
        int $flags = 0
331
    ) : bool
332
    {
333
        if ($filename == '') {
334
            return false;
335
        }
336
337
        //check if a directory passed ($filename ends with slash)
338
        if (DirHelper::endsWithSlash($filename)) {
339
            return false;
340
        }
341
342
        $dirName = dirname($filename);
343
344
        if (!$forceCreateDirIfNotExists && !DirHelper::isDirSafe($dirName)) {
345
            return false;
346
        }
347
348
        if (!DirHelper::checkDirExistOrCreate(DirHelper::addFinalSlash($dirName), $modeMask)) {
349
            return false;
350
        }
351
352
        return file_put_contents($filename, $data, $flags);
353
    }
354
355
    /**
356
     * Return mime type of a passed file in optimized mode.
357
     * @param string $fullPathFile
358
     * @return string
359
     */
360
    public static function getMimeType(string $fullPathFile) : string
361
    {
362
        $mime_types = self::$arrMimeType;
363
        $ext = strtolower(self::getFilenameExtension($fullPathFile));
364
        if (array_key_exists($ext, $mime_types)) {
365
            return $mime_types[$ext];
366
        }
367
        $mimetype = self::getMimeTypeByMimeContentType($fullPathFile);
368
        if (isNotNullOrEmpty($mimetype)) {
369
            return $mimetype;
370
        }
371
        $mimetype = self::getMimeTypeByFinfo($fullPathFile);
372
        if (isNotNullOrEmpty($mimetype)) {
373
            return $mimetype;
374
        }
375
        return 'application/octet-stream';
376
    }
377
378
    /**
379
     * Return mime type of a passed file using finfo
380
     * @param string $fullPathFile
381
     * @return string return empty string if it fails.
382
     */
383
    public static function getMimeTypeByFinfo(string $fullPathFile) : string
384
    {
385
        if (!function_exists('finfo_open')) {
386
            return '';
387
        }
388
        $finfo = finfo_open(FILEINFO_MIME);
389
        $mimetype = finfo_file($finfo, $fullPathFile);
390
        finfo_close($finfo);
391
        if ($mimetype === false) {
392
            return '';
393
        }
394
        return $mimetype;
395
    }
396
397
    /**
398
     * Return mime type of a passed file using mime_content_type()
399
     * @param string $fullPathFile
400
     * @return string return empty string if it fails.
401
     */
402
    public static function getMimeTypeByMimeContentType(string $fullPathFile) : string
403
    {
404
        if (!function_exists('mime_content_type')) {
405
            return '';
406
        }
407
        return mime_content_type($fullPathFile);
408
    }
409
410
    /**
411
     * Converts string to lower-case (multi-byte safe if mbstring is installed).
412
     *
413
     * @param string $str The string
414
     *
415
     * @return string Lower case string
416
     * @see https://github.com/laradic/support/blob/master/src/Path.php
417
     */
418
    private static function toLower($str)
419
    {
420
        if (function_exists('mb_strtolower')) {
421
            return mb_strtolower($str, mb_detect_encoding($str));
422
        }
423
        return strtolower($str);
424
    }
425
426
    /**
427
     * Check if $path is a file and is readable.
428
     * Return false if you pass a dir.
429
     * @param string $path
430
     * @return bool
431
     */
432
    public static function isReadable(string $path):bool
433
    {
434
        return self::fileExistsSafe($path) && is_readable($path);
435
    }
436
437
    /**
438
     * Gets file or dir permissions in octal form ('0777') or not ('644').
439
     * @param string $file
440
     * @param bool $octal default false i.e. return '644'
441
     * @return bool|string return false if it fails.
442
     */
443
    public static function filPerms(string $file, bool $octal = false)
444
    {
445
        if (!file_exists($file)) {
446
            return false;
447
        }
448
449
        $perms = fileperms($file);
450
        if($perms===false){
451
            return false;
452
        }
453
454
        $cut = $octal ? -4 : -3;
455
456
        return substr(decoct($perms), $cut);
457
    }
458
}
459