Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.23% covered (success)
94.23%
49 / 52
84.62% covered (warning)
84.62%
11 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Directory
94.23% covered (success)
94.23%
49 / 52
84.62% covered (warning)
84.62%
11 / 13
32.20
0.00% covered (danger)
0.00%
0 / 1
 createDirectory
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 createDirectoryIfNotExists
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 createParentDirectoryIfNotExists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 exists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getChildrenCore
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
11
 getChildren
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDirectories
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 find
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
2.03
 removeDirectory
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
6.22
 cleanupDirectory
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setTemporaryDirectory
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getTemporaryDirectory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\IO;
6
7use PeServer\Core\Environment;
8use PeServer\Core\Errors\ErrorHandler;
9use PeServer\Core\IO\File;
10use PeServer\Core\IO\Path;
11use PeServer\Core\ResultData;
12use PeServer\Core\Throws\IOException;
13
14/**
15 * ディレクトリ処理系。
16 */
17abstract class Directory
18{
19    #region define
20
21    /** ディレクトリ作成時の通常権限。 */
22    public const DIRECTORY_PERMISSIONS = 0755;
23
24    #endregion
25
26    #region function
27
28    /**
29     * ディレクトリ作成する。
30     *
31     * ディレクトリは再帰的に作成される。
32     *
33     * `mkdir` ラッパー。
34     *
35     * @param string $directoryPath ディレクトリパス。
36     * @param int $permissions
37     * @return bool 作成出来たか。
38     * @see https://www.php.net/manual/function.mkdir.php
39     */
40    public static function createDirectory(string $directoryPath, int $permissions = self::DIRECTORY_PERMISSIONS): bool
41    {
42        $result = ErrorHandler::trap(fn () => mkdir($directoryPath, $permissions, true));
43        return $result->success && $result->value;
44    }
45
46    /**
47     * ディレクトリが存在しない場合に作成する。
48     *
49     * ディレクトリは再帰的に作成される。
50     *
51     * @param string $directoryPath ディレクトリパス
52     * @return bool 作成出来たか。
53     */
54    public static function createDirectoryIfNotExists(string $directoryPath, int $permissions = self::DIRECTORY_PERMISSIONS): bool
55    {
56        if (!file_exists($directoryPath)) {
57            return self::createDirectory($directoryPath, $permissions);
58        }
59
60        return false;
61    }
62
63    /**
64     * 対象パスの親ディレクトリが存在しない場合に親ディレクトリを作成する。
65     *
66     * ディレクトリは再帰的に作成される。
67     *
68     * @param string $path 対象パス(メソッド自体はファイルパスとして使用することを前提としている)
69     * @return bool 作成されたか。
70     */
71    public static function createParentDirectoryIfNotExists(string $path, int $permissions = self::DIRECTORY_PERMISSIONS): bool
72    {
73        return self::createDirectoryIfNotExists(dirname($path), $permissions);
74    }
75
76    /**
77     * ディレクトリが存在するか。
78     *
79     * `is_dir` ラッパー。
80     *
81     * @param string $path
82     * @return boolean 存在するか。
83     * @see https://www.php.net/manual/function.is-dir.php
84     */
85    public static function exists(string $path): bool
86    {
87        return is_dir($path);
88    }
89
90    /**
91     * ファイル/ディレクトリ一覧を取得する。
92     *
93     * @param string $directoryPath ディレクトリパス。
94     * @param boolean $file
95     * @param boolean $directory
96     * @param boolean $recursive 再帰的に取得するか。
97     * @return string[] ファイル一覧。
98     */
99    private static function getChildrenCore(string $directoryPath, bool $directory, bool $file, bool $recursive): array
100    {
101        /** @var string[] */
102        $files = [];
103        $result = ErrorHandler::trap(fn () => scandir($directoryPath, SCANDIR_SORT_NONE));
104        // $items = scandir($directoryPath);
105        if ($result->isFailureOrFalse()) {
106            return $files;
107        }
108        $items = $result->value;
109
110        foreach ($items as $item) {
111            if ($item === '.' || $item === '..') {
112                continue;
113            }
114
115            $path = Path::combine($directoryPath, $item);
116
117            $isDir = self::exists($path);
118
119            if ($isDir && $directory) {
120                $files[] = $path;
121            } elseif (!$isDir && $file) {
122                $files[] = $path;
123            }
124
125            if ($isDir && $recursive) {
126                $files = array_merge($files, self::getChildrenCore($path, $directory, $file, $recursive));
127            }
128        }
129
130        return $files;
131    }
132
133    /**
134     * ファイル/ディレクトリ一覧を取得する。
135     *
136     * @param string $directoryPath ディレクトリパス。
137     * @param boolean $recursive 再帰的に取得するか。
138     * @return string[] ファイル一覧。
139     */
140    public static function getChildren(string $directoryPath, bool $recursive): array
141    {
142        return self::getChildrenCore($directoryPath, true, true, $recursive);
143    }
144
145    /**
146     * ファイル一覧を取得する。
147     *
148     * @param string $directoryPath ディレクトリパス。
149     * @param boolean $recursive 再帰的に取得するか。
150     * @return string[] ファイル一覧。
151     */
152    public static function getFiles(string $directoryPath, bool $recursive): array
153    {
154        return self::getChildrenCore($directoryPath, false, true, $recursive);
155    }
156
157    /**
158     * ディレクトリ一覧を取得する。
159     *
160     * @param string $directoryPath ディレクトリパス。
161     * @param boolean $recursive 再帰的に取得するか。
162     * @return string[] ファイル一覧。
163     */
164    public static function getDirectories(string $directoryPath, bool $recursive): array
165    {
166        return self::getChildrenCore($directoryPath, true, false, $recursive);
167    }
168
169    /**
170     * パターンに一致するファイル・ディレクトリ一覧取得。
171     *
172     * `glob` ラッパー。
173     *
174     * @param string $directoryPath ディレクトリパス
175     * @param string $wildcard ワイルドカード。
176     * @return string[] 一覧。
177     * @throws IOException
178     * @see https://www.php.net/manual/function.glob.php
179     */
180    public static function find(string $directoryPath, string $wildcard): array
181    {
182        $pattern = Path::combine($directoryPath, $wildcard);
183        $items = glob($pattern, GLOB_MARK);
184        if ($items === false) {
185            throw new IOException();
186        }
187
188        return $items;
189    }
190
191    /**
192     * ディレクトリを削除する。
193     * ファイル・ディレクトリはすべて破棄される。
194     *
195     * @param string $directoryPath 削除ディレクトリ。
196     * @param bool $recursive 再帰的削除を行うか。
197     * @return bool
198     * @throws IOException
199     */
200    public static function removeDirectory(string $directoryPath, bool $recursive = false): bool
201    {
202        if ($recursive) {
203            $files = self::getChildren($directoryPath, false);
204            foreach ($files as $file) {
205                if (self::exists($file)) {
206                    if (!self::removeDirectory($file, true)) {
207                        return false;
208                    }
209                } else {
210                    File::removeFile($file);
211                }
212            }
213        }
214
215        $result = ErrorHandler::trap(fn () => rmdir($directoryPath));
216        if ($result->isFailureOrFalse()) {
217            throw new IOException();
218        }
219
220        return $result->value;
221    }
222
223    /**
224     * ディレクトリを破棄・作成する
225     *
226     * @param string $directoryPath 対象ディレクトリ。
227     * @return void
228     */
229    public static function cleanupDirectory(string $directoryPath, int $permissions = self::DIRECTORY_PERMISSIONS): void
230    {
231        if (self::exists($directoryPath)) {
232            self::removeDirectory($directoryPath, true);
233        }
234        self::createDirectory($directoryPath, $permissions);
235    }
236
237    /**
238     * 一時ディレクトリ設定。
239     *
240     * @param string $path
241     * @return bool
242     */
243    public static function setTemporaryDirectory(string $path): bool
244    {
245        self::createDirectoryIfNotExists($path);
246
247        Environment::setVariable('TMP', $path);
248        Environment::setVariable('TMPDIR', $path); //cspell:disable-line
249        Environment::setVariable('TEMP', $path);
250
251        return true;
252    }
253
254    /**
255     * 一時ディレクトリ取得。
256     *
257     * `sys_get_temp_di` ラッパー。
258     *
259     * @return string
260     * @see https://www.php.net/manual/function.sys-get-temp-dir.php
261     */
262    public static function getTemporaryDirectory(): string
263    {
264        return sys_get_temp_dir();
265    }
266
267    #endregion
268}