]> BookStack Code Mirror - system-cli/blob - src/Services/Directories.php
Addressed further symlink issues
[system-cli] / src / Services / Directories.php
1 <?php declare(strict_types=1);
2
3 namespace Cli\Services;
4 use FilesystemIterator;
5 use RecursiveDirectoryIterator;
6 use RecursiveIteratorIterator;
7 use SplFileInfo;
8
9 class Directories
10 {
11
12     public static function move(string $src, string $target): void
13     {
14         static::copy($src, $target);
15         static::delete($src);
16     }
17
18     public static function copy(string $src, string $target): void
19     {
20         if (!file_exists($target)) {
21             mkdir($target);
22         }
23
24         /** @var RecursiveDirectoryIterator $files */
25         $files = new RecursiveIteratorIterator(
26             new RecursiveDirectoryIterator($src, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),
27             RecursiveIteratorIterator::SELF_FIRST
28         );
29
30         /** @var SplFileInfo $fileinfo */
31         foreach ($files as $fileinfo) {
32             $srcPath = $fileinfo->getRealPath();
33             $subPath = $files->getSubPathName();
34             $destPath = Paths::join($target, $subPath);
35             $result = true;
36             if ($fileinfo->isDir() && !file_exists($destPath)) {
37                 echo $destPath . "\n";
38                 $result = mkdir($destPath);
39             } else if ($fileinfo->isFile()) {
40                 $result = copy($srcPath, $destPath);
41             }
42
43             if ($result === false) {
44                 throw new \Exception("Failed to copy file or directory from {$srcPath} to {$destPath}");
45             }
46         }
47     }
48
49     /**
50      * Delete the contents of the given directory.
51      * Will not delete symlinked folders to ensure that symlinks remain consistent,
52      * but will aim to delete contents of symlinked folders.
53      */
54     public static function delete(string $dir): void
55     {
56         $files = new RecursiveIteratorIterator(
57             new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),
58             RecursiveIteratorIterator::CHILD_FIRST
59         );
60
61         $links = '::';
62
63         /** @var SplFileInfo $fileinfo */
64         foreach ($files as $fileinfo) {
65             $path = $fileinfo->getRealPath();
66             $result = true;
67             if ($fileinfo->isDir()) {
68                 if ($fileinfo->isLink()) {
69                     $links .= $fileinfo->getPath() . '::';
70                 } else if (!str_contains($links, '::' . $path)) {
71                     $result = rmdir($path);
72                 }
73             } else if ($fileinfo->isFile()) {
74                 $result = unlink($path);
75             }
76
77             if ($result === false) {
78                 throw new \Exception("Failed to delete file or directory at {$path}");
79             }
80         }
81
82         if ($links === '::') {
83             rmdir($dir);
84         }
85     }
86 }