symbolic_permissions()   F
last analyzed

Complexity

Conditions 23
Paths > 20000

Size

Total Lines 36
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 552

Importance

Changes 0
Metric Value
cc 23
eloc 26
c 0
b 0
f 0
nc 262144
nop 1
dl 0
loc 36
ccs 0
cts 12
cp 0
crap 552
rs 0

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
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
if (! function_exists('directory_map')) {
13
    /**
14
     * Créer une carte de répertoire
15
     *
16
     * Lit le répertoire spécifié et construit un tableau
17
     * représentation de celui-ci. Les sous-dossiers contenus dans le répertoire seront également mappés.
18
     *
19
     * @param string $sourceDir      Chemin d'accès à la source
20
     * @param int    $directoryDepth Profondeur des répertoires à parcourir
21
     *                               (0 = entièrement récursif, 1 = répertoire actuel, etc.)
22
     * @param bool   $hidden         Afficher ou non les fichiers cachés
23
     */
24
    function directory_map(string $sourceDir, int $directoryDepth = 0, bool $hidden = false): array
25
    {
26
        try {
27 6
            $fp = opendir($sourceDir);
28
29 6
            $fileData  = [];
30 6
            $newDepth  = $directoryDepth - 1;
31 6
            $sourceDir = rtrim($sourceDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
32
33
            while (false !== ($file = readdir($fp))) {
34
                // Remove '.', '..', and hidden files [optional]
35
                if ($file === '.' || $file === '..' || ($hidden === false && $file[0] === '.')) {
36 6
                    continue;
37
                }
38
39
                if (is_dir($sourceDir . $file)) {
40 6
                    $file .= DIRECTORY_SEPARATOR;
41
                }
42
43
                if (($directoryDepth < 1 || $newDepth > 0) && is_dir($sourceDir . $file)) {
44 6
                    $fileData[$file] = directory_map($sourceDir . $file, $newDepth, $hidden);
45
                } else {
46 6
                    $fileData[] = $file;
47
                }
48
            }
49
50 6
            closedir($fp);
51
52 6
            return $fileData;
53
        } catch (Throwable) {
54
            return [];
55
        }
56
    }
57
}
58
59
if (! function_exists('directory_mirror')) {
60
    /**
61
     * Copie récursivement les fichiers et répertoires du répertoire d'origine
62
     * dans le répertoire cible, c'est-à-dire "miroir" son contenu.
63
     *
64
     * @param bool $overwrite Si les fichiers individuels sont écrasés en cas de collision
65
     */
66
    function directory_mirror(string $originDir, string $targetDir, bool $overwrite = true): bool
67
    {
68
        return service('fs')->copyDirectory($originDir, $targetDir, $overwrite);
69
    }
70
}
71
72
if (! function_exists('write_file')) {
73
    /**
74
     * Write File
75
     *
76
     * Writes data to the file specified in the path.
77
     * Creates a new file if non-existent.
78
     *
79
     * @param string $path File path
80
     * @param string $data Data to write
81
     * @param string $mode fopen() mode (default: 'wb')
82
     */
83
    function write_file(string $path, string $data, string $mode = 'wb'): bool
84
    {
85
        try {
86 8
            $fp = fopen($path, $mode);
87
88 8
            flock($fp, LOCK_EX);
89
90 8
            for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) {
91
                if (($result = fwrite($fp, substr($data, $written))) === false) {
92
                    break;
93
                }
94
            }
95
96 8
            flock($fp, LOCK_UN);
97 8
            fclose($fp);
98
99 8
            return is_int($result);
100
        } catch (Throwable) {
101
            return false;
102
        }
103
    }
104
}
105
106
if (! function_exists('delete_files')) {
107
    /**
108
     * Delete Files
109
     *
110
     * Deletes all files contained in the supplied directory path.
111
     * Files must be writable or owned by the system in order to be deleted.
112
     * If the second parameter is set to true, any directories contained
113
     * within the supplied base directory will be nuked as well.
114
     *
115
     * @param string $path   File path
116
     * @param bool   $delDir Whether to delete any directories found in the path
117
     * @param bool   $htdocs Whether to skip deleting .htaccess and index page files
118
     * @param bool   $hidden Whether to include hidden files (files beginning with a period)
119
     */
120
    function delete_files(string $path, bool $delDir = false, bool $htdocs = false, bool $hidden = false): bool
121
    {
122 10
        $path = realpath($path) ?: $path;
123 10
        $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
124
125
        try {
126
            foreach (new RecursiveIteratorIterator(
127
                new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
128
                RecursiveIteratorIterator::CHILD_FIRST
129
            ) as $object) {
130 10
                $filename = $object->getFilename();
131
                if (! $hidden && $filename[0] === '.') {
132
                    continue;
133
                }
134
135
                if (! $htdocs || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) {
136 10
                    $isDir = $object->isDir();
137
                    if ($isDir && $delDir) {
138 10
                        rmdir($object->getPathname());
139
140
                        continue;
141
                    }
142
                    if (! $isDir) {
143 10
                        unlink($object->getPathname());
144
                    }
145
                }
146
            }
147
148 10
            return true;
149
        } catch (Throwable) {
150
            return false;
151
        }
152
    }
153
}
154
155
if (! function_exists('get_filenames')) {
156
    /**
157
     * Get Filenames
158
     *
159
     * Reads the specified directory and builds an array containing the filenames.
160
     * Any sub-folders contained within the specified path are read as well.
161
     *
162
     * @param string    $sourceDir   Path to source
163
     * @param bool|null $includePath Whether to include the path as part of the filename; false for no path, null for a relative path, true for full path
164
     * @param bool      $hidden      Whether to include hidden files (files beginning with a period)
165
     * @param bool      $includeDir  Whether to include directories
166
     */
167
    function get_filenames(
168
        string $sourceDir,
169
        ?bool $includePath = false,
170
        bool $hidden = false,
171
        bool $includeDir = true
172
    ): array {
173
        $files = [];
174
175
        $sourceDir = realpath($sourceDir) ?: $sourceDir;
176
        $sourceDir = rtrim($sourceDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
177
178
        try {
179
            foreach (new RecursiveIteratorIterator(
180
                new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
181
                RecursiveIteratorIterator::SELF_FIRST
182
            ) as $name => $object) {
183
                $basename = pathinfo($name, PATHINFO_BASENAME);
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null and true; however, parameter $path of pathinfo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

183
                $basename = pathinfo(/** @scrutinizer ignore-type */ $name, PATHINFO_BASENAME);
Loading history...
184
                if (! $hidden && $basename[0] === '.') {
185
                    continue;
186
                }
187
188
                if ($includeDir || ! $object->isDir()) {
189
                    if ($includePath === false) {
190
                        $files[] = $basename;
191
                    } elseif ($includePath === null) {
192
                        $files[] = str_replace($sourceDir, '', $name);
193
                    } else {
194
                        $files[] = $name;
195
                    }
196
                }
197
            }
198
        } catch (Throwable) {
199
            return [];
200
        }
201
202
        sort($files);
203
204
        return $files;
205
    }
206
}
207
208
if (! function_exists('get_dir_file_info')) {
209
    /**
210
     * Get Directory File Information
211
     *
212
     * Reads the specified directory and builds an array containing the filenames,
213
     * filesize, dates, and permissions
214
     *
215
     * Any sub-folders contained within the specified path are read as well.
216
     *
217
     * @param string $sourceDir    Path to source
218
     * @param bool   $topLevelOnly Look only at the top level directory specified?
219
     * @param bool   $recursion    Internal variable to determine recursion status - do not use in calls
220
     */
221
    function get_dir_file_info(string $sourceDir, bool $topLevelOnly = true, bool $recursion = false): array
222
    {
223
        static $fileData = [];
224
        $relativePath    = $sourceDir;
225
226
        try {
227
            $fp = opendir($sourceDir);
228
229
            // reset the array and make sure $source_dir has a trailing slash on the initial call
230
            if ($recursion === false) {
231
                $fileData  = [];
232
                $sourceDir = rtrim(realpath($sourceDir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
233
            }
234
235
            // Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast
236
            while (false !== ($file = readdir($fp))) {
237
                if (is_dir($sourceDir . $file) && $file[0] !== '.' && $topLevelOnly === false) {
238
                    get_dir_file_info($sourceDir . $file . DIRECTORY_SEPARATOR, $topLevelOnly, true);
239
                } elseif ($file[0] !== '.') {
240
                    $fileData[$file]                  = get_file_info($sourceDir . $file);
241
                    $fileData[$file]['relative_path'] = $relativePath;
242
                }
243
            }
244
245
            closedir($fp);
246
247
            return $fileData;
248
        } catch (Throwable) {
249
            return [];
250
        }
251
    }
252
}
253
254
if (! function_exists('get_file_info')) {
255
    /**
256
     * Get File Info
257
     *
258
     * Given a file and path, returns the name, path, size, date modified
259
     * Second parameter allows you to explicitly declare what information you want returned
260
     * Options are: name, server_path, size, date, readable, writable, executable, fileperms
261
     * Returns false if the file cannot be found.
262
     *
263
     * @param string $file           Path to file
264
     * @param mixed  $returnedValues Array or comma separated string of information returned
265
     *
266
     * @return array|null
267
     */
268
    function get_file_info(string $file, $returnedValues = ['name', 'server_path', 'size', 'date'])
269
    {
270
        if (! is_file($file)) {
271
            return null;
272
        }
273
274
        $fileInfo = [];
275
276
        if (is_string($returnedValues)) {
277
            $returnedValues = explode(',', $returnedValues);
278
        }
279
280
        foreach ($returnedValues as $key) {
281
            switch ($key) {
282
                case 'name':
283
                    $fileInfo['name'] = basename($file);
284
                    break;
285
286
                case 'server_path':
287
                    $fileInfo['server_path'] = $file;
288
                    break;
289
290
                case 'size':
291
                    $fileInfo['size'] = filesize($file);
292
                    break;
293
294
                case 'date':
295
                    $fileInfo['date'] = filemtime($file);
296
                    break;
297
298
                case 'readable':
299
                    $fileInfo['readable'] = is_readable($file);
300
                    break;
301
302
                case 'writable':
303
                    $fileInfo['writable'] = is_really_writable($file);
304
                    break;
305
306
                case 'executable':
307
                    $fileInfo['executable'] = is_executable($file);
308
                    break;
309
310
                case 'fileperms':
311
                    $fileInfo['fileperms'] = fileperms($file);
312
                    break;
313
            }
314
        }
315
316
        return $fileInfo;
317
    }
318
}
319
320
if (! function_exists('symbolic_permissions')) {
321
    /**
322
     * Symbolic Permissions
323
     *
324
     * Takes a numeric value representing a file's permissions and returns
325
     * standard symbolic notation representing that value
326
     *
327
     * @param int $perms Permissions
328
     */
329
    function symbolic_permissions(int $perms): string
330
    {
331
        if (($perms & 0xC000) === 0xC000) {
332
            $symbolic = 's'; // Socket
333
        } elseif (($perms & 0xA000) === 0xA000) {
334
            $symbolic = 'l'; // Symbolic Link
335
        } elseif (($perms & 0x8000) === 0x8000) {
336
            $symbolic = '-'; // Regular
337
        } elseif (($perms & 0x6000) === 0x6000) {
338
            $symbolic = 'b'; // Block special
339
        } elseif (($perms & 0x4000) === 0x4000) {
340
            $symbolic = 'd'; // Directory
341
        } elseif (($perms & 0x2000) === 0x2000) {
342
            $symbolic = 'c'; // Character special
343
        } elseif (($perms & 0x1000) === 0x1000) {
344
            $symbolic = 'p'; // FIFO pipe
345
        } else {
346
            $symbolic = 'u'; // Unknown
347
        }
348
349
        // Owner
350
        $symbolic .= ((($perms & 0x0100) !== 0) ? 'r' : '-')
351
                . ((($perms & 0x0080) !== 0) ? 'w' : '-')
352
                . ((($perms & 0x0040) !== 0) ? ((($perms & 0x0800) !== 0) ? 's' : 'x') : ((($perms & 0x0800) !== 0) ? 'S' : '-'));
353
354
        // Group
355
        $symbolic .= ((($perms & 0x0020) !== 0) ? 'r' : '-')
356
                . ((($perms & 0x0010) !== 0) ? 'w' : '-')
357
                . ((($perms & 0x0008) !== 0) ? ((($perms & 0x0400) !== 0) ? 's' : 'x') : ((($perms & 0x0400) !== 0) ? 'S' : '-'));
358
359
        // World
360
        $symbolic .= ((($perms & 0x0004) !== 0) ? 'r' : '-')
361
                . ((($perms & 0x0002) !== 0) ? 'w' : '-')
362
                . ((($perms & 0x0001) !== 0) ? ((($perms & 0x0200) !== 0) ? 't' : 'x') : ((($perms & 0x0200) !== 0) ? 'T' : '-'));
363
364
        return $symbolic;
365
    }
366
}
367
368
if (! function_exists('octal_permissions')) {
369
    /**
370
     * Octal Permissions
371
     *
372
     * Takes a numeric value representing a file's permissions and returns
373
     * a three character string representing the file's octal permissions
374
     *
375
     * @param int $perms Permissions
376
     */
377
    function octal_permissions(int $perms): string
378
    {
379
        return substr(sprintf('%o', $perms), -3);
380
    }
381
}
382
383
if (! function_exists('same_file')) {
384
    /**
385
     * Checks if two files both exist and have identical hashes
386
     *
387
     * @return bool Same or not
388
     */
389
    function same_file(string $file1, string $file2): bool
390
    {
391 2
        return is_file($file1) && is_file($file2) && md5_file($file1) === md5_file($file2);
392
    }
393
}
394
395
if (! function_exists('set_realpath')) {
396
    /**
397
     * Set Realpath
398
     *
399
     * @param bool $checkExistence Checks to see if the path exists
400
     */
401
    function set_realpath(string $path, bool $checkExistence = false): string
402
    {
403
        // Security check to make sure the path is NOT a URL. No remote file inclusion!
404
        if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp)#i', $path) || filter_var($path, FILTER_VALIDATE_IP) === $path) {
405 12
            throw new InvalidArgumentException('The path you submitted must be a local server path, not a URL');
406
        }
407
408
        // Resolve the path
409
        if (realpath($path) !== false) {
410 12
            $path = realpath($path);
411
        } elseif ($checkExistence && ! is_dir($path) && ! is_file($path)) {
412 2
            throw new InvalidArgumentException('Not a valid path: ' . $path);
413
        }
414
415
        // Add a trailing slash, if this is a directory
416 12
        return is_dir($path) ? rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $path;
417
    }
418
}
419