PluginProbe
ManageWP Worker / 4.9.25
ManageWP Worker v4.9.25
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / src / Symfony / Filesystem / Filesystem.php

Filesystem.php in ManageWP Worker 4.9.25, at src/Symfony/Filesystem/Filesystem.php

483 lines 18.8 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 Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 /**
13 * Provides basic utility to manipulate the file system.
14 *
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17 class Symfony_Filesystem_Filesystem
18 {
19 /**
20 * Copies a file.
21 *
22 * This method only copies the file if the origin file is newer than the target file.
23 *
24 * By default, if the target already exists, it is not overridden.
25 *
26 * @param string $originFile The original filename
27 * @param string $targetFile The target filename
28 * @param bool $override Whether to override an existing file or not
29 *
30 * @throws Symfony_Filesystem_Exception_FileNotFoundException When originFile doesn't exist
31 * @throws Symfony_Filesystem_Exception_IOException When copy fails
32 */
33 public function copy($originFile, $targetFile, $override = false)
34 {
35 if (stream_is_local($originFile) && !is_file($originFile)) {
36 throw new Symfony_Filesystem_Exception_FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
37 }
38
39 $this->mkdir(dirname($targetFile));
40
41 if (!$override && is_file($targetFile)) {
42 $doCopy = filemtime($originFile) > filemtime($targetFile);
43 } else {
44 $doCopy = true;
45 }
46
47 if ($doCopy) {
48 // https://bugs.php.net/bug.php?id=64634
49 $source = fopen($originFile, 'r');
50 $target = fopen($targetFile, 'w+');
51 stream_copy_to_stream($source, $target);
52 fclose($source);
53 fclose($target);
54 unset($source, $target);
55
56 if (!is_file($targetFile)) {
57 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
58 }
59 }
60 }
61
62 /**
63 * Creates a directory recursively.
64 *
65 * @param string|array|Traversable $dirs The directory path
66 * @param integer $mode The directory mode
67 *
68 * @throws Symfony_Filesystem_Exception_IOException On any directory creation failure
69 */
70 public function mkdir($dirs, $mode = 0777)
71 {
72 foreach ($this->toIterator($dirs) as $dir) {
73 if (is_dir($dir)) {
74 continue;
75 }
76
77 if (true !== @mkdir($dir, $mode, true)) {
78 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to create "%s".', $dir), 0, null, $dir);
79 }
80 }
81 }
82
83 /**
84 * Checks the existence of files or directories.
85 *
86 * @param string|array|Traversable $files A filename, an array of files, or a Traversable instance to check
87 *
88 * @return bool true if the file exists, false otherwise
89 */
90 public function exists($files)
91 {
92 foreach ($this->toIterator($files) as $file) {
93 if (!file_exists($file)) {
94 return false;
95 }
96 }
97
98 return true;
99 }
100
101 /**
102 * Sets access and modification time of file.
103 *
104 * @param string|array|Traversable $files A filename, an array of files, or a Traversable instance to create
105 * @param integer $time The touch time as a unix timestamp
106 * @param integer $atime The access time as a unix timestamp
107 *
108 * @throws Symfony_Filesystem_Exception_IOException When touch fails
109 */
110 public function touch($files, $time = null, $atime = null)
111 {
112 foreach ($this->toIterator($files) as $file) {
113 $touch = $time ? @touch($file, $time, $atime) : @touch($file);
114 if (true !== $touch) {
115 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
116 }
117 }
118 }
119
120 /**
121 * Removes files or directories.
122 *
123 * @param string|array|Traversable $files A filename, an array of files, or a Traversable instance to remove
124 *
125 * @throws Symfony_Filesystem_Exception_IOException When removal fails
126 */
127 public function remove($files)
128 {
129 $files = iterator_to_array($this->toIterator($files));
130 $files = array_reverse($files);
131 foreach ($files as $file) {
132 if (!file_exists($file) && !is_link($file)) {
133 continue;
134 }
135
136 if (is_dir($file) && !is_link($file)) {
137 $this->remove(new Symfony_Filesystem_FilesystemIterator($file));
138
139 if (true !== @rmdir($file)) {
140 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to remove directory "%s".', $file), 0, null, $file);
141 }
142 } else {
143 // https://bugs.php.net/bug.php?id=52176
144 if ($this->isWindows() && is_dir($file)) {
145 if (true !== @rmdir($file)) {
146 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
147 }
148 } else {
149 if (true !== @unlink($file)) {
150 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
151 }
152 }
153 }
154 }
155 }
156
157 /**
158 * Change mode for an array of files or directories.
159 *
160 * @param string|array|Traversable $files A filename, an array of files, or a Traversable instance to change mode
161 * @param integer $mode The new mode (octal)
162 * @param integer $umask The mode mask (octal)
163 * @param bool $recursive Whether change the mod recursively or not
164 *
165 * @throws Symfony_Filesystem_Exception_IOException When the change fail
166 */
167 public function chmod($files, $mode, $umask = 0000, $recursive = false)
168 {
169 foreach ($this->toIterator($files) as $file) {
170 if ($recursive && is_dir($file) && !is_link($file)) {
171 $this->chmod(new Symfony_Filesystem_FilesystemIterator($file), $mode, $umask, true);
172 }
173 if (true !== @chmod($file, $mode & ~$umask)) {
174 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
175 }
176 }
177 }
178
179 /**
180 * Change the owner of an array of files or directories
181 *
182 * @param string|array|Traversable $files A filename, an array of files, or a Traversable instance to change owner
183 * @param string $user The new owner user name
184 * @param bool $recursive Whether change the owner recursively or not
185 *
186 * @throws Symfony_Filesystem_Exception_IOException When the change fail
187 */
188 public function chown($files, $user, $recursive = false)
189 {
190 foreach ($this->toIterator($files) as $file) {
191 if ($recursive && is_dir($file) && !is_link($file)) {
192 $this->chown(new Symfony_Filesystem_FilesystemIterator($file), $user, true);
193 }
194 if (is_link($file) && function_exists('lchown')) {
195 if (true !== @lchown($file, $user)) {
196 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
197 }
198 } else {
199 if (true !== @chown($file, $user)) {
200 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
201 }
202 }
203 }
204 }
205
206 /**
207 * Change the group of an array of files or directories
208 *
209 * @param string|array|Traversable $files A filename, an array of files, or a Traversable instance to change group
210 * @param string $group The group name
211 * @param bool $recursive Whether change the group recursively or not
212 *
213 * @throws Symfony_Filesystem_Exception_IOException When the change fail
214 */
215 public function chgrp($files, $group, $recursive = false)
216 {
217 foreach ($this->toIterator($files) as $file) {
218 if ($recursive && is_dir($file) && !is_link($file)) {
219 $this->chgrp(new Symfony_Filesystem_FilesystemIterator($file), $group, true);
220 }
221 if (is_link($file) && function_exists('lchgrp')) {
222 if (true !== @lchgrp($file, $group)) {
223 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
224 }
225 } else {
226 if (true !== @chgrp($file, $group)) {
227 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
228 }
229 }
230 }
231 }
232
233 /**
234 * Renames a file or a directory.
235 *
236 * @param string $origin The origin filename or directory
237 * @param string $target The new filename or directory
238 * @param bool $overwrite Whether to overwrite the target if it already exists
239 *
240 * @throws Symfony_Filesystem_Exception_IOException When target file or directory already exists
241 * @throws Symfony_Filesystem_Exception_IOException When origin cannot be renamed
242 */
243 public function rename($origin, $target, $overwrite = false)
244 {
245 // we check that target does not exist
246 if (!$overwrite && is_readable($target)) {
247 throw new Symfony_Filesystem_Exception_IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
248 }
249
250 if (true !== @rename($origin, $target)) {
251 throw new Symfony_Filesystem_Exception_IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
252 }
253 }
254
255 /**
256 * Creates a symbolic link or copy a directory.
257 *
258 * @param string $originDir The origin directory path
259 * @param string $targetDir The symbolic link name
260 * @param bool $copyOnWindows Whether to copy files if on Windows
261 *
262 * @throws Symfony_Filesystem_Exception_IOException When symlink fails
263 *
264 * Warning: DO NOT call this function "s y m l i n k", the whole file gets deleted by some "very advanced" antivirus checker.
265 */
266 public function symboliclink($originDir, $targetDir, $copyOnWindows = false)
267 {
268 if (!function_exists('symlink') && $copyOnWindows) {
269 $this->mirror($originDir, $targetDir);
270
271 return;
272 }
273
274 $this->mkdir(dirname($targetDir));
275
276 $ok = false;
277 if (is_link($targetDir)) {
278 if (readlink($targetDir) != $originDir) {
279 $this->remove($targetDir);
280 } else {
281 $ok = true;
282 }
283 }
284
285 if (!$ok) {
286 $fn = 'symlink';
287 if (true !== @$fn($originDir, $targetDir)) {
288 $report = error_get_last();
289 if (is_array($report)) {
290 if ($this->isWindows() && false !== strpos($report['message'], 'error code(1314)')) {
291 throw new Symfony_Filesystem_Exception_IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
292 }
293 }
294
295 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
296 }
297 }
298 }
299
300 /**
301 * Given an existing path, convert it to a path relative to a given starting path
302 *
303 * @param string $endPath Absolute path of target
304 * @param string $startPath Absolute path where traversal begins
305 *
306 * @return string Path of target relative to starting path
307 */
308 public function makePathRelative($endPath, $startPath)
309 {
310 // Normalize separators on windows
311 if ($this->isWindows()) {
312 $endPath = strtr($endPath, '\\', '/');
313 $startPath = strtr($startPath, '\\', '/');
314 }
315
316 // Split the paths into arrays
317 $startPathArr = explode('/', trim($startPath, '/'));
318 $endPathArr = explode('/', trim($endPath, '/'));
319
320 $index = 0;
321 $depth = 0;
322 if ($startPath !== '/') {
323 // Find for which directory the common path stops
324 while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
325 $index++;
326 }
327
328 // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
329 $depth = count($startPathArr) - $index;
330 }
331
332 // Repeated "../" for each level need to reach the common path
333 $traverser = str_repeat('../', $depth);
334
335 $endPathRemainder = implode('/', array_slice($endPathArr, $index));
336
337 // Construct $endPath from traversing to the common path, then to the remaining $endPath
338 $relativePath = $traverser.(strlen($endPathRemainder) > 0 ? $endPathRemainder.'/' : '');
339
340 return (strlen($relativePath) === 0) ? './' : $relativePath;
341 }
342
343 /**
344 * Mirrors a directory to another.
345 *
346 * @param string $originDir The origin directory
347 * @param string $targetDir The target directory
348 * @param Traversable $iterator A Traversable instance
349 * @param array $options An array of boolean options
350 * Valid options are:
351 * - $options['override'] Whether to override an existing file on copy or not (see copy())
352 * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see sym_link() without the underscore)
353 * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
354 *
355 * @throws Symfony_Filesystem_Exception_IOException When file type is unknown
356 */
357 public function mirror($originDir, $targetDir, Traversable $iterator = null, $options = array())
358 {
359 $targetDir = rtrim($targetDir, '/\\');
360 $originDir = rtrim($originDir, '/\\');
361
362 // Iterate in destination folder to remove obsolete entries
363 if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
364 $deleteIterator = $iterator;
365 if (null === $deleteIterator) {
366 $flags = Symfony_Filesystem_FilesystemIterator::SKIP_DOTS;
367 $deleteIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($targetDir, $flags), RecursiveIteratorIterator::CHILD_FIRST);
368 }
369 /** @var SplFileObject $file */
370 foreach ($deleteIterator as $file) {
371 $origin = str_replace($targetDir, $originDir, $file->getPathname());
372 if (!$this->exists($origin)) {
373 $this->remove($file);
374 }
375 }
376 }
377
378 $copyOnWindows = false;
379 if (isset($options['copy_on_windows']) && !function_exists('symlink')) {
380 $copyOnWindows = $options['copy_on_windows'];
381 }
382
383 if (null === $iterator) {
384 $flags = $copyOnWindows ? Symfony_Filesystem_FilesystemIterator::SKIP_DOTS | Symfony_Filesystem_FilesystemIterator::FOLLOW_SYMLINKS : Symfony_Filesystem_FilesystemIterator::SKIP_DOTS;
385 $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($originDir, $flags), RecursiveIteratorIterator::SELF_FIRST);
386 }
387
388 foreach ($iterator as $file) {
389 $target = str_replace($originDir, $targetDir, $file->getPathname());
390
391 if ($copyOnWindows) {
392 if (is_link($file) || is_file($file)) {
393 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
394 } elseif (is_dir($file)) {
395 $this->mkdir($target);
396 } else {
397 throw new Symfony_Filesystem_Exception_IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
398 }
399 } else {
400 if (is_link($file)) {
401 $this->symboliclink($file, $target);
402 } elseif (is_dir($file)) {
403 $this->mkdir($target);
404 } elseif (is_file($file)) {
405 $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
406 } else {
407 throw new Symfony_Filesystem_Exception_IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
408 }
409 }
410 }
411 }
412
413 /**
414 * Returns whether the file path is an absolute path.
415 *
416 * @param string $file A file path
417 *
418 * @return bool
419 */
420 public function isAbsolutePath($file)
421 {
422 if (strspn($file, '/\\', 0, 1)
423 || (strlen($file) > 3 && ctype_alpha($file[0])
424 && substr($file, 1, 1) === ':'
425 && (strspn($file, '/\\', 2, 1))
426 )
427 || null !== parse_url($file, PHP_URL_SCHEME)
428 ) {
429 return true;
430 }
431
432 return false;
433 }
434
435 /**
436 * Atomically dumps content into a file.
437 *
438 * @param string $filename The file to be written to.
439 * @param string $content The data to write into the file.
440 * @param integer $mode The file mode (octal).
441 *
442 * @throws Symfony_Filesystem_Exception_IOException If the file cannot be written to.
443 */
444 public function dumpFile($filename, $content, $mode = 0666)
445 {
446 $dir = dirname($filename);
447
448 if (!is_dir($dir)) {
449 $this->mkdir($dir);
450 } elseif (!is_writable($dir)) {
451 throw new Symfony_Filesystem_Exception_IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
452 }
453
454 $tmpFile = tempnam($dir, basename($filename));
455
456 if (false === @file_put_contents($tmpFile, $content)) {
457 throw new Symfony_Filesystem_Exception_IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
458 }
459
460 $this->rename($tmpFile, $filename, true);
461 $this->chmod($filename, $mode);
462 }
463
464 /**
465 * @param mixed $files
466 *
467 * @return Traversable
468 */
469 private function toIterator($files)
470 {
471 if (!$files instanceof Traversable) {
472 $files = new ArrayObject(is_array($files) ? $files : array($files));
473 }
474
475 return $files;
476 }
477
478 private function isWindows()
479 {
480 return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
481 }
482 }
483