Filesystem   F
last analyzed

Complexity

Total Complexity 86

Size/Duplication

Total Lines 634
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 140
dl 0
loc 634
rs 2
c 0
b 0
f 0
wmc 86

40 Methods

Rating   Name   Duplication   Size   Complexity  
B copyDirectory() 0 34 8
A isWritable() 0 3 1
A moveDirectory() 0 6 4
A size() 0 3 1
A jsonHandler() 0 4 1
A mimeType() 0 3 1
A delete() 0 14 5
A directories() 0 7 2
A dirname() 0 3 1
A hash() 0 3 1
A change() 0 16 2
A prepend() 0 6 2
A basename() 0 3 1
A extension() 0 3 1
A type() 0 3 1
A makeDirectory() 0 6 2
A cleanDirectory() 0 3 1
A allFiles() 0 5 1
A replace() 0 10 2
A link() 0 7 3
A get() 0 7 3
A isDirectory() 0 3 1
A glob() 0 3 1
A move() 0 3 1
B getAllFilesInDirectory() 0 27 11
A getRequire() 0 7 2
A name() 0 3 1
A exists() 0 3 1
A deleteDirectories() 0 10 3
A append() 0 3 1
A isReadable() 0 3 1
A chmod() 0 6 2
A lastModified() 0 3 1
A copy() 0 3 1
A put() 0 3 2
A requireOnce() 0 3 1
A deleteDirectory() 0 24 6
A sharedGet() 0 16 4
A files() 0 5 1
A isFile() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Filesystem often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Filesystem, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Resta\Support;
4
5
use ErrorException;
6
use FilesystemIterator;
7
use Symfony\Component\Finder\Finder;
8
use Resta\Exception\FileNotFoundException;
9
10
class Filesystem
11
{
12
    /**
13
     * Determine if a file or directory exists.
14
     *
15
     * @param  string  $path
16
     * @return bool
17
     */
18
    public function exists($path)
19
    {
20
        return file_exists($path);
21
    }
22
23
    /**
24
     * Get the contents of a file.
25
     *
26
     * @param string $path
27
     * @param bool $lock
28
     * @return string
29
     *
30
     * @throws FileNotFoundException
31
     *
32
     */
33
    public function get($path, $lock = false)
34
    {
35
        if ($this->isFile($path)) {
36
            return $lock ? $this->sharedGet($path) : file_get_contents($path);
37
        }
38
39
        exception()->fileNotFoundException("File does not exist at path {$path}");
40
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
        $handle = fopen($path, 'rb');
53
        if ($handle) {
0 ignored issues
show
introduced by
$handle is of type resource, thus it always evaluated to false.
Loading history...
54
            try {
55
                if (flock($handle, LOCK_SH)) {
56
                    clearstatcache(true, $path);
57
                    $contents = fread($handle, $this->size($path) ?: 1);
58
                    flock($handle, LOCK_UN);
59
                }
60
            } finally {
61
                fclose($handle);
62
            }
63
        }
64
        return $contents;
65
    }
66
67
    /**
68
     * Get the returned value of a file.
69
     *
70
     * @param  string  $path
71
     * @return mixed
72
     *
73
     * @throws FileNotFoundException
74
     */
75
    public function getRequire($path)
76
    {
77
        if ($this->isFile($path)) {
78
            return require $path;
79
        }
80
81
        exception()->fileNotFoundException("File does not exist at path {$path}");
82
    }
83
84
    /**
85
     * Require the given file once.
86
     *
87
     * @param  string  $file
88
     * @return mixed
89
     */
90
    public function requireOnce($file)
91
    {
92
        require_once $file;
93
    }
94
95
    /**
96
     * Get the MD5 hash of the file at the given path.
97
     *
98
     * @param  string  $path
99
     * @return string
100
     */
101
    public function hash($path)
102
    {
103
        return md5_file($path);
104
    }
105
106
    /**
107
     * Write the contents of a file.
108
     *
109
     * @param  string  $path
110
     * @param  string  $contents
111
     * @param  bool  $lock
112
     * @return int|bool
113
     */
114
    public function put($path, $contents, $lock = false)
115
    {
116
        return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
117
    }
118
119
    /**
120
     * Write the contents of a file, replacing it atomically if it already exists.
121
     *
122
     * @param  string  $path
123
     * @param  string  $content
124
     * @return void
125
     */
126
    public function replace($path, $content)
127
    {
128
        // If the path already exists and is a symlink, get the real path...
129
        clearstatcache(true, $path);
130
        $path = realpath($path) ?: $path;
131
        $tempPath = tempnam(dirname($path), basename($path));
132
        // Fix permissions of tempPath because `tempnam()` creates it with permissions set to 0600...
133
        chmod($tempPath, 0777 - umask());
134
        file_put_contents($tempPath, $content);
135
        rename($tempPath, $path);
136
    }
137
138
    /**
139
     * Prepend to a file.
140
     *
141
     * @param  string  $path
142
     * @param  string  $data
143
     * @return int
144
     */
145
    public function prepend($path, $data)
146
    {
147
        if ($this->exists($path)) {
148
            return $this->put($path, $data.$this->get($path));
149
        }
150
        return $this->put($path, $data);
151
    }
152
153
    /**
154
     * Append to a file.
155
     *
156
     * @param  string  $path
157
     * @param  string  $data
158
     * @return int
159
     */
160
    public function append($path, $data)
161
    {
162
        return file_put_contents($path, $data, FILE_APPEND);
163
    }
164
165
    /**
166
     * Get or set UNIX mode of a file or directory.
167
     *
168
     * @param  string  $path
169
     * @param  int|null  $mode
170
     * @return mixed
171
     */
172
    public function chmod($path, $mode = null)
173
    {
174
        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...
175
            return chmod($path, $mode);
176
        }
177
        return substr(sprintf('%o', fileperms($path)), -4);
178
    }
179
180
    /**
181
     * Delete the file at a given path.
182
     *
183
     * @param  string|array  $paths
184
     * @return bool
185
     */
186
    public function delete($paths)
187
    {
188
        $paths = is_array($paths) ? $paths : func_get_args();
189
        $success = true;
190
        foreach ($paths as $path) {
191
            try {
192
                if (! @unlink($path)) {
193
                    $success = false;
194
                }
195
            } catch (ErrorException $e) {
196
                $success = false;
197
            }
198
        }
199
        return $success;
200
    }
201
202
    /**
203
     * Move a file to a new location.
204
     *
205
     * @param  string  $path
206
     * @param  string  $target
207
     * @return bool
208
     */
209
    public function move($path, $target)
210
    {
211
        return rename($path, $target);
212
    }
213
214
    /**
215
     * Copy a file to a new location.
216
     *
217
     * @param  string  $path
218
     * @param  string  $target
219
     * @return bool
220
     */
221
    public function copy($path, $target)
222
    {
223
        return copy($path, $target);
224
    }
225
226
    /**
227
     * Create a hard link to the target file or directory.
228
     *
229
     * @param  string  $target
230
     * @param  string  $link
231
     * @return void
232
     */
233
    public function link($target, $link)
234
    {
235
        if (! windows_os()) {
236
            return symlink($target, $link);
0 ignored issues
show
Bug Best Practice introduced by
The expression return symlink($target, $link) returns the type boolean which is incompatible with the documented return type void.
Loading history...
237
        }
238
        $mode = $this->isDirectory($target) ? 'J' : 'H';
239
        exec("mklink /{$mode} ".escapeshellarg($link).' '.escapeshellarg($target));
240
    }
241
242
    /**
243
     * Extract the file name from a file path.
244
     *
245
     * @param  string  $path
246
     * @return string
247
     */
248
    public function name($path)
249
    {
250
        return pathinfo($path, PATHINFO_FILENAME);
0 ignored issues
show
Bug Best Practice introduced by
The expression return pathinfo($path, R...port\PATHINFO_FILENAME) also could return the type array which is incompatible with the documented return type string.
Loading history...
251
    }
252
253
    /**
254
     * Extract the trailing name component from a file path.
255
     *
256
     * @param  string  $path
257
     * @return string
258
     */
259
    public function basename($path)
260
    {
261
        return pathinfo($path, PATHINFO_BASENAME);
0 ignored issues
show
Bug Best Practice introduced by
The expression return pathinfo($path, R...port\PATHINFO_BASENAME) also could return the type array which is incompatible with the documented return type string.
Loading history...
262
    }
263
264
    /**
265
     * Extract the parent directory from a file path.
266
     *
267
     * @param  string  $path
268
     * @return string
269
     */
270
    public function dirname($path)
271
    {
272
        return pathinfo($path, PATHINFO_DIRNAME);
0 ignored issues
show
Bug Best Practice introduced by
The expression return pathinfo($path, R...pport\PATHINFO_DIRNAME) also could return the type array which is incompatible with the documented return type string.
Loading history...
273
    }
274
275
    /**
276
     * Extract the file extension from a file path.
277
     *
278
     * @param  string  $path
279
     * @return string
280
     */
281
    public function extension($path)
282
    {
283
        return pathinfo($path, PATHINFO_EXTENSION);
0 ignored issues
show
Bug Best Practice introduced by
The expression return pathinfo($path, R...ort\PATHINFO_EXTENSION) also could return the type array which is incompatible with the documented return type string.
Loading history...
284
    }
285
286
    /**
287
     * Get the file type of a given file.
288
     *
289
     * @param  string  $path
290
     * @return string
291
     */
292
    public function type($path)
293
    {
294
        return filetype($path);
295
    }
296
297
    /**
298
     * Get the mime-type of a given file.
299
     *
300
     * @param  string  $path
301
     * @return string|false
302
     */
303
    public function mimeType($path)
304
    {
305
        return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
306
    }
307
308
    /**
309
     * Get the file size of a given file.
310
     *
311
     * @param  string  $path
312
     * @return int
313
     */
314
    public function size($path)
315
    {
316
        return filesize($path);
317
    }
318
319
    /**
320
     * Get the file's last modification time.
321
     *
322
     * @param  string  $path
323
     * @return int
324
     */
325
    public function lastModified($path)
326
    {
327
        return filemtime($path);
328
    }
329
330
    /**
331
     * Determine if the given path is a directory.
332
     *
333
     * @param  string  $directory
334
     * @return bool
335
     */
336
    public function isDirectory($directory)
337
    {
338
        return is_dir($directory);
339
    }
340
341
    /**
342
     * Determine if the given path is readable.
343
     *
344
     * @param  string  $path
345
     * @return bool
346
     */
347
    public function isReadable($path)
348
    {
349
        return is_readable($path);
350
    }
351
352
    /**
353
     * Determine if the given path is writable.
354
     *
355
     * @param  string  $path
356
     * @return bool
357
     */
358
    public function isWritable($path)
359
    {
360
        return is_writable($path);
361
    }
362
363
    /**
364
     * Determine if the given path is a file.
365
     *
366
     * @param  string  $file
367
     * @return bool
368
     */
369
    public function isFile($file)
370
    {
371
        return is_file($file);
372
    }
373
374
    /**
375
     * Find path names matching a given pattern.
376
     *
377
     * @param  string  $pattern
378
     * @param  int     $flags
379
     * @return array
380
     */
381
    public function glob($pattern, $flags = 0)
382
    {
383
        return glob($pattern, $flags);
384
    }
385
386
    /**
387
     * Get an array of all files in a directory.
388
     *
389
     * @param  string  $directory
390
     * @param  bool  $hidden
391
     * @return \Symfony\Component\Finder\SplFileInfo[]
392
     */
393
    public function files($directory, $hidden = false)
394
    {
395
        return iterator_to_array(
396
            Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->depth(0)->sortByName(),
397
            false
398
        );
399
    }
400
401
    /**
402
     * Get all of the files from the given directory (recursive).
403
     *
404
     * @param  string  $directory
405
     * @param  bool  $hidden
406
     * @return \Symfony\Component\Finder\SplFileInfo[]
407
     */
408
    public function allFiles($directory, $hidden = false)
409
    {
410
        return iterator_to_array(
411
            Finder::create()->files()->ignoreDotFiles(! $hidden)->in($directory)->sortByName(),
412
            false
413
        );
414
    }
415
416
    /**
417
     * Get all of the directories within a given directory.
418
     *
419
     * @param  string  $directory
420
     * @return array
421
     */
422
    public function directories($directory)
423
    {
424
        $directories = [];
425
        foreach (Finder::create()->in($directory)->directories()->depth(0)->sortByName() as $dir) {
426
            $directories[] = $dir->getPathname();
427
        }
428
        return $directories;
429
    }
430
431
    /**
432
     * Create a directory.
433
     *
434
     * @param  string  $path
435
     * @param  int     $mode
436
     * @param  bool    $recursive
437
     * @param  bool    $force
438
     * @return bool
439
     */
440
    public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false)
441
    {
442
        if ($force) {
443
            return @mkdir($path, $mode, $recursive);
444
        }
445
        return mkdir($path, $mode, $recursive);
446
    }
447
448
    /**
449
     * Move a directory.
450
     *
451
     * @param  string  $from
452
     * @param  string  $to
453
     * @param  bool  $overwrite
454
     * @return bool
455
     */
456
    public function moveDirectory($from, $to, $overwrite = false)
457
    {
458
        if ($overwrite && $this->isDirectory($to) && ! $this->deleteDirectory($to)) {
459
            return false;
460
        }
461
        return @rename($from, $to) === true;
462
    }
463
464
    /**
465
     * Copy a directory from one location to another.
466
     *
467
     * @param  string  $directory
468
     * @param  string  $destination
469
     * @param  int|null  $options
470
     * @return bool
471
     */
472
    public function copyDirectory($directory, $destination, $options = null)
473
    {
474
        if (! $this->isDirectory($directory)) {
475
            return false;
476
        }
477
        $options = $options ?: FilesystemIterator::SKIP_DOTS;
478
        // If the destination directory does not actually exist, we will go ahead and
479
        // create it recursively, which just gets the destination prepared to copy
480
        // the files over. Once we make the directory we'll proceed the copying.
481
        if (! $this->isDirectory($destination)) {
482
            $this->makeDirectory($destination, 0777, true);
483
        }
484
        $items = new FilesystemIterator($directory, $options);
485
        foreach ($items as $item) {
486
            // As we spin through items, we will check to see if the current file is actually
487
            // a directory or a file. When it is actually a directory we will need to call
488
            // back into this function recursively to keep copying these nested folders.
489
            $target = $destination.'/'.$item->getBasename();
490
            if ($item->isDir()) {
491
                $path = $item->getPathname();
492
                if (! $this->copyDirectory($path, $target, $options)) {
493
                    return false;
494
                }
495
            }
496
            // If the current items is just a regular file, we will just copy this to the new
497
            // location and keep looping. If for some reason the copy fails we'll bail out
498
            // and return false, so the developer is aware that the copy process failed.
499
            else {
500
                if (! $this->copy($item->getPathname(), $target)) {
501
                    return false;
502
                }
503
            }
504
        }
505
        return true;
506
    }
507
508
    /**
509
     * Recursively delete a directory.
510
     *
511
     * The directory itself may be optionally preserved.
512
     *
513
     * @param  string  $directory
514
     * @param  bool    $preserve
515
     * @return bool
516
     */
517
    public function deleteDirectory($directory, $preserve = false)
518
    {
519
        if (! $this->isDirectory($directory)) {
520
            return false;
521
        }
522
        $items = new FilesystemIterator($directory);
523
        foreach ($items as $item) {
524
            // If the item is a directory, we can just recurse into the function and
525
            // delete that sub-directory otherwise we'll just delete the file and
526
            // keep iterating through each file until the directory is cleaned.
527
            if ($item->isDir() && ! $item->isLink()) {
528
                $this->deleteDirectory($item->getPathname());
529
            }
530
            // If the item is just a file, we can go ahead and delete it since we're
531
            // just looping through and waxing all of the files in this directory
532
            // and calling directories recursively, so we delete the real path.
533
            else {
534
                $this->delete($item->getPathname());
535
            }
536
        }
537
        if (! $preserve) {
538
            @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

538
            /** @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...
539
        }
540
        return true;
541
    }
542
543
    /**
544
     * Remove all of the directories within a given directory.
545
     *
546
     * @param  string  $directory
547
     * @return bool
548
     */
549
    public function deleteDirectories($directory)
550
    {
551
        $allDirectories = $this->directories($directory);
552
        if (! empty($allDirectories)) {
553
            foreach ($allDirectories as $directoryName) {
554
                $this->deleteDirectory($directoryName);
555
            }
556
            return true;
557
        }
558
        return false;
559
    }
560
561
    /**
562
     * Empty the specified directory of all files and folders.
563
     *
564
     * @param  string  $directory
565
     * @return bool
566
     */
567
    public function cleanDirectory($directory)
568
    {
569
        return $this->deleteDirectory($directory, true);
570
    }
571
572
    /**
573
     * get all files in directory
574
     *
575
     * @param $dir
576
     * @param bool $recursive
577
     * @param string $basedir
578
     * @param bool $include_dirs
579
     * @return array
580
     */
581
    public function getAllFilesInDirectory($dir, $recursive = true, $basedir = '', $include_dirs = false)
582
    {
583
        if ($dir == '') {return array();} else {$results = array(); $subresults = array();}
584
        if (!is_dir($dir)) {$dir = dirname($dir);} // so a files path can be sent
585
        if ($basedir == '') {$basedir = realpath($dir).DIRECTORY_SEPARATOR;}
586
587
        $files = scandir($dir);
588
        foreach ($files as $key => $value){
589
            if ( ($value != '.') && ($value != '..') ) {
590
                $path = realpath($dir.DIRECTORY_SEPARATOR.$value);
591
                if (is_dir($path)) {
592
                    // optionally include directories in file list
593
                    if ($include_dirs) {$subresults[] = str_replace($basedir, '', $path);}
594
                    // optionally get file list for all subdirectories
595
                    if ($recursive) {
596
                        $subdirresults = $this->getAllFilesInDirectory($path, $recursive, $basedir, $include_dirs);
597
                        $results = array_merge($results, $subdirresults);
598
                    }
599
                } else {
600
                    // strip basedir and add to subarray to separate file list
601
                    $subresults[] = str_replace($basedir, '', $path);
602
                }
603
            }
604
        }
605
        // merge the subarray to give the list of files then subdirectory files
606
        if (count($subresults) > 0) {$results = array_merge($subresults, $results);}
607
        return $results;
608
    }
609
610
    /**
611
     * it writes data as json the specified file
612
     * 
613
     * @param $path
614
     * @param array $data
615
     * @return JsonHandler
616
     */
617
    public function jsonHandler($path)
618
    {
619
        JsonHandler::$file = $path;
620
        return JsonHandler::class;
0 ignored issues
show
Bug Best Practice introduced by
The expression return Resta\Support\JsonHandler::class returns the type string which is incompatible with the documented return type Resta\Support\JsonHandler.
Loading history...
621
    }
622
623
    /**
624
     * @param $executionPath
625
     * @param $param
626
     * @return bool
627
     */
628
    public function change($executionPath,$param)
629
    {
630
        $dt = fopen($executionPath, "r");
631
        $content = fread($dt, filesize($executionPath));
632
        fclose($dt);
633
634
        foreach ($param as $key=>$value){
635
636
            $content=str_replace("".$key."",$value,$content);
637
        }
638
639
        $dt = fopen($executionPath, "w");
640
        fwrite($dt, $content);
641
        fclose($dt);
642
643
        return true;
644
    }
645
}