Completed
Pull Request — master (#1105)
by Tim
42:55
created

FileSystem::recursiveChown()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 5
nop 3
dl 0
loc 23
ccs 0
cts 11
cp 0
crap 30
rs 9.6111
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 4
     *
111
     * @param \SplFileInfo $dir             The directory to remove
112
     * @param bool         $alsoRemoveFiles The flag for removing files also
113
     *
114 4
     * @return void
115 1
     */
116
    public static function cleanUpDir(\SplFileInfo $dir, $alsoRemoveFiles = true)
117
    {
118
119 3
        // first check if the directory exists, if not return immediately
120 3
        if ($dir->isDir() === false) {
121
            return;
122 3
        }
123
124 3
        // remove old archive from webapps folder recursively
125
        $files = new \RecursiveIteratorIterator(
126 3
            new \RecursiveDirectoryIterator($dir->getPathname()),
127 3
            \RecursiveIteratorIterator::CHILD_FIRST
128
        );
129 3
130 2
        foreach ($files as $file) {
131 3
            // skip . and .. dirs
132 2
            if ($file->getFilename() === '.' || $file->getFilename() === '..') {
133 2
                continue;
134
            }
135
            if ($file->isDir()) {
136 3
                @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
                unlink($file->getRealPath());
139
            } else {
140
                // do nothing, because file should NOT be deleted obviously
141
            }
142
        }
143
    }
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 5
     *
178
     * @param string $src The source directory to copy
179 5
     * @param string $dst The target directory
180 1
     *
181 5
     * @return void
182 2
     */
183 1
    public static function copyDir($src, $dst)
184 1
    {
185
        if (is_link($src)) {
186 2
            symlink(readlink($src), $dst);
187 2
        } elseif (is_dir($src)) {
188 2
            if (is_dir($dst) === false) {
189 2
                mkdir($dst, 0775, true);
190 2
            }
191
            // copy files recursive
192 4
            foreach (scandir($src) as $file) {
193 3
                if ($file != '.' && $file != '..') {
194 3
                    FileSystem::copyDir("$src/$file", "$dst/$file");
195
                }
196
            }
197 5
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
198
        } elseif (is_file($src)) {
199
            copy($src, $dst);
200
        } else {
201
            // do nothing, we didn't have a directory to copy
202
        }
203
    }
204
205
    /**
206
     * Creates the passed directory.
207
     *
208
     * @param string  $directoryToCreate The directory that should be created
209 3
     * @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 3
     * @throws \Exception Is thrown if the directory can't be created
214
     */
215 2
    public static function createDirectory($directoryToCreate, $mode = 0775, $recursive = false)
216
    {
217
218 2
        // 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
            if (mkdir($directoryToCreate, $mode, $recursive) === false) {
222
                throw new \Exception(sprintf('Directory %s can\'t be created', $directoryToCreate));
223
            }
224
        }
225
    }
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 1
     *
231
     * @param integer $umask The new umask to set
232
     *
233
     * @return void
234 1
     * @throws \Exception Is thrown if the umask can not be set
235
     */
236
    public static function initUmask($umask)
237
    {
238
239 1
        // don't do anything under Windows
240
        if (FileSystem::getOsIdentifier() === self::OS_IDENTIFIER_WIN) {
241
            return;
242 1
        }
243
244
        // set new umask to use
245 1
        umask($umask);
246
247
        // query whether the new umask has been set or not
248
        if (umask() != $umask) {
249
            throw new \Exception(sprintf('Can\'t set umask \'%s\' found \'%\' instead', $umask, umask()));
250
        }
251
    }
252 4
253
    /**
254 4
     * Will return a three character OS identifier e.g. WIN or LIN
255
     *
256
     * @return string
257
     */
258
    public static function getOsIdentifier()
259
    {
260
        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 2
     * @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 2
     * @link http://php.net/glob
273
     */
274
    public static function globDir($pattern, $flags = 0, $recursive = true)
275 2
    {
276 2
277 1
        // parse the first directory
278 2
        $files = glob($pattern, $flags);
279 2
280
        // parse all subdirectories, if recursive parsing is wanted
281
        if ($recursive !== false) {
282 2
            foreach (glob(dirname($pattern). DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR|GLOB_NOSORT|GLOB_BRACE) as $dir) {
283
                $files = array_merge($files, FileSystem::globDir($dir . DIRECTORY_SEPARATOR . basename($pattern), $flags));
284
            }
285
        }
286
287
        // return the array with the files matching the glob pattern
288
        return $files;
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 null|integer, 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