Passed
Branch master (410c7b)
by Michael
03:30
created

FilesManagement   F

Complexity

Total Complexity 65

Size/Duplication

Total Lines 356
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 65
eloc 108
dl 0
loc 356
rs 3.2
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A createFolder() 0 13 6
B rcopy() 0 43 11
A copyFile() 0 5 1
B recurseCopy() 0 25 8
B deleteDirectory() 0 48 9
B rmove() 0 47 11
B xcopy() 0 47 10
B rrmdir() 0 39 9

How to fix   Complexity   

Complex Class

Complex classes like FilesManagement often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FilesManagement, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace XoopsModules\Suico\Common;
6
7
/*
8
 You may not change or alter any portion of this comment or credits
9
 of supporting developers from this source code or any supporting source code
10
 which is considered copyrighted (c) material of the original comment or credit authors.
11
12
 This program is distributed in the hope that it will be useful,
13
 but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
 */
16
17
/**
18
 * @category        Module
19
 * @package         suico
20
 * @copyright       {@link https://xoops.org/ XOOPS Project}
21
 * @license         GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
22
 * @author          Marcello Brandão aka  Suico, Mamba, LioMJ  <https://xoops.org>
23
 */
24
25
use DirectoryIterator;
26
use RuntimeException;
27
use SplFileInfo;
28
use Throwable;
29
use XoopsUser;
30
31
trait FilesManagement
32
{
33
    /**
34
     * Function responsible for checking if a directory exists, we can also write in and create an index.html file
35
     *
36
     * @param string $folder The full path of the directory to check
37
     *
38
     * @throws RuntimeException
39
     */
40
41
    public static function createFolder(
42
        $folder
43
    ) {
44
        try {
45
            if (!\file_exists($folder)) {
46
                if (!\is_dir($folder) && !\mkdir($folder) && !\is_dir($folder)) {
47
                    throw new RuntimeException(\sprintf('Unable to create the %s directory', $folder));
48
                }
49
50
                file_put_contents($folder . '/index.html', '<script>history.go(-1);</script>');
51
            }
52
        } catch (Throwable $throwable) {
53
            echo 'Caught exception: ', $throwable->getMessage(), '<br>';
54
        }
55
    }
56
57
    /**
58
     * @param $file
59
     * @param $folder
60
     * @return bool
61
     */
62
63
    public static function copyFile(
64
        $file,
65
        $folder
66
    ) {
67
        return \copy($file, $folder);
68
    }
69
70
    /**
71
     * @param $src
72
     * @param $dst
73
     * @return bool
74
     */
75
76
    public static function recurseCopy($src, $dst)
77
    {
78
        $dir = \opendir($src);
79
80
        if (false === $dir) {
81
            return false;
82
        }
83
84
        //        @mkdir($dst);
85
86
        if (!@\mkdir($dst) && !\is_dir($dst)) {
87
            throw new RuntimeException('The directory ' . $dst . ' could not be created.');
88
        }
89
90
        while (false !== ($file = \readdir($dir))) {
91
            if (('.' !== $file) && ('..' !== $file)) {
92
                if (\is_dir($src . '/' . $file)) {
93
                    self::recurseCopy($src . '/' . $file, $dst . '/' . $file);
94
                } else {
95
                    \copy($src . '/' . $file, $dst . '/' . $file);
96
                }
97
            }
98
        }
99
100
        \closedir($dir);
101
    }
102
103
    /**
104
     * Copy a file, or recursively copy a folder and its contents
105
     * @param string $source Source path
106
     * @param string $dest   Destination path
107
     * @return      bool     Returns true on success, false on failure
108
     * @author      Aidan Lister <[email protected]>
109
     * @version     1.0.1
110
     * @link        http://aidanlister.com/2004/04/recursively-copying-directories-in-php/
111
     */
112
113
    public static function xcopy(
114
        $source,
115
        $dest
116
    ) {
117
        // Check for symlinks
118
119
        if (\is_link($source)) {
120
            return \symlink(\readlink($source), $dest);
121
        }
122
123
        // Simple copy for a file
124
125
        if (\is_file($source)) {
126
            return \copy($source, $dest);
127
        }
128
129
        // Make destination directory
130
131
        if (!\is_dir($dest)) {
132
            if (!\mkdir($dest) && !\is_dir($dest)) {
133
                throw new RuntimeException(\sprintf('Directory "%s" was not created', $dest));
134
            }
135
        }
136
137
        // Loop through the folder
138
139
        $dir = \dir($source);
140
141
        if (@\is_dir($dir)) {
142
            while (false !== $entry = $dir->read()) {
143
                // Skip pointers
144
145
                if ('.' === $entry || '..' === $entry) {
146
                    continue;
147
                }
148
149
                // Deep copy directories
150
151
                self::xcopy("${source}/${entry}", "${dest}/${entry}");
152
            }
153
154
            // Clean up
155
156
            $dir->close();
157
        }
158
159
        return true;
160
    }
161
162
    /**
163
     * Remove files and (sub)directories
164
     *
165
     * @param string $src source directory to delete
166
     *
167
     * @return bool true on success
168
     * @uses \Xmf\Module\Helper::isUserAdmin()
169
     *
170
     * @uses \Xmf\Module\Helper::getHelper()
171
     */
172
173
    public static function deleteDirectory(
174
        $src
175
    ) {
176
        // Only continue if user is a 'global' Admin
177
178
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
179
            return false;
180
        }
181
182
        $success = true;
183
184
        // remove old files
185
186
        $dirInfo = new SplFileInfo($src);
187
188
        // validate is a directory
189
190
        if ($dirInfo->isDir()) {
191
            $fileList = \array_diff(\scandir($src, \SCANDIR_SORT_NONE), ['..', '.']);
0 ignored issues
show
Bug introduced by
It seems like scandir($src, SCANDIR_SORT_NONE) can also be of type false; however, parameter $array1 of array_diff() does only seem to accept array, 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

191
            $fileList = \array_diff(/** @scrutinizer ignore-type */ \scandir($src, \SCANDIR_SORT_NONE), ['..', '.']);
Loading history...
192
193
            foreach ($fileList as $k => $v) {
194
                $fileInfo = new SplFileInfo("{$src}/{$v}");
195
196
                if ($fileInfo->isDir()) {
197
                    // recursively handle subdirectories
198
199
                    if (!$success = self::deleteDirectory(
200
                        $fileInfo->getRealPath()
201
                    )) {
202
                        break;
203
                    }
204
                } elseif (!($success = \unlink($fileInfo->getRealPath()))) {
205
                    break;
206
                }
207
            }
208
209
            // now delete this (sub)directory if all the files are gone
210
211
            if ($success) {
212
                $success = \rmdir($dirInfo->getRealPath());
213
            }
214
        } else {
215
            // input is not a valid directory
216
217
            $success = false;
218
        }
219
220
        return $success;
221
    }
222
223
    /**
224
     * Recursively remove directory
225
     *
226
     * @todo currently won't remove directories with hidden files, should it?
227
     *
228
     * @param string $src directory to remove (delete)
229
     *
230
     * @return bool true on success
231
     */
232
233
    public static function rrmdir(
234
        $src
235
    ) {
236
        // Only continue if user is a 'global' Admin
237
238
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
239
            return false;
240
        }
241
242
        // If source is not a directory stop processing
243
244
        if (!\is_dir($src)) {
245
            return false;
246
        }
247
248
        $success = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $success is dead and can be removed.
Loading history...
249
250
        // Open the source directory to read in files
251
252
        $iterator = new DirectoryIterator($src);
253
254
        foreach ($iterator as $fObj) {
255
            if ($fObj->isFile()) {
256
                $filename = $fObj->getPathname();
257
258
                $fObj = null; // clear this iterator object to close the file
0 ignored issues
show
Unused Code introduced by
The assignment to $fObj is dead and can be removed.
Loading history...
259
260
                if (!\unlink($filename)) {
261
                    return false; // couldn't delete the file
262
                }
263
            } elseif (!$fObj->isDot() && $fObj->isDir()) {
264
                // Try recursively on directory
265
266
                self::rrmdir($fObj->getPathname());
267
            }
268
        }
269
270
        $iterator = null;   // clear iterator Obj to close file/directory
0 ignored issues
show
Unused Code introduced by
The assignment to $iterator is dead and can be removed.
Loading history...
271
        return \rmdir($src); // remove the directory & return results
272
    }
273
274
    /**
275
     * Recursively move files from one directory to another
276
     *
277
     * @param string $src  - Source of files being moved
278
     * @param string $dest - Destination of files being moved
279
     *
280
     * @return bool true on success
281
     */
282
283
    public static function rmove(
284
        $src,
285
        $dest
286
    ) {
287
        // Only continue if user is a 'global' Admin
288
289
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
290
            return false;
291
        }
292
293
        // If source is not a directory stop processing
294
295
        if (!\is_dir($src)) {
296
            return false;
297
        }
298
299
        // If the destination directory does not exist and could not be created stop processing
300
301
        if (!\is_dir(
302
                $dest
303
            )
304
            && !\mkdir(
305
                $dest
306
            )
307
            && !\is_dir(
308
                $dest
309
            )) {
310
            return false;
311
        }
312
313
        // Open the source directory to read in files
314
315
        $iterator = new DirectoryIterator($src);
316
317
        foreach ($iterator as $fObj) {
318
            if ($fObj->isFile()) {
319
                \rename($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
320
            } elseif (!$fObj->isDot() && $fObj->isDir()) {
321
                // Try recursively on directory
322
323
                self::rmove($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
324
                //                rmdir($fObj->getPath()); // now delete the directory
325
            }
326
        }
327
328
        $iterator = null;   // clear iterator Obj to close file/directory
0 ignored issues
show
Unused Code introduced by
The assignment to $iterator is dead and can be removed.
Loading history...
329
        return \rmdir($src); // remove the directory & return results
330
    }
331
332
    /**
333
     * Recursively copy directories and files from one directory to another
334
     *
335
     * @param string $src  - Source of files being moved
336
     * @param string $dest - Destination of files being moved
337
     *
338
     * @return bool true on success
339
     * @uses \Xmf\Module\Helper::isUserAdmin()
340
     *
341
     * @uses \Xmf\Module\Helper::getHelper()
342
     */
343
344
    public static function rcopy(
345
        $src,
346
        $dest
347
    ) {
348
        // Only continue if user is a 'global' Admin
349
350
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
351
            return false;
352
        }
353
354
        // If source is not a directory stop processing
355
356
        if (!\is_dir($src)) {
357
            return false;
358
        }
359
360
        // If the destination directory does not exist and could not be created stop processing
361
362
        if (!\is_dir(
363
                $dest
364
            )
365
            && !\mkdir(
366
                $dest
367
            )
368
            && !\is_dir(
369
                $dest
370
            )) {
371
            return false;
372
        }
373
374
        // Open the source directory to read in files
375
376
        $iterator = new DirectoryIterator($src);
377
378
        foreach ($iterator as $fObj) {
379
            if ($fObj->isFile()) {
380
                \copy($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
381
            } elseif (!$fObj->isDot() && $fObj->isDir()) {
382
                self::rcopy($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
383
            }
384
        }
385
386
        return true;
387
    }
388
}
389