FileSystem::copyDir()   B
last analyzed

Complexity

Conditions 8
Paths 9

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 11
nc 9
nop 2
dl 0
loc 18
ccs 15
cts 15
cp 1
crap 8
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * \AppserverIo\Appserver\Core\Utilities\FileSystem
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Johann Zelger <[email protected]>
15
 * @copyright 2015 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/appserver
18
 * @link      http://www.appserver.io
19
 */
20
21
namespace AppserverIo\Appserver\Core\Utilities;
22
23
/**
24
 * Utility class that provides simple file system commands
25
 *
26
 * @author    Johann Zelger <[email protected]>
27
 * @copyright 2015 TechDivision GmbH <[email protected]>
28
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
29
 * @link      https://github.com/appserver-io/appserver
30
 * @link      http://www.appserver.io
31
 */
32
class FileSystem
33
{
34
35
    /**
36
     * OS identifier strings as returned by FileSystem::getOsIdentifier().
37
     * There are a lot more possible values, but these are the most used ones
38
     * @see http://stackoverflow.com/questions/738823/possible-values-for-php-os
39
     * @see https://en.wikipedia.org/wiki/Uname#Table_of_standard_uname_output
40
     *
41
     * @var string OS_IDENTIFIER_LIN
42
     * @var string OS_IDENTIFIER_DARWIN
43
     * @var string OS_IDENTIFIER_WIN
44
     */
45
    const OS_IDENTIFIER_LINUX = 'LIN';
46
    const OS_IDENTIFIER_DARWIN = 'DAR';
47
    const OS_IDENTIFIER_WIN = 'WIN';
48
49
    /**
50
     * Chmod function
51
     *
52
     * @param string $path Relative or absolute path to a file or directory which should be processed.
53
     * @param int    $perm The permissions any file or dir should get.
54
55
     * @return bool
56
     */
57
    public static function chmod($path, $perm)
58
    {
59
60
        // don't do anything under Windows
61
        if (FileSystem::getOsIdentifier() === self::OS_IDENTIFIER_WIN) {
62
            return;
63
        }
64
65
        // change the mode
66
        if (chmod($path, $perm) === false) {
67
            throw new \Exception(sprintf('Can\'t change mode for directory %s to %s', $path, $perm));
68
        }
69
    }
70
71
    /**
72
     * Chown function
73
     *
74
     * @param string   $path  Relative or absolute path to a file or directory which should be processed.
75
     * @param int      $user  The user that should gain owner rights.
76
     * @param int|null $group The group that should gain group rights.
77
     *
78
     * @return bool
79
     */
80
    public static function chown($path, $user, $group = null)
81
    {
82
83
        // don't do anything under Windows
84
        if (FileSystem::getOsIdentifier() === self::OS_IDENTIFIER_WIN) {
85
            return;
86
        }
87
88
        // check if the path exists
89
        if (!file_exists($path)) {
90
            return false;
91
        }
92
93
        // change the owner
94
        if (chown($path, $user) === false) {
95
            throw new \Exception(sprintf('Can\'t change owner for directory/flie %s to %s', $path, $user));
96
        }
97
98
        // check if group is given too
99
        if (!is_null($group)) {
100
            if (chgrp($path, $group) === false) {
101
                throw new \Exception(sprintf('Can\'t change group for directory/flie %s to %s', $path, $group));
102
            }
103
        }
104
105
        return true;
106
    }
107
108
    /**
109
     * Deletes all files and subdirectories from the passed directory.
110
     *
111
     * @param \SplFileInfo $dir             The directory to remove
112
     * @param bool         $alsoRemoveFiles The flag for removing files also
113
     *
114
     * @return void
115
     */
116 4
    public static function cleanUpDir(\SplFileInfo $dir, $alsoRemoveFiles = true)
117
    {
118
119
        // first check if the directory exists, if not return immediately
120 4
        if ($dir->isDir() === false) {
121 1
            return;
122
        }
123
124
        // remove old archive from webapps folder recursively
125 3
        $files = new \RecursiveIteratorIterator(
126 3
            new \RecursiveDirectoryIterator($dir->getPathname()),
127
            \RecursiveIteratorIterator::CHILD_FIRST
128 3
        );
129
130 3
        foreach ($files as $file) {
131
            // skip . and .. dirs
132 3
            if ($file->getFilename() === '.' || $file->getFilename() === '..') {
133 3
                continue;
134
            }
135 3
            if ($file->isDir()) {
136 2
                @rmdir($file->getRealPath());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rmdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

136
                /** @scrutinizer ignore-unhandled */ @rmdir($file->getRealPath());

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
137 3
            } elseif ($file->isFile() && $alsoRemoveFiles) {
138 2
                unlink($file->getRealPath());
139 2
            } else {
140
                // do nothing, because file should NOT be deleted obviously
141
            }
142 3
        }
143 3
    }
144
145
    /**
146
     * Removes a directory recursively.
147
     *
148
     * @param string $src The source directory to be removed
149
     *
150
     * @return void
151
     */
152
    public static function removeDir($src)
153
    {
154
155
        // open the directory
156
        $dir = opendir($src);
157
158
        // remove files/folders recursively
159
        while (false !== ($file = readdir($dir))) {
0 ignored issues
show
Bug introduced by
It seems like $dir can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, 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

159
        while (false !== ($file = readdir(/** @scrutinizer ignore-type */ $dir))) {
Loading history...
160
            if (($file != '.') && ($file != '..')) {
161
                $full = $src . '/' . $file;
162
                if (is_dir($full)) {
163
                    FileSystem::removeDir($full);
164
                } else {
165
                    unlink($full);
166
                }
167
            }
168
        }
169
170
        // close handle and remove directory itself
171
        closedir($dir);
0 ignored issues
show
Bug introduced by
It seems like $dir can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, 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

171
        closedir(/** @scrutinizer ignore-type */ $dir);
Loading history...
172
        rmdir($src);
173
    }
174
175
    /**
176
     * Copies a directory recursively.
177
     *
178
     * @param string $src The source directory to copy
179
     * @param string $dst The target directory
180
     *
181
     * @return void
182
     */
183 5
    public static function copyDir($src, $dst)
184
    {
185 5
        if (is_link($src)) {
186 1
            symlink(readlink($src), $dst);
187 5
        } elseif (is_dir($src)) {
188 2
            if (is_dir($dst) === false) {
189 1
                mkdir($dst, 0775, true);
190 1
            }
191
            // copy files recursive
192 2
            foreach (scandir($src) as $file) {
193 2
                if ($file != '.' && $file != '..') {
194 2
                    FileSystem::copyDir("$src/$file", "$dst/$file");
195 2
                }
196 2
            }
197
198 4
        } elseif (is_file($src)) {
199 3
            copy($src, $dst);
200 3
        } else {
201
            // do nothing, we didn't have a directory to copy
202
        }
203 5
    }
204
205
    /**
206
     * Creates the passed directory.
207
     *
208
     * @param string  $directoryToCreate The directory that should be created
209
     * @param integer $mode              The mode to create the directory with
210
     * @param boolean $recursive         TRUE if the directory has to be created recursively, else FALSE
211
     *
212
     * @return void
213
     * @throws \Exception Is thrown if the directory can't be created
214
     */
215 3
    public static function createDirectory($directoryToCreate, $mode = 0775, $recursive = false)
216
    {
217
218
        // we don't have a directory to change the user/group permissions for
219 3
        if (is_dir($directoryToCreate) === false) {
220
            // create the directory if necessary
221 2
            if (mkdir($directoryToCreate, $mode, $recursive) === false) {
222
                throw new \Exception(sprintf('Directory %s can\'t be created', $directoryToCreate));
223
            }
224 2
        }
225 3
    }
226
227
    /**
228
     * Init the umask to use creating files/directories, either with
229
     * the passed value or the one found in the configuration.
230
     *
231
     * @param integer $umask The new umask to set
232
     *
233
     * @return void
234
     * @throws \Exception Is thrown if the umask can not be set
235
     */
236 1
    public static function initUmask($umask)
237
    {
238
239
        // don't do anything under Windows
240 1
        if (FileSystem::getOsIdentifier() === self::OS_IDENTIFIER_WIN) {
241
            return;
242
        }
243
244
        // set new umask to use
245 1
        umask($umask);
246
247
        // query whether the new umask has been set or not
248 1
        if (umask() != $umask) {
249
            throw new \Exception(sprintf('Can\'t set umask \'%s\' found \'%\' instead', $umask, umask()));
250
        }
251 1
    }
252
253
    /**
254
     * Will return a three character OS identifier e.g. WIN or LIN
255
     *
256
     * @return string
257
     */
258 4
    public static function getOsIdentifier()
259
    {
260 4
        return strtoupper(substr(PHP_OS, 0, 3));
261
    }
262
263
    /**
264
     * Parses and returns the directories and files that matches
265
     * the passed glob pattern in a recursive way (if wanted).
266
     *
267
     * @param string  $pattern   The glob pattern used to parse the directories
268
     * @param integer $flags     The flags passed to the glob function
269
     * @param boolean $recursive Whether or not to parse directories recursively
270
     *
271
     * @return array The directories matches the passed glob pattern
272
     * @link http://php.net/glob
273
     */
274 2
    public static function globDir($pattern, $flags = 0, $recursive = true)
275
    {
276
277
        // parse the first directory
278 2
        $files = glob($pattern, $flags);
279
280
        // parse all subdirectories, if recursive parsing is wanted
281 2
        if ($recursive !== false) {
282 2
            foreach (glob(dirname($pattern). DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR|GLOB_NOSORT|GLOB_BRACE) as $dir) {
283 1
                $files = array_merge($files, FileSystem::globDir($dir . DIRECTORY_SEPARATOR . basename($pattern), $flags));
0 ignored issues
show
Bug introduced by
It seems like $files can also be of type false; however, parameter $array1 of array_merge() 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

283
                $files = array_merge(/** @scrutinizer ignore-type */ $files, FileSystem::globDir($dir . DIRECTORY_SEPARATOR . basename($pattern), $flags));
Loading history...
284 2
            }
285 2
        }
286
287
        // return the array with the files matching the glob pattern
288 2
        return $files;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $files could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
289
    }
290
291
    /**
292
     * Will set the owner and group on the passed directory.
293
     *
294
     * @param string $path  The directory to set the rights for
295
     * @param string $user  The user to set
296
     * @param string $group The group to set
297
     *
298
     * @return void
299
     */
300
    public static function recursiveChown($path, $user, $group = null)
301
    {
302
303
        // we don't do anything under Windows
304
        if (FileSystem::getOsIdentifier() === self::OS_IDENTIFIER_WIN) {
305
            return;
306
        }
307
308
        // we don't have a directory to change the user/group permissions for
309
        if (is_dir($path) === false) {
310
            return;
311
        }
312
313
        // get all the files recursively
314
        $files = FileSystem::globDir($path . '/*');
315
316
        // query whether we've a user passed
317
        if (empty($user) === false) {
318
            // Change the rights of everything within the defined dirs
319
            foreach ($files as $file) {
320
                FileSystem::chown($file, $user, $group);
0 ignored issues
show
Bug introduced by
It seems like $group can also be of type string; however, parameter $group of AppserverIo\Appserver\Co...ies\FileSystem::chown() does only seem to accept integer|null, 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

320
                FileSystem::chown($file, $user, /** @scrutinizer ignore-type */ $group);
Loading history...
Bug introduced by
$user of type string is incompatible with the type integer expected by parameter $user of AppserverIo\Appserver\Co...ies\FileSystem::chown(). ( Ignorable by Annotation )

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

320
                FileSystem::chown($file, /** @scrutinizer ignore-type */ $user, $group);
Loading history...
321
            }
322
            FileSystem::chown($path, $user, $group);
323
        }
324
    }
325
326
    /**
327
     * Chmods files and folders with different permissions.
328
     *
329
     * This is an all-PHP alternative to using: \n
330
     * <tt>exec("find ".$path." -type f -exec chmod 644 {} \;");</tt> \n
331
     * <tt>exec("find ".$path." -type d -exec chmod 755 {} \;");</tt>
332
     *
333
     * @param string $path     Relative or absolute path to a file or directory which should be processed.
334
     * @param int    $filePerm The permissions any found files should get.
335
     * @param int    $dirPerm  The permissions any found folder should get.
336
     *
337
     * @return void
338
     */
339
    public static function recursiveChmod($path, $filePerm = 0644, $dirPerm = 0755)
340
    {
341
342
        // don't do anything under Windows
343
        if (FileSystem::getOsIdentifier() === self::OS_IDENTIFIER_WIN) {
344
            return;
345
        }
346
347
        // check if the directory exists
348
        if (is_dir($path) === false) {
349
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type void.
Loading history...
350
        }
351
352
        // get all the files recursively
353
        $files = FileSystem::globDir($path . '/*');
354
355
        // iterate over all directories and files
356
        foreach ($files as $file) {
357
            // see whether this is a file
358
            if (is_file($file)) {
359
                // chmod the file with our given file permissions
360
                FileSystem::chmod($file, $filePerm);
361
            // if this is a directory...
362
            } elseif (is_dir($file)) {
363
                // chmod the directory itself
364
                FileSystem::chmod($file, $dirPerm);
365
            }
366
        }
367
368
        // change the permmissions of the directory itself
369
        FileSystem::chmod($path, $dirPerm);
370
    }
371
}
372