Passed
Push — master ( 864cd3...c7da61 )
by Darío
02:21
created

Shell::mv()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 7
nop 2
dl 0
loc 15
rs 9.6111
c 0
b 0
f 0
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 string; however, parameter $path of Drone\FileSystem\Shell::cd() does only seem to accept boolean|null, 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
     *
77
     * @return array
78
     */
79
    public function getContents($directory, $fileCallback, $dirCallback, $callback = null)
80
    {
81
        $contents = [];
82
83
        if (is_dir($directory))
84
        {
85
            foreach ($this->ls($directory) as $item)
86
            {
87
                if ($item != '.' && $item != '..')
88
                    $contents[] = $item;
89
            }
90
91
            $allContents = $contents;
92
93
            if (count($contents) > 0)
94
            {
95
                foreach ($contents as $i)
96
                {
97
                    if (is_file($directory.'/'.$i))
98
                    {
99
                        $allContents[] = $directory.'/'.$i;
100
101
                        $this->buffer = $directory.'/'.$i;
102
                        call_user_func($fileCallback, $this);
103
                    }
104
                    elseif (is_dir($directory.'/'.$i))
105
                    {
106
                        $allContents[] = $directory.'/'.$i;
107
108
                        $this->getContents($directory.'/'.$i, $fileCallback, $dirCallback);
109
110
                        $this->buffer = $directory.'/'.$i;
111
                        call_user_func($dirCallback, $this);
112
113
                        /*$directory = scandir($directory);
114
115
                        if (!count($directory) < 3)
116
                            $this->buffer = $directory.'/'.$i;*/
117
                    }
118
                }
119
            }
120
        }
121
        else if (is_file($directory))
122
            throw new \InvalidArgumentException("'$directory' is actually a file");
123
        else
124
            throw new \InvalidArgumentException("The directory '$directory' does not exists");
125
126
        if (!is_null($callback))
127
            call_user_func($callback, $this);
128
129
        return $allContents;
130
    }
131
132
    /**
133
     * Returns the curent directory
134
     *
135
     * @return string|boolean
136
     */
137
    public function pwd()
138
    {
139
        if (getcwd())
140
            $this->buffer = getcwd();
141
        else
142
            return false;
143
144
        return $this->buffer;
145
    }
146
147
    /**
148
     * Returns a list with directory contents
149
     *
150
     * @param string|null $path
151
     * @param boolean     $recursive
152
     *
153
     * @return array
154
     */
155
    public function ls($path = null, $recursive = false)
156
    {
157
        $filesToReturn = [];
158
159
        $path = (is_null($path) || empty($path)) ? '.' : $path;
160
161
        if (is_file($path))
162
            $filesToReturn = array($path);
163
        else if (is_dir($path))
164
        {
165
            $pathIns = dir($path);
166
167
            if ($recursive)
168
            {
169
                $dirs = $files = [];
170
171
                $this->getContents($path,
172
                    # file's callback
173
                    function($event) use (&$files)
174
                    {
175
                        $files[] = $event->getBuffer();
176
                    },
177
                    # folder's callback
178
                    function($event) use (&$dirs)
179
                    {
180
                        $dirs[] = $event->getBuffer();
181
                    }
182
                );
183
184
                foreach ($dirs as $item)
185
                    $filesToReturn[] = $item;
186
187
                foreach ($files as $item)
188
                    $filesToReturn[] = $item;
189
            }
190
            else
191
            {
192
                while (($item = $pathIns->read()) !== false)
193
                {
194
                    if ($item != '.' && $item != '..')
195
                        $filesToReturn[] = $item;
196
                }
197
198
                $pathIns->close();
199
            }
200
        }
201
        else {
202
203
            $contents = $this->ls();
204
205
            foreach ($contents as $item)
206
            {
207
                if (!empty($path))
208
                    if (!strlen(stristr($item, $path)) > 0)
209
                        continue;
210
                if (strstr($item,'~') === false && $item != '.' && $item != '..')
211
                    $filesToReturn[] = $item;
212
            }
213
        }
214
215
        return $filesToReturn;
216
    }
217
218
    /**
219
     * Changes the current directory
220
     *
221
     * @param boolean|null $path
222
     *
223
     * @return boolean
224
     */
225
    public function cd($path = null)
226
    {
227
        $path = (is_null($path) || empty($path)) ? $this->home : $path;
228
229
        if (is_dir($path))
230
        {
231
            if (chdir($path))
232
                return true;
233
        }
234
235
        return false;
236
    }
237
238
    /**
239
     * Changes the file's date
240
     *
241
     * @param string
242
     *
243
     * @return boolean
244
     */
245
    public function touch($file)
246
    {
247
        $contents = file_exists($file) ? file_get_contents($file) : "";
248
249
        $hd = @fopen($file, "w+");
250
251
        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...
252
        {
253
            $this->error(Errno::FILE_PERMISSION_DENIED, $file);
254
            return false;
255
        }
256
257
        @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

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

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