Completed
Push — master ( 4a0612...17e4c8 )
by duan
02:14
created

Filesystem::copyDirectory()   B

Complexity

Conditions 8
Paths 11

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 8.4218

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 31
ccs 13
cts 16
cp 0.8125
rs 8.4444
c 0
b 0
f 0
cc 8
nc 11
nop 3
crap 8.4218
1
<?php
2
3
namespace Yiranzai\Tools;
4
5
use Exception;
6
use FilesystemIterator;
7
use Symfony\Component\Filesystem\Exception\IOException;
8
use Symfony\Component\Filesystem\Filesystem as FilesystemAlias;
9
10
class Filesystem extends FilesystemAlias
11
{
12
13
    /**
14
     * Store an item in the cache for a given number of minutes.
15
     *
16
     * @param string $path
17
     * @param string $contents
18
     * @param bool   $lock
19
     * @return bool|int
20
     */
21 3
    public function put($path, $contents, $lock = false)
22
    {
23 3
        $this->ensureCacheDirectoryExists($path);
24 3
        return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
25
    }
26
27
    /**
28
     * Create the file cache directory if necessary.
29
     *
30
     * @param string $path
31
     * @return void
32
     */
33 3
    protected function ensureCacheDirectoryExists($path): void
34
    {
35 3
        if (!$this->exists(dirname($path))) {
36 3
            $this->makeDirectory(dirname($path), 0777, true, true);
37
        }
38 3
    }
39
40
    /**
41
     * Get the MD5 hash of the file at the given path.
42
     *
43
     * @param string $path
44
     * @return string
45
     */
46 3
    public function hash($path): string
47
    {
48 3
        return md5_file($path);
49
    }
50
51
    /**
52
     * Prepend to a file.
53
     *
54
     * @param string $path
55
     * @param string $data
56
     * @return int
57
     */
58 3
    public function prepend($path, $data): int
59
    {
60 3
        if ($this->exists($path)) {
61 3
            return $this->put($path, $data . $this->get($path));
62
        }
63
64 3
        return $this->put($path, $data);
65
    }
66
67
    /**
68
     * Determine if a file or directory exists.
69
     *
70
     * @param string $path
71
     * @return bool
72
     */
73 9
    public function exists($path): bool
74
    {
75 9
        return file_exists($path);
76
    }
77
78
    /**
79
     * Get the contents of a file.
80
     *
81
     * @param string $path
82
     * @param bool   $lock
83
     * @return string
84
     */
85 6
    public function get($path, $lock = false): string
86
    {
87 6
        if ($this->isFile($path)) {
88 3
            return $lock ? $this->sharedGet($path) : file_get_contents($path);
89
        }
90
91 3
        throw new IOException("File does not exist at path {$path}");
92
    }
93
94
    /**
95
     * Determine if the given path is a file.
96
     *
97
     * @param string $file
98
     * @return bool
99
     */
100 6
    public function isFile($file): bool
101
    {
102 6
        return is_file($file);
103
    }
104
105
    /**
106
     * Get contents of a file with shared access.
107
     *
108
     * @param string $path
109
     * @return string
110
     */
111 3
    public function sharedGet($path): string
112
    {
113 3
        $contents = '';
114
115 3
        $handle = fopen($path, 'rb');
116
117 3
        if ($handle !== false) {
118
            try {
119 3
                if (flock($handle, LOCK_SH)) {
120 3
                    clearstatcache(true, $path);
121
122 3
                    $contents = fread($handle, $this->size($path) ?: 1);
123
124 3
                    flock($handle, LOCK_UN);
125
                }
126 3
            } finally {
127 3
                fclose($handle);
128
            }
129
        }
130
131 3
        return $contents;
132
    }
133
134
    /**
135
     * Get the file size of a given file.
136
     *
137
     * @param string $path
138
     * @return int
139
     */
140 3
    public function size($path): int
141
    {
142 3
        return filesize($path);
143
    }
144
145
    /**
146
     * Append to a file.
147
     *
148
     * @param string $path
149
     * @param string $data
150
     * @return int
151
     */
152 3
    public function append($path, $data): int
153
    {
154 3
        return file_put_contents($path, $data, FILE_APPEND);
155
    }
156
157
    /**
158
     * Get or set UNIX mode of a file or directory.
159
     *
160
     * @param string $path
161
     * @param int    $mode
162
     * @return mixed
163
     */
164 9
    public function chmodFile($path, $mode = null)
165
    {
166 9
        if ($mode !== null) {
167 9
            return chmod($path, $mode);
168
        }
169
170 3
        return substr(sprintf('%o', fileperms($path)), -4);
171
    }
172
173
    /**
174
     * Move a file to a new location.
175
     *
176
     * @param string $path
177
     * @param string $target
178
     * @return bool
179
     */
180 3
    public function move($path, $target): bool
181
    {
182 3
        return rename($path, $target);
183
    }
184
185
    /**
186
     * Extract the file name from a file path.
187
     *
188
     * @param string $path
189
     * @return string
190
     */
191 3
    public function name($path): string
192
    {
193 3
        return pathinfo($path, PATHINFO_FILENAME);
194
    }
195
196
    /**
197
     * Extract the trailing name component from a file path.
198
     *
199
     * @param string $path
200
     * @return string
201
     */
202 3
    public function basename($path): string
203
    {
204 3
        return pathinfo($path, PATHINFO_BASENAME);
205
    }
206
207
    /**
208
     * Extract the parent directory from a file path.
209
     *
210
     * @param string $path
211
     * @return string
212
     */
213 3
    public function dirname($path): string
214
    {
215 3
        return pathinfo($path, PATHINFO_DIRNAME);
216
    }
217
218
    /**
219
     * Extract the file extension from a file path.
220
     *
221
     * @param string $path
222
     * @return string
223
     */
224 3
    public function extension($path): string
225
    {
226 3
        return pathinfo($path, PATHINFO_EXTENSION);
227
    }
228
229
    /**
230
     * Get the file type of a given file.
231
     *
232
     * @param string $path
233
     * @return string
234
     */
235 3
    public function type($path): string
236
    {
237 3
        return filetype($path);
238
    }
239
240
    /**
241
     * Get the mime-type of a given file.
242
     *
243
     * @param string $path
244
     * @return string|false
245
     */
246 3
    public function mimeType($path)
247
    {
248 3
        return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
249
    }
250
251
    /**
252
     * Get the file's last modification time.
253
     *
254
     * @param string $path
255
     * @return int
256
     */
257 3
    public function lastModified($path): int
258
    {
259 3
        return filemtime($path);
260
    }
261
262
    /**
263
     * Determine if the given path is readable.
264
     *
265
     * @param string $path
266
     * @return bool
267
     */
268 9
    public function isReadable($path): bool
269
    {
270 9
        return is_readable($path);
271
    }
272
273
    /**
274
     * Determine if the given path is writable.
275
     *
276
     * @param string $path
277
     * @return bool
278
     */
279 9
    public function isWritable($path): bool
280
    {
281 9
        return is_writable($path);
282
    }
283
284
    /**
285
     * Move a directory.
286
     *
287
     * @param string $from
288
     * @param string $to
289
     * @param bool   $overwrite
290
     * @return bool
291
     */
292 6
    public function moveDirectory($from, $to, $overwrite = false): bool
293
    {
294 6
        if ($overwrite && $this->isDirectory($to) && !$this->deleteDirectory($to)) {
295
            return false;
296
        }
297
298 6
        return @rename($from, $to) === true;
299
    }
300
301
    /**
302
     * Determine if the given path is a directory.
303
     *
304
     * @param string $directory
305
     * @return bool
306
     */
307 9
    public function isDirectory($directory): bool
308
    {
309 9
        return is_dir($directory);
310
    }
311
312
    /**
313
     * Recursively delete a directory.
314
     *
315
     * The directory itself may be optionally preserved.
316
     *
317
     * @param string $directory
318
     * @param bool   $preserve
319
     * @return bool
320
     */
321 9
    public function deleteDirectory($directory, $preserve = false): bool
322
    {
323 9
        if (!$this->isDirectory($directory)) {
324 3
            return false;
325
        }
326
327 9
        $items = new FilesystemIterator($directory);
328
329 9
        foreach ($items as $item) {
330 3
            if ($item->isDir() && !$item->isLink()) {
331 3
                $this->deleteDirectory($item->getPathname());
332
            } else {
333 1
                $this->delete($item->getPathname());
334
            }
335
        }
336
337 9
        if (!$preserve) {
338
            /** @scrutinizer ignore-unhandled */
339 9
            @rmdir($directory);
340
        }
341
342 9
        return true;
343
    }
344
345
    /**
346
     * Delete the file at a given path.
347
     *
348
     * @param string|array $paths
349
     * @return bool
350
     */
351 3
    public function delete($paths): bool
352
    {
353 3
        $paths = is_array($paths) ? $paths : func_get_args();
354
355 3
        $success = true;
356
357 3
        foreach ($paths as $path) {
358
            try {
359 3
                if (!@unlink($path)) {
360 3
                    $success = false;
361
                }
362
            } catch (Exception $e) {
363 1
                $success = false;
364
            }
365
        }
366
367 3
        return $success;
368
    }
369
370
    /**
371
     * Copy a directory from one location to another.
372
     *
373
     * @param string $directory
374
     * @param string $destination
375
     * @param int    $options
376
     * @return bool
377
     */
378 6
    public function copyDirectory($directory, $destination, $options = null): bool
379
    {
380 6
        if (!$this->isDirectory($directory)) {
381
            return false;
382
        }
383
384 6
        $options = $options ?: FilesystemIterator::SKIP_DOTS;
385
386 6
        if (!$this->isDirectory($destination)) {
387 6
            $this->makeDirectory($destination, 0777, true);
388
        }
389
390 6
        $items = new FilesystemIterator($directory, $options);
391
392 6
        foreach ($items as $item) {
393 3
            $target = $destination . '/' . $item->getBasename();
394
395 3
            if (!$item->isDir()) {
396
                if (!$this->copyFile($item->getPathname(), $target)) {
397
                    return false;
398
                }
399
            } else {
400 3
                $path = $item->getPathname();
401
402 3
                if (!$this->copyDirectory($path, $target, $options)) {
403 1
                    return false;
404
                }
405
            }
406
        }
407
408 6
        return true;
409
    }
410
411
    /**
412
     * Create a directory.
413
     *
414
     * @param string $path
415
     * @param int    $mode
416
     * @param bool   $recursive
417
     * @param bool   $force
418
     * @return bool
419
     */
420 9
    public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false): bool
421
    {
422 9
        if ($force) {
423 6
            return @mkdir($path, $mode, $recursive);
424
        }
425
426 6
        return mkdir($path, $mode, $recursive);
427
    }
428
429
    /**
430
     * Copy a file to a new location.
431
     *
432
     * @param string $path
433
     * @param string $target
434
     * @return bool
435
     */
436 3
    public function copyFile($path, $target): bool
437
    {
438 3
        return copy($path, $target);
439
    }
440
441
    /**
442
     * Empty the specified directory of all files and folders.
443
     *
444
     * @param string $directory
445
     * @return bool
446
     */
447 3
    public function cleanDirectory($directory): bool
448
    {
449 3
        return $this->deleteDirectory($directory, true);
450
    }
451
452
    /**
453
     * Determine whether the current environment is Windows based.
454
     *
455
     * @return bool
456
     */
457 3
    public function windowsOs(): bool
458
    {
459 3
        return stripos(PHP_OS, 'win') === 0;
460
    }
461
}
462