Test Failed
Push — master ( 37e8ab...13f89e )
by Php Easy Api
04:31
created

Filesystem::change()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 2
eloc 9
c 1
b 1
f 0
nc 2
nop 2
dl 0
loc 16
rs 9.9666
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 false|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);
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);
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);
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);
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);
0 ignored issues
show
Bug Best Practice introduced by
The expression return glob($pattern, $flags) could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
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));
0 ignored issues
show
Bug introduced by
It seems like $dt can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

631
        $content = fread(/** @scrutinizer ignore-type */ $dt, filesize($executionPath));
Loading history...
632
        fclose($dt);
0 ignored issues
show
Bug introduced by
It seems like $dt can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

632
        fclose(/** @scrutinizer ignore-type */ $dt);
Loading history...
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);
0 ignored issues
show
Bug introduced by
It seems like $dt can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

640
        fwrite(/** @scrutinizer ignore-type */ $dt, $content);
Loading history...
641
        fclose($dt);
642
643
        return true;
644
    }
645
}