PluginProbe
Age Gate / 3.7.3
Age Gate v3.7.3
3.7.3 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 All 113 releases
age-gate / vendor / nette / utils / src / Utils / FileSystem.php

FileSystem.php in Age Gate 3.7.3, at vendor/nette/utils/src/Utils/FileSystem.php

263 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7
8 declare(strict_types=1);
9
10 namespace Nette\Utils;
11
12 use Nette;
13
14
15 /**
16 * File system tool.
17 */
18 final class FileSystem
19 {
20 use Nette\StaticClass;
21
22 /**
23 * Creates a directory if it does not exist, including parent directories.
24 * @throws Nette\IOException on error occurred
25 */
26 public static function createDir(string $dir, int $mode = 0777): void
27 {
28 if (!is_dir($dir) && !@mkdir($dir, $mode, true) && !is_dir($dir)) { // @ - dir may already exist
29 throw new Nette\IOException(sprintf(
30 "Unable to create directory '%s' with mode %s. %s",
31 self::normalizePath($dir),
32 decoct($mode),
33 Helpers::getLastError()
34 ));
35 }
36 }
37
38
39 /**
40 * Copies a file or an entire directory. Overwrites existing files and directories by default.
41 * @throws Nette\IOException on error occurred
42 * @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists
43 */
44 public static function copy(string $origin, string $target, bool $overwrite = true): void
45 {
46 if (stream_is_local($origin) && !file_exists($origin)) {
47 throw new Nette\IOException(sprintf("File or directory '%s' not found.", self::normalizePath($origin)));
48
49 } elseif (!$overwrite && file_exists($target)) {
50 throw new Nette\InvalidStateException(sprintf("File or directory '%s' already exists.", self::normalizePath($target)));
51
52 } elseif (is_dir($origin)) {
53 static::createDir($target);
54 foreach (new \FilesystemIterator($target) as $item) {
55 static::delete($item->getPathname());
56 }
57
58 foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($origin, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) {
59 if ($item->isDir()) {
60 static::createDir($target . '/' . $iterator->getSubPathName());
61 } else {
62 static::copy($item->getPathname(), $target . '/' . $iterator->getSubPathName());
63 }
64 }
65 } else {
66 static::createDir(dirname($target));
67 if (
68 ($s = @fopen($origin, 'rb'))
69 && ($d = @fopen($target, 'wb'))
70 && @stream_copy_to_stream($s, $d) === false
71 ) { // @ is escalated to exception
72 throw new Nette\IOException(sprintf(
73 "Unable to copy file '%s' to '%s'. %s",
74 self::normalizePath($origin),
75 self::normalizePath($target),
76 Helpers::getLastError()
77 ));
78 }
79 }
80 }
81
82
83 /**
84 * Deletes a file or an entire directory if exists. If the directory is not empty, it deletes its contents first.
85 * @throws Nette\IOException on error occurred
86 */
87 public static function delete(string $path): void
88 {
89 if (is_file($path) || is_link($path)) {
90 $func = DIRECTORY_SEPARATOR === '\\' && is_dir($path) ? 'rmdir' : 'unlink';
91 if (!@$func($path)) { // @ is escalated to exception
92 throw new Nette\IOException(sprintf(
93 "Unable to delete '%s'. %s",
94 self::normalizePath($path),
95 Helpers::getLastError()
96 ));
97 }
98 } elseif (is_dir($path)) {
99 foreach (new \FilesystemIterator($path) as $item) {
100 static::delete($item->getPathname());
101 }
102
103 if (!@rmdir($path)) { // @ is escalated to exception
104 throw new Nette\IOException(sprintf(
105 "Unable to delete directory '%s'. %s",
106 self::normalizePath($path),
107 Helpers::getLastError()
108 ));
109 }
110 }
111 }
112
113
114 /**
115 * Renames or moves a file or a directory. Overwrites existing files and directories by default.
116 * @throws Nette\IOException on error occurred
117 * @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists
118 */
119 public static function rename(string $origin, string $target, bool $overwrite = true): void
120 {
121 if (!$overwrite && file_exists($target)) {
122 throw new Nette\InvalidStateException(sprintf("File or directory '%s' already exists.", self::normalizePath($target)));
123
124 } elseif (!file_exists($origin)) {
125 throw new Nette\IOException(sprintf("File or directory '%s' not found.", self::normalizePath($origin)));
126
127 } else {
128 static::createDir(dirname($target));
129 if (realpath($origin) !== realpath($target)) {
130 static::delete($target);
131 }
132
133 if (!@rename($origin, $target)) { // @ is escalated to exception
134 throw new Nette\IOException(sprintf(
135 "Unable to rename file or directory '%s' to '%s'. %s",
136 self::normalizePath($origin),
137 self::normalizePath($target),
138 Helpers::getLastError()
139 ));
140 }
141 }
142 }
143
144
145 /**
146 * Reads the content of a file.
147 * @throws Nette\IOException on error occurred
148 */
149 public static function read(string $file): string
150 {
151 $content = @file_get_contents($file); // @ is escalated to exception
152 if ($content === false) {
153 throw new Nette\IOException(sprintf(
154 "Unable to read file '%s'. %s",
155 self::normalizePath($file),
156 Helpers::getLastError()
157 ));
158 }
159
160 return $content;
161 }
162
163
164 /**
165 * Writes the string to a file.
166 * @throws Nette\IOException on error occurred
167 */
168 public static function write(string $file, string $content, ?int $mode = 0666): void
169 {
170 static::createDir(dirname($file));
171 if (@file_put_contents($file, $content) === false) { // @ is escalated to exception
172 throw new Nette\IOException(sprintf(
173 "Unable to write file '%s'. %s",
174 self::normalizePath($file),
175 Helpers::getLastError()
176 ));
177 }
178
179 if ($mode !== null && !@chmod($file, $mode)) { // @ is escalated to exception
180 throw new Nette\IOException(sprintf(
181 "Unable to chmod file '%s' to mode %s. %s",
182 self::normalizePath($file),
183 decoct($mode),
184 Helpers::getLastError()
185 ));
186 }
187 }
188
189
190 /**
191 * Sets file permissions to `$fileMode` or directory permissions to `$dirMode`.
192 * Recursively traverses and sets permissions on the entire contents of the directory as well.
193 * @throws Nette\IOException on error occurred
194 */
195 public static function makeWritable(string $path, int $dirMode = 0777, int $fileMode = 0666): void
196 {
197 if (is_file($path)) {
198 if (!@chmod($path, $fileMode)) { // @ is escalated to exception
199 throw new Nette\IOException(sprintf(
200 "Unable to chmod file '%s' to mode %s. %s",
201 self::normalizePath($path),
202 decoct($fileMode),
203 Helpers::getLastError()
204 ));
205 }
206 } elseif (is_dir($path)) {
207 foreach (new \FilesystemIterator($path) as $item) {
208 static::makeWritable($item->getPathname(), $dirMode, $fileMode);
209 }
210
211 if (!@chmod($path, $dirMode)) { // @ is escalated to exception
212 throw new Nette\IOException(sprintf(
213 "Unable to chmod directory '%s' to mode %s. %s",
214 self::normalizePath($path),
215 decoct($dirMode),
216 Helpers::getLastError()
217 ));
218 }
219 } else {
220 throw new Nette\IOException(sprintf("File or directory '%s' not found.", self::normalizePath($path)));
221 }
222 }
223
224
225 /**
226 * Determines if the path is absolute.
227 */
228 public static function isAbsolute(string $path): bool
229 {
230 return (bool) preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
231 }
232
233
234 /**
235 * Normalizes `..` and `.` and directory separators in path.
236 */
237 public static function normalizePath(string $path): string
238 {
239 $parts = $path === '' ? [] : preg_split('~[/\\\\]+~', $path);
240 $res = [];
241 foreach ($parts as $part) {
242 if ($part === '..' && $res && end($res) !== '..' && end($res) !== '') {
243 array_pop($res);
244 } elseif ($part !== '.') {
245 $res[] = $part;
246 }
247 }
248
249 return $res === ['']
250 ? DIRECTORY_SEPARATOR
251 : implode(DIRECTORY_SEPARATOR, $res);
252 }
253
254
255 /**
256 * Joins all segments of the path and normalizes the result.
257 */
258 public static function joinPaths(string ...$paths): string
259 {
260 return self::normalizePath(implode('/', $paths));
261 }
262 }
263