FilesManagement   F
last analyzed

Complexity

Total Complexity 65

Size/Duplication

Total Lines 285
Duplicated Lines 0 %

Importance

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

8 Methods

Rating   Name   Duplication   Size   Complexity  
A createFolder() 0 12 6
B rcopy() 0 34 11
A copyFile() 0 5 1
B recurseCopy() 0 20 8
B deleteDirectory() 0 35 9
B rmove() 0 37 11
B xcopy() 0 33 10
B rrmdir() 0 28 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
/**
32
 * Trait FilesManagement
33
 * @package XoopsModules\Suico\Common
34
 */
35
trait FilesManagement
36
{
37
    /**
38
     * Function responsible for checking if a directory exists, we can also write in and create an index.html file
39
     *
40
     * @param string $folder The full path of the directory to check
41
     *
42
     * @throws RuntimeException
43
     */
44
    public static function createFolder(
45
        $folder
46
    ) {
47
        try {
48
            if (!\is_dir($folder)) {
49
                if (!\is_dir($folder) && !\mkdir($folder) && !\is_dir($folder)) {
50
                    throw new RuntimeException(\sprintf('Unable to create the %s directory', $folder));
51
                }
52
                file_put_contents($folder . '/index.html', '<script>history.go(-1);</script>');
53
            }
54
        } catch (Throwable $throwable) {
55
            echo 'Caught exception: ', $throwable->getMessage(), '<br>';
56
        }
57
    }
58
59
    /**
60
     * @param $file
61
     * @param $folder
62
     * @return bool
63
     */
64
    public static function copyFile(
65
        $file,
66
        $folder
67
    ) {
68
        return \copy($file, $folder);
69
    }
70
71
    /**
72
     * @param $src
73
     * @param $dst
74
     * @return bool
75
     */
76
    public static function recurseCopy($src, $dst)
77
    {
78
        $dir = \opendir($src);
79
        if (false === $dir) {
80
            return false;
81
        }
82
        //        @mkdir($dst);
83
        if (!@\mkdir($dst) && !\is_dir($dst)) {
84
            throw new RuntimeException('The directory ' . $dst . ' could not be created.');
85
        }
86
        while (false !== ($file = \readdir($dir))) {
87
            if (('.' !== $file) && ('..' !== $file)) {
88
                if (\is_dir($src . '/' . $file)) {
89
                    self::recurseCopy($src . '/' . $file, $dst . '/' . $file);
90
                } else {
91
                    \copy($src . '/' . $file, $dst . '/' . $file);
92
                }
93
            }
94
        }
95
        \closedir($dir);
96
    }
97
98
    /**
99
     * Copy a file, or recursively copy a folder and its contents
100
     * @param string $source Source path
101
     * @param string $dest   Destination path
102
     * @return      bool     Returns true on success, false on failure
103
     * @author      Aidan Lister <[email protected]>
104
     * @version     1.0.1
105
     * @link        http://aidanlister.com/2004/04/recursively-copying-directories-in-php/
106
     */
107
    public static function xcopy(
108
        $source,
109
        $dest
110
    ) {
111
        // Check for symlinks
112
        if (\is_link($source)) {
113
            return \symlink(\readlink($source), $dest);
114
        }
115
        // Simple copy for a file
116
        if (\is_file($source)) {
117
            return \copy($source, $dest);
118
        }
119
        // Make destination directory
120
        if (!\is_dir($dest)) {
121
            if (!\mkdir($dest) && !\is_dir($dest)) {
122
                throw new RuntimeException(\sprintf('Directory "%s" was not created', $dest));
123
            }
124
        }
125
        // Loop through the folder
126
        $dir = \dir($source);
127
        if (@\is_dir($dir)) {
0 ignored issues
show
Bug introduced by
$dir of type Directory is incompatible with the type string expected by parameter $filename of is_dir(). ( Ignorable by Annotation )

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

127
        if (@\is_dir(/** @scrutinizer ignore-type */ $dir)) {
Loading history...
128
            while (false !== $entry = $dir->read()) {
129
                // Skip pointers
130
                if ('.' === $entry || '..' === $entry) {
131
                    continue;
132
                }
133
                // Deep copy directories
134
                self::xcopy("${source}/${entry}", "${dest}/${entry}");
135
            }
136
            // Clean up
137
            $dir->close();
138
        }
139
        return true;
140
    }
141
142
    /**
143
     * Remove files and (sub)directories
144
     *
145
     * @param string $src source directory to delete
146
     *
147
     * @return bool true on success
148
     * @uses \Xmf\Module\Helper::isUserAdmin()
149
     *
150
     * @uses \Xmf\Module\Helper::getHelper()
151
     */
152
    public static function deleteDirectory(
153
        $src
154
    ) {
155
        // Only continue if user is a 'global' Admin
156
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
157
            return false;
158
        }
159
        $success = true;
160
        // remove old files
161
        $dirInfo = new SplFileInfo($src);
162
        // validate is a directory
163
        if ($dirInfo->isDir()) {
164
            $fileList = \array_diff(\scandir($src, \SCANDIR_SORT_NONE), ['..', '.']);
165
            foreach ($fileList as $k => $v) {
166
                $fileInfo = new SplFileInfo("{$src}/{$v}");
167
                if ($fileInfo->isDir()) {
168
                    // recursively handle subdirectories
169
                    if (!$success = self::deleteDirectory(
170
                        $fileInfo->getRealPath()
171
                    )) {
172
                        break;
173
                    }
174
                } elseif (!($success = \unlink($fileInfo->getRealPath()))) {
175
                    break;
176
                }
177
            }
178
            // now delete this (sub)directory if all the files are gone
179
            if ($success) {
180
                $success = \rmdir($dirInfo->getRealPath());
181
            }
182
        } else {
183
            // input is not a valid directory
184
            $success = false;
185
        }
186
        return $success;
187
    }
188
189
    /**
190
     * Recursively remove directory
191
     *
192
     * @todo currently won't remove directories with hidden files, should it?
193
     *
194
     * @param string $src directory to remove (delete)
195
     *
196
     * @return bool true on success
197
     */
198
    public static function rrmdir(
199
        $src
200
    ) {
201
        // Only continue if user is a 'global' Admin
202
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
203
            return false;
204
        }
205
        // If source is not a directory stop processing
206
        if (!\is_dir($src)) {
207
            return false;
208
        }
209
        $success = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $success is dead and can be removed.
Loading history...
210
        // Open the source directory to read in files
211
        $iterator = new DirectoryIterator($src);
212
        foreach ($iterator as $fObj) {
213
            if ($fObj->isFile()) {
214
                $filename = $fObj->getPathname();
215
                $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...
216
                if (!\unlink($filename)) {
217
                    return false; // couldn't delete the file
218
                }
219
            } elseif (!$fObj->isDot() && $fObj->isDir()) {
220
                // Try recursively on directory
221
                self::rrmdir($fObj->getPathname());
222
            }
223
        }
224
        $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...
225
        return \rmdir($src); // remove the directory & return results
226
    }
227
228
    /**
229
     * Recursively move files from one directory to another
230
     *
231
     * @param string $src  - Source of files being moved
232
     * @param string $dest - Destination of files being moved
233
     *
234
     * @return bool true on success
235
     */
236
    public static function rmove(
237
        $src,
238
        $dest
239
    ) {
240
        // Only continue if user is a 'global' Admin
241
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
242
            return false;
243
        }
244
        // If source is not a directory stop processing
245
        if (!\is_dir($src)) {
246
            return false;
247
        }
248
        // If the destination directory does not exist and could not be created stop processing
249
        if (!\is_dir(
250
                $dest
251
            )
252
            && !\mkdir(
253
                $dest
254
            )
255
            && !\is_dir(
256
                $dest
257
            )) {
258
            return false;
259
        }
260
        // Open the source directory to read in files
261
        $iterator = new DirectoryIterator($src);
262
        foreach ($iterator as $fObj) {
263
            if ($fObj->isFile()) {
264
                \rename($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
265
            } elseif (!$fObj->isDot() && $fObj->isDir()) {
266
                // Try recursively on directory
267
                self::rmove($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
268
                //                rmdir($fObj->getPath()); // now delete the directory
269
            }
270
        }
271
        $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...
272
        return \rmdir($src); // remove the directory & return results
273
    }
274
275
    /**
276
     * Recursively copy directories and files from one directory to another
277
     *
278
     * @param string $src  - Source of files being moved
279
     * @param string $dest - Destination of files being moved
280
     *
281
     * @return bool true on success
282
     * @uses \Xmf\Module\Helper::isUserAdmin()
283
     *
284
     * @uses \Xmf\Module\Helper::getHelper()
285
     */
286
    public static function rcopy(
287
        $src,
288
        $dest
289
    ) {
290
        // Only continue if user is a 'global' Admin
291
        if (!($GLOBALS['xoopsUser'] instanceof XoopsUser) || !$GLOBALS['xoopsUser']->isAdmin()) {
292
            return false;
293
        }
294
        // If source is not a directory stop processing
295
        if (!\is_dir($src)) {
296
            return false;
297
        }
298
        // If the destination directory does not exist and could not be created stop processing
299
        if (!\is_dir(
300
                $dest
301
            )
302
            && !\mkdir(
303
                $dest
304
            )
305
            && !\is_dir(
306
                $dest
307
            )) {
308
            return false;
309
        }
310
        // Open the source directory to read in files
311
        $iterator = new DirectoryIterator($src);
312
        foreach ($iterator as $fObj) {
313
            if ($fObj->isFile()) {
314
                \copy($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
315
            } elseif (!$fObj->isDot() && $fObj->isDir()) {
316
                self::rcopy($fObj->getPathname(), "{$dest}/" . $fObj->getFilename());
317
            }
318
        }
319
        return true;
320
    }
321
}
322