Passed
Push — master ( 0d49ff...ad352f )
by Darío
01:47
created

Shell::rm()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 4
nop 2
dl 0
loc 31
rs 9.2222
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 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
     *
77
     * @return array
78
     */
79
    public function getContents($directory, $fileCallback = null, $dirCallback = null, $callback = null)
80
    {
81
        $contents = $allContents = [];
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
            if (count($contents) > 0)
92
            {
93
                foreach ($contents as $i)
94
                {
95
                    if (is_file($directory.'/'.$i))
96
                    {
97
                        $allContents[] = $i;
98
99
                        $this->buffer = $directory.'/'.$i;
100
                        call_user_func($fileCallback, $this);
101
                    }
102
                    else if (is_dir($directory.'/'.$i))
103
                    {
104
                        $directory_name = basename($directory).'/'.$i;
105
106
                        if (strpos($directory_name, './') === 0)
107
                        {
108
                            $from = './';
109
                            $from = '/'.preg_quote($from, '/').'/';
110
                            $directory_name = preg_replace($from, "", $directory_name, 1);
111
                        }
112
113
                        $allContents[$directory_name] =
114
                            $this->getContents($directory.'/'.$i, $fileCallback, $dirCallback);
115
116
                        $this->buffer = $directory.'/'.$i;
117
                        call_user_func($dirCallback, $this);
118
                    }
119
                }
120
            }
121
        }
122
        else if (is_file($directory))
123
            throw new \InvalidArgumentException("'$directory' is actually a file");
124
        else
125
            throw new \InvalidArgumentException("The directory '$directory' does not exists");
126
127
        if (!is_null($callback))
128
            call_user_func($callback, $this);
129
130
        return $allContents;
131
    }
132
133
    /**
134
     * Returns the curent directory
135
     *
136
     * @return string|boolean
137
     */
138
    public function pwd()
139
    {
140
        if (getcwd())
141
            $this->buffer = getcwd();
142
        else
143
            return false;
144
145
        return $this->buffer;
146
    }
147
148
    /**
149
     * Returns a list with directory contents
150
     *
151
     * @param string|null $path
152
     * @param boolean     $recursive
153
     *
154
     * @return array
155
     */
156
    public function ls($path = null, $recursive = false)
157
    {
158
        $filesToReturn = [];
159
160
        $path = (is_null($path) || empty($path)) ? '.' : $path;
161
162
        if (is_file($path))
163
            $filesToReturn = array($path);
164
        else if (is_dir($path))
165
        {
166
            $pathIns = dir($path);
167
168
            if ($recursive)
169
                $filesToReturn = $this->getContents($path);
170
            else
171
            {
172
                while (($item = $pathIns->read()) !== false)
173
                {
174
                    if ($item != '.' && $item != '..')
175
                        $filesToReturn[] = $item;
176
                }
177
178
                $pathIns->close();
179
            }
180
        }
181
        else {
182
183
            $contents = $this->ls();
184
185
            foreach ($contents as $item)
186
            {
187
                if (!empty($path))
188
                    if (!strlen(stristr($item, $path)) > 0)
189
                        continue;
190
                if (strstr($item,'~') === false && $item != '.' && $item != '..')
191
                    $filesToReturn[] = $item;
192
            }
193
        }
194
195
        return $filesToReturn;
196
    }
197
198
    /**
199
     * Changes the current directory
200
     *
201
     * @param string|null $path
202
     *
203
     * @return boolean
204
     */
205
    public function cd($path = null)
206
    {
207
        $path = (is_null($path) || empty($path)) ? $this->home : $path;
208
209
        if (is_dir($path))
210
        {
211
            if (chdir($path))
212
                return true;
213
        }
214
215
        return false;
216
    }
217
218
    /**
219
     * Changes the file's date
220
     *
221
     * @param string
222
     *
223
     * @return boolean
224
     */
225
    public function touch($file)
226
    {
227
        $contents = file_exists($file) ? file_get_contents($file) : "";
228
229
        $hd = @fopen($file, "w+");
230
231
        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...
232
        {
233
            $this->error(Errno::FILE_PERMISSION_DENIED, $file);
234
            return false;
235
        }
236
237
        @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

237
        /** @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...
238
239
        return true;
240
    }
241
242
    /**
243
     * Deletes one or more files or directories
244
     *
245
     * @param string  $file
246
     * @param boolean $recursive
247
     *
248
     * @return boolean
249
     */
250
    public function rm($file, $recursive = false)
251
    {
252
        if (is_null($file))
0 ignored issues
show
introduced by
The condition is_null($file) is always false.
Loading history...
253
            throw new \InvalidArgumentException("Missing first parameter");
254
255
        if (file_exists($file) && !$recursive)
256
            unlink($file);
257
        elseif (is_dir($file) && $recursive)
258
        {
259
            $that = $this;
260
261
            $this->getContents($file,
262
                # file's callback
263
                function() use ($that)
264
                {
265
                    unlink($that->getBuffer());
266
                },
267
                # folder's callback
268
                function() use ($that)
269
                {
270
                    rmdir($that->getBuffer());
271
                },
272
                # final callback
273
                function() use ($file)
274
                {
275
                    @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

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