Passed
Push — master ( b176c5...1503d9 )
by Darío
01:55
created

Shell::getContents()   C

Complexity

Conditions 13
Paths 14

Size

Total Lines 45
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 23
nc 14
nop 5
dl 0
loc 45
rs 6.6166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * DronePHP (http://www.dronephp.com)
4
 *
5
 * @link      http://github.com/Pleets/DronePHP
6
 * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org)
7
 * @license   http://www.dronephp.com/license
8
 * @author    Darío Rivera <[email protected]>
9
 */
10
11
namespace Drone\FileSystem;
12
13
use Drone\Error\Errno;
14
15
/**
16
 * Shell class
17
 *
18
 * This class represents a system terminal
19
 */
20
class Shell implements ShellInterface
21
{
22
    use \Drone\Error\ErrorTrait;
23
24
    /**
25
     * Home directory (~)
26
     *
27
     * @var string
28
     */
29
    private $home;
30
31
    /**
32
     * Result of last command (optional)
33
     *
34
     * @var string
35
     */
36
    private $buffer = null;
37
38
    /**
39
     * Returns the home attribute
40
     *
41
     * @return string
42
     */
43
    public function getHome()
44
    {
45
        return $this->home;
46
    }
47
48
    /**
49
     * Returns the buffer attribute
50
     *
51
     * @return mixed
52
     */
53
    public function getBuffer()
54
    {
55
        return $this->buffer;
56
    }
57
58
    /**
59
     * Constructor
60
     *
61
     * @param string $home
62
     */
63
    public function __construct($home = null)
64
    {
65
        $this->home = (is_null($home) || empty($home)) ? $this->pwd() : $home;
0 ignored issues
show
Documentation Bug introduced by
It seems like is_null($home) || empty(... ? $this->pwd() : $home can also be of type false. However, the property $home is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
66
        $this->cd($this->home);
0 ignored issues
show
Bug introduced by
It seems like $this->home can also be of type false; however, parameter $path of Drone\FileSystem\Shell::cd() does only seem to accept null|string, 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

66
        $this->cd(/** @scrutinizer ignore-type */ $this->home);
Loading history...
67
    }
68
69
    /**
70
     * Iterative function for directories and files
71
     *
72
     * @param string   $directory
73
     * @param callable $fileCallback
74
     * @param callable $dirCallback
75
     * @param callable $callback
76
     * @param boolean  $showParentPath
77
     *
78
     * @return array
79
     */
80
    public function getContents($directory, $fileCallback, $dirCallback, $callback = null, $showParentPath = false)
81
    {
82
        $contents = [];
83
84
        if (is_dir($directory))
85
        {
86
            foreach ($this->ls($directory) as $item)
87
            {
88
                if ($item != '.' && $item != '..')
89
                    $contents[] = $item;
90
            }
91
92
            //$allContents = $contents;
93
94
            if (count($contents) > 0)
95
            {
96
                foreach ($contents as $i)
97
                {
98
                    if (is_file($directory.'/'.$i))
99
                    {
100
                        $allContents[] = ($showParentPath) ? $directory.'/'.$i : $i;
101
102
                        $this->buffer = $directory.'/'.$i;
103
                        call_user_func($fileCallback, $this);
104
                    }
105
                    else if (is_dir($directory.'/'.$i))
106
                    {
107
                        $allContents[] = ($showParentPath) ? $directory.'/'.$i : $i;
108
                        $allContents[] = $this->getContents($directory.'/'.$i, $fileCallback, $dirCallback, null, false);
109
110
                        $this->buffer = $directory.'/'.$i;
111
                        call_user_func($dirCallback, $this);
112
                    }
113
                }
114
            }
115
        }
116
        else if (is_file($directory))
117
            throw new \InvalidArgumentException("'$directory' is actually a file");
118
        else
119
            throw new \InvalidArgumentException("The directory '$directory' does not exists");
120
121
        if (!is_null($callback))
122
            call_user_func($callback, $this);
123
124
        return $allContents;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $allContents does not seem to be defined for all execution paths leading up to this point.
Loading history...
125
    }
126
127
    /**
128
     * Returns the curent directory
129
     *
130
     * @return string|boolean
131
     */
132
    public function pwd()
133
    {
134
        if (getcwd())
135
            $this->buffer = getcwd();
136
        else
137
            return false;
138
139
        return $this->buffer;
140
    }
141
142
    /**
143
     * Returns a list with directory contents
144
     *
145
     * @param string|null $path
146
     * @param boolean     $recursive
147
     *
148
     * @return array
149
     */
150
    public function ls($path = null, $recursive = false)
151
    {
152
        $filesToReturn = [];
153
154
        $path = (is_null($path) || empty($path)) ? '.' : $path;
155
156
        if (is_file($path))
157
            $filesToReturn = array($path);
158
        else if (is_dir($path))
159
        {
160
            $pathIns = dir($path);
161
162
            if ($recursive)
163
            {
164
                $dirs = $files = [];
165
166
                $filesToReturn = $this->getContents($path,
167
                    # file's callback
168
                    function($event) use (&$files)
169
                    {
170
                        $files[] = $event->getBuffer();
171
                    },
172
                    # folder's callback
173
                    function($event) use (&$dirs)
174
                    {
175
                        $dirs[] = $event->getBuffer();
176
                    }
177
                );
178
179
                /*foreach ($dirs as $item)
180
                    $filesToReturn[] = $item;
181
182
                foreach ($files as $item)
183
                    $filesToReturn[] = $item;*/
184
            }
185
            else
186
            {
187
                while (($item = $pathIns->read()) !== false)
188
                {
189
                    if ($item != '.' && $item != '..')
190
                        $filesToReturn[] = $item;
191
                }
192
193
                $pathIns->close();
194
            }
195
        }
196
        else {
197
198
            $contents = $this->ls();
199
200
            foreach ($contents as $item)
201
            {
202
                if (!empty($path))
203
                    if (!strlen(stristr($item, $path)) > 0)
204
                        continue;
205
                if (strstr($item,'~') === false && $item != '.' && $item != '..')
206
                    $filesToReturn[] = $item;
207
            }
208
        }
209
210
        return $filesToReturn;
211
    }
212
213
    /**
214
     * Changes the current directory
215
     *
216
     * @param string|null $path
217
     *
218
     * @return boolean
219
     */
220
    public function cd($path = null)
221
    {
222
        $path = (is_null($path) || empty($path)) ? $this->home : $path;
223
224
        if (is_dir($path))
225
        {
226
            if (chdir($path))
227
                return true;
228
        }
229
230
        return false;
231
    }
232
233
    /**
234
     * Changes the file's date
235
     *
236
     * @param string
237
     *
238
     * @return boolean
239
     */
240
    public function touch($file)
241
    {
242
        $contents = file_exists($file) ? file_get_contents($file) : "";
243
244
        $hd = @fopen($file, "w+");
245
246
        if (!$hd || @fwrite($hd, $contents) === false)
0 ignored issues
show
introduced by
$hd is of type false|resource, thus it always evaluated to false.
Loading history...
247
        {
248
            $this->error(Errno::FILE_PERMISSION_DENIED, $file);
249
            return false;
250
        }
251
252
        @fclose($hd);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). 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

252
        /** @scrutinizer ignore-unhandled */ @fclose($hd);

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...
253
254
        return true;
255
    }
256
257
    /**
258
     * Deletes one or more files
259
     *
260
     * @param string       $file
261
     * @param boolean|null $recursive
262
     *
263
     * @return boolean
264
     */
265
    public function rm($file, $recursive = null)
266
    {
267
        $recursive = is_null($recursive) ? false : $recursive;
268
269
        if (is_null($file))
0 ignored issues
show
introduced by
The condition is_null($file) is always false.
Loading history...
270
            throw new \InvalidArgumentException("Missing first parameter");
271
272
        if (file_exists($file) && !$recursive)
273
            unlink($file);
274
        elseif (is_dir($file) && $recursive)
275
        {
276
            $that = $this;
277
278
            $this->getContents($file, function() use ($that) {
279
                unlink($that->getBuffer());
280
            }, function() use ($that) {
281
                rmdir($that->getBuffer());
282
            }, function() use ($file) {
283
                @rmdir($file);
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

283
                /** @scrutinizer ignore-unhandled */ @rmdir($file);

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...
284
            });
285
        }
286
287
        return true;
288
    }
289
290
    /**
291
     * Copies one or more files or directories
292
     *
293
     * @param string       $file
294
     * @param string       $dest
295
     * @param boolean|null $recursive
296
     *
297
     * @return boolean
298
     */
299
    public function cp($file, $dest, $recursive = null)
300
    {
301
        $recursive = (is_null($recursive)) ? false : $recursive;
302
303
        if (empty($file) || empty($dest))
304
            throw new \InvalidArgumentException("Missing parameters");
305
306
        if (is_dir($file) && !$recursive)
307
            throw new \RuntimeException("Ommiting directory <<$foo>>");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $foo seems to be never defined.
Loading history...
308
309
        if (is_dir($file) && (is_dir($dest) || !file_exists($dest)))
310
        {
311
            $files = [
312
                "files"   => [],
313
                "folders" => []
314
            ];
315
316
            if (is_dir($dest))
317
                $files["folders"][] = basename($file);
318
319
            if (!file_exists($dest))
320
                mkdir($dest);
321
322
            $that = $this;
323
324
            $this->getContents($file,
325
                # file's callback
326
                function() use($that, &$files)
327
                {
328
                    $files["files"][] = $that->getBuffer();
329
                },
330
                # folder's callback
331
                function() use($that, &$files)
332
                {
333
                    $files["folders"][] = $that->getBuffer();
334
                },
335
                # final callback
336
                function() use (&$files, $dest)
337
                {
338
                    if (count($files["folders"]))
339
                    {
340
                        foreach ($files["folders"] as $folder)
341
                        {
342
                            if (!file_exists($dest.'/'.$folder))
343
                                mkdir("$dest/$folder", 0777, true);
344
                        }
345
                    }
346
347
                    if (count($files["files"]))
348
                    {
349
                        foreach ($files["files"] as $item)
350
                        {
351
                            if (!file_exists("$dest/$files"))
352
                                copy($item, $dest.'/'.$item);
353
                        }
354
                    }
355
                }
356
            );
357
        }
358
359
        if (is_dir($dest))
360
        {
361
            if (!$recursive)
362
                copy($file, $dest.'/'.$file);
363
            else {
364
365
                $files = array();
366
                $files[0] = array();
367
                $files[1] = array();
368
369
                $_SESSION["BUFFER"]["EXO"]["cp"][2] = $dest;
370
371
                $that = $this;
372
373
                $this->getContents($file, function() use($that, &$files) {
374
                    $files[0][] = $that->getBuffer();
375
                }, function() use($that, &$files) {
376
                    $files[1][] = $that->getBuffer();
377
                }, function() use ($files, $dest) {
378
379
                    foreach ($files[1] as $item)
380
                    {
381
                        if (!file_exists($dest.'/'.$item))
382
                            mkdir("$dest/$item", 0777, true);
383
                    }
384
385
                    foreach ($files[0] as $item)
386
                    {
387
                        if (!file_exists("$dest/$files"))
388
                            copy($item, $dest.'/'.$item);
389
                    }
390
                });
391
            }
392
        }
393
        else
394
            copy($file, $dest);
395
396
        return true;
397
    }
398
399
    /**
400
     * Moves or renames files
401
     *
402
     * @param string $oldfile
403
     * @param string $newfile
404
     *
405
     * @return boolean
406
     */
407
    public function mv($oldfile, $newfile)
408
    {
409
        if (empty($oldfile))
410
            throw new \InvalidArgumentException("Missing first parameter");
411
412
        if (is_dir($newfile))
413
                $newfile .= '/'.basename($oldfile);
414
415
        if ($oldfile == $newfile)
416
            throw new \Exception("'$oldfile' and '$newfile' are the same file");
417
418
        if(!rename($oldfile, $newfile))
419
            return false;
420
421
        return true;
422
    }
423
424
    /**
425
     * Creates a directory
426
     *
427
     * @param string       $dir
428
     * @param string|null  $dest
429
     * @param boolean|null $recursive
430
     *
431
     * @return boolean
432
     */
433
    public function mkdir($dir, $dest = null, $recursive = null)
434
    {
435
        if (empty($dir))
436
            throw new \InvalidArgumentException("Missing first parameter");
437
438
        if (empty($dest))
439
            $dest = '.';
440
441
        $recursive = (is_null($recursive)) ? false : $recursive;
442
443
        if ($recursive)
444
            mkdir("$dest/$dir", 0777, true);
445
        else {
446
            if (!is_dir($dir))
447
            {
448
                if(!mkdir("$dir", 0777))
449
                    return false;
450
            }
451
        }
452
        return true;
453
    }
454
455
    /**
456
     * Deletes a directory
457
     *
458
     * @param string $dir
459
     *
460
     * @return boolean
461
     */
462
    public function rmdir($dir)
463
    {
464
        if (is_null($dir) || empty($dir))
465
            throw new \RuntimeException("Missing first parameter");
466
467
        if (rmdir($dir))
468
            return true;
469
        else
470
            return false;
471
    }
472
}