Completed
Push β€” master ( 442bf2...547913 )
by duan
08:47 queued 07:38
created

Filesystem::windowsOs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: yiranzai
5
 * Date: 19-3-6
6
 * Time: δΈ‹εˆ6:32
7
 */
8
9
namespace Yiranzai\Dht;
10
11
use FilesystemIterator;
12
13
class Filesystem
14
{
15
16
    /**
17
     * Determine if a file or directory exists.
18
     *
19
     * @param  string $path
20
     * @return bool
21
     */
22 9
    public function exists($path)
23
    {
24 9
        return file_exists($path);
25
    }
26
27
    /**
28
     * Get the contents of a file.
29
     *
30
     * @param  string $path
31
     * @param  bool   $lock
32
     * @return string
33
     */
34 3
    public function get($path, $lock = false)
35
    {
36 3
        if ($this->isFile($path)) {
37 3
            return $lock ? $this->sharedGet($path) : file_get_contents($path);
38
        }
39
40
        throw new \RuntimeException("File does not exist at path {$path}");
41
    }
42
43
    /**
44
     * Get contents of a file with shared access.
45
     *
46
     * @param  string $path
47
     * @return string
48
     */
49
    public function sharedGet($path)
50
    {
51
        $contents = '';
52
53
        $handle = fopen($path, 'rb');
54
55
        if ($handle) {
0 ignored issues
show
introduced by
$handle is of type false|resource, thus it always evaluated to false.
Loading history...
56
            try {
57
                if (flock($handle, LOCK_SH)) {
58
                    clearstatcache(true, $path);
59
60
                    $contents = fread($handle, $this->size($path) ?: 1);
61
62
                    flock($handle, LOCK_UN);
63
                }
64
            } finally {
65
                fclose($handle);
66
            }
67
        }
68
69
        return $contents;
70
    }
71
72
    /**
73
     * Get the returned value of a file.
74
     *
75
     * @param  string $path
76
     * @return mixed
77
     *
78
     */
79
    public function getRequire($path)
80
    {
81
        if ($this->isFile($path)) {
82
            return require $path;
83
        }
84
85
        throw new \RuntimeException("File does not exist at path {$path}");
86
    }
87
88
    /**
89
     * Require the given file once.
90
     *
91
     * @param  string $file
92
     * @return mixed
93
     */
94
    public function requireOnce($file)
95
    {
96
        require_once $file;
97
    }
98
99
    /**
100
     * Get the MD5 hash of the file at the given path.
101
     *
102
     * @param  string $path
103
     * @return string
104
     */
105
    public function hash($path)
106
    {
107
        return md5_file($path);
108
    }
109
110
    /**
111
     * Write the contents of a file.
112
     *
113
     * @param  string $path
114
     * @param  string $contents
115
     * @param  bool   $lock
116
     * @return int
117
     */
118 3
    public function put($path, $contents, $lock = false)
119
    {
120 3
        return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
121
    }
122
123
    /**
124
     * Prepend to a file.
125
     *
126
     * @param  string $path
127
     * @param  string $data
128
     * @return int
129
     */
130
    public function prepend($path, $data)
131
    {
132
        if ($this->exists($path)) {
133
            return $this->put($path, $data . $this->get($path));
134
        }
135
136
        return $this->put($path, $data);
137
    }
138
139
    /**
140
     * Append to a file.
141
     *
142
     * @param  string $path
143
     * @param  string $data
144
     * @return int
145
     */
146
    public function append($path, $data)
147
    {
148
        return file_put_contents($path, $data, FILE_APPEND);
149
    }
150
151
    /**
152
     * Get or set UNIX mode of a file or directory.
153
     *
154
     * @param  string $path
155
     * @param  int    $mode
156
     * @return mixed
157
     */
158
    public function chmod($path, $mode = null)
159
    {
160
        if ($mode) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mode of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
161
            return chmod($path, $mode);
162
        }
163
164
        return substr(sprintf('%o', fileperms($path)), -4);
165
    }
166
167
    /**
168
     * Delete the file at a given path.
169
     *
170
     * @param  string|array $paths
171
     * @return bool
172
     */
173
    public function delete($paths)
174
    {
175
        $paths = is_array($paths) ? $paths : func_get_args();
176
177
        $success = true;
178
179
        foreach ($paths as $path) {
180
            try {
181
                if (!@unlink($path)) {
182
                    $success = false;
183
                }
184
            } catch (\Exception $e) {
185
                $success = false;
186
            }
187
        }
188
189
        return $success;
190
    }
191
192
    /**
193
     * Move a file to a new location.
194
     *
195
     * @param  string $path
196
     * @param  string $target
197
     * @return bool
198
     */
199
    public function move($path, $target)
200
    {
201
        return rename($path, $target);
202
    }
203
204
    /**
205
     * Copy a file to a new location.
206
     *
207
     * @param  string $path
208
     * @param  string $target
209
     * @return bool
210
     */
211
    public function copy($path, $target)
212
    {
213
        return copy($path, $target);
214
    }
215
216
    /**
217
     * Create a hard link to the target file or directory.
218
     *
219
     * @param  string $target
220
     * @param  string $link
221
     * @return void
222
     */
223
    public function link($target, $link)
224
    {
225
        if (!$this->windowsOs()) {
226
            return symlink($target, $link);
227
        }
228
229
        $mode = $this->isDirectory($target) ? 'J' : 'H';
230
231
        exec("mklink /{$mode} \"{$link}\" \"{$target}\"");
232
    }
233
234
    /**
235
     * Extract the file name from a file path.
236
     *
237
     * @param  string $path
238
     * @return string
239
     */
240
    public function name($path)
241
    {
242
        return pathinfo($path, PATHINFO_FILENAME);
243
    }
244
245
    /**
246
     * Extract the trailing name component from a file path.
247
     *
248
     * @param  string $path
249
     * @return string
250
     */
251
    public function basename($path)
252
    {
253
        return pathinfo($path, PATHINFO_BASENAME);
254
    }
255
256
    /**
257
     * Extract the parent directory from a file path.
258
     *
259
     * @param  string $path
260
     * @return string
261
     */
262
    public function dirname($path)
263
    {
264
        return pathinfo($path, PATHINFO_DIRNAME);
265
    }
266
267
    /**
268
     * Extract the file extension from a file path.
269
     *
270
     * @param  string $path
271
     * @return string
272
     */
273
    public function extension($path)
274
    {
275
        return pathinfo($path, PATHINFO_EXTENSION);
276
    }
277
278
    /**
279
     * Get the file type of a given file.
280
     *
281
     * @param  string $path
282
     * @return string
283
     */
284
    public function type($path)
285
    {
286
        return filetype($path);
287
    }
288
289
    /**
290
     * Get the mime-type of a given file.
291
     *
292
     * @param  string $path
293
     * @return string|false
294
     */
295
    public function mimeType($path)
296
    {
297
        return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
298
    }
299
300
    /**
301
     * Get the file size of a given file.
302
     *
303
     * @param  string $path
304
     * @return int
305
     */
306
    public function size($path)
307
    {
308
        return filesize($path);
309
    }
310
311
    /**
312
     * Get the file's last modification time.
313
     *
314
     * @param  string $path
315
     * @return int
316
     */
317
    public function lastModified($path)
318
    {
319
        return filemtime($path);
320
    }
321
322
    /**
323
     * Determine if the given path is a directory.
324
     *
325
     * @param  string $directory
326
     * @return bool
327
     */
328
    public function isDirectory($directory)
329
    {
330
        return is_dir($directory);
331
    }
332
333
    /**
334
     * Determine if the given path is readable.
335
     *
336
     * @param  string $path
337
     * @return bool
338
     */
339
    public function isReadable($path)
340
    {
341
        return is_readable($path);
342
    }
343
344
    /**
345
     * Determine if the given path is writable.
346
     *
347
     * @param  string $path
348
     * @return bool
349
     */
350
    public function isWritable($path)
351
    {
352
        return is_writable($path);
353
    }
354
355
    /**
356
     * Determine if the given path is a file.
357
     *
358
     * @param  string $file
359
     * @return bool
360
     */
361 3
    public function isFile($file)
362
    {
363 3
        return is_file($file);
364
    }
365
366
    /**
367
     * Find path names matching a given pattern.
368
     *
369
     * @param  string $pattern
370
     * @param  int    $flags
371
     * @return array
372
     */
373
    public function glob($pattern, $flags = 0)
374
    {
375
        return glob($pattern, $flags);
376
    }
377
378
    /**
379
     * Create a directory.
380
     *
381
     * @param  string $path
382
     * @param  int    $mode
383
     * @param  bool   $recursive
384
     * @param  bool   $force
385
     * @return bool
386
     */
387 3
    public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false)
388
    {
389 3
        if ($force) {
390
            return @mkdir($path, $mode, $recursive);
391
        }
392
393 3
        return mkdir($path, $mode, $recursive);
394
    }
395
396
    /**
397
     * Move a directory.
398
     *
399
     * @param  string $from
400
     * @param  string $to
401
     * @param  bool   $overwrite
402
     * @return bool
403
     */
404
    public function moveDirectory($from, $to, $overwrite = false)
405
    {
406
        if ($overwrite && $this->isDirectory($to)) {
407
            if (!$this->deleteDirectory($to)) {
408
                return false;
409
            }
410
        }
411
412
        return @rename($from, $to) === true;
413
    }
414
415
    /**
416
     * Copy a directory from one location to another.
417
     *
418
     * @param  string $directory
419
     * @param  string $destination
420
     * @param  int    $options
421
     * @return bool
422
     */
423
    public function copyDirectory($directory, $destination, $options = null)
424
    {
425
        if (!$this->isDirectory($directory)) {
426
            return false;
427
        }
428
429
        $options = $options ?: FilesystemIterator::SKIP_DOTS;
430
431
        // If the destination directory does not actually exist, we will go ahead and
432
        // create it recursively, which just gets the destination prepared to copy
433
        // the files over. Once we make the directory we'll proceed the copying.
434
        if (!$this->isDirectory($destination)) {
435
            $this->makeDirectory($destination, 0777, true);
436
        }
437
438
        $items = new FilesystemIterator($directory, $options);
439
440
        foreach ($items as $item) {
441
            // As we spin through items, we will check to see if the current file is actually
442
            // a directory or a file. When it is actually a directory we will need to call
443
            // back into this function recursively to keep copying these nested folders.
444
            $target = $destination . '/' . $item->getBasename();
445
446
            if (!$item->isDir()) {
447
                if (!$this->copy($item->getPathname(), $target)) {
448
                    return false;
449
                }
450
            } else {
451
                $path = $item->getPathname();
452
453
                if (!$this->copyDirectory($path, $target, $options)) {
454
                    return false;
455
                }
456
            }
457
        }
458
459
        return true;
460
    }
461
462
    /**
463
     * Recursively delete a directory.
464
     *
465
     * The directory itself may be optionally preserved.
466
     *
467
     * @param  string $directory
468
     * @param  bool   $preserve
469
     * @return bool
470
     */
471
    public function deleteDirectory($directory, $preserve = false)
472
    {
473
        if (!$this->isDirectory($directory)) {
474
            return false;
475
        }
476
477
        $items = new FilesystemIterator($directory);
478
479
        foreach ($items as $item) {
480
            // If the item is a directory, we can just recurse into the function and
481
            // delete that sub-directory otherwise we'll just delete the file and
482
            // keep iterating through each file until the directory is cleaned.
483
            if ($item->isDir() && !$item->isLink()) {
484
                $this->deleteDirectory($item->getPathname());
485
            } else {
486
                $this->delete($item->getPathname());
487
            }
488
        }
489
490
        if (!$preserve) {
491
            @rmdir($directory);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rmdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

491
            /** @scrutinizer ignore-unhandled */ @rmdir($directory);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
492
        }
493
494
        return true;
495
    }
496
497
    /**
498
     * Empty the specified directory of all files and folders.
499
     *
500
     * @param  string $directory
501
     * @return bool
502
     */
503
    public function cleanDirectory($directory)
504
    {
505
        return $this->deleteDirectory($directory, true);
506
    }
507
508
    /**
509
     * Determine whether the current environment is Windows based.
510
     *
511
     * @return bool
512
     */
513
    public function windowsOs()
514
    {
515
        return stripos(PHP_OS, 'win') === 0;
516
    }
517
}
518