Shell::cp()   D
last analyzed

Complexity

Conditions 23
Paths 8

Size

Total Lines 88
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 23.0061

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 23
eloc 47
c 1
b 0
f 0
nc 8
nop 3
dl 0
loc 88
ccs 43
cts 44
cp 0.9773
crap 23.0061
rs 4.1666

How to fix   Long Method    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 1
    public function getHome()
44
    {
45 1
        return $this->home;
46
    }
47
48
    /**
49
     * Returns the buffer attribute
50
     *
51
     * @return mixed
52
     */
53 5
    public function getBuffer()
54
    {
55 5
        return $this->buffer;
56
    }
57
58
    /**
59
     * Constructor
60
     *
61
     * @param string $home
62
     */
63 15
    public function __construct($home = null)
64
    {
65 15
        $this->home = (is_null($home) || empty($home))
66 2
            ? ($this->pwd() !== false)
67 2
                ? $this->pwd()
68 2
                : $home
69 13
            : $home;
70
71 15
        $this->cd($this->home);
72 15
    }
73
74
    /**
75
     * Iterative function for directories and files
76
     *
77
     * @param string   $directory
78
     * @param callable $fileCallback
79
     * @param callable $dirCallback
80
     * @param callable $callback
81
     *
82
     * @return array
83
     */
84 6
    public function getContents($directory, $fileCallback = null, $dirCallback = null, $callback = null)
85
    {
86 6
        $contents = $allContents = [];
87
88 6
        if (is_dir($directory)) {
89 6
            foreach ($this->ls($directory) as $item) {
90 6
                if ($item != '.' && $item != '..') {
91 6
                    $contents[] = $item;
92
                }
93
            }
94
95 6
            if (count($contents) > 0) {
96 6
                foreach ($contents as $i) {
97 6
                    if (is_file($directory.'/'.$i)) {
98 6
                        $allContents[] = $i;
99
100 6
                        $this->buffer = $directory.'/'.$i;
101 6
                        call_user_func($fileCallback, $this);
102 4
                    } elseif (is_dir($directory.'/'.$i)) {
103 4
                        $directory_name = basename($directory).'/'.$i;
104
105 4
                        if (strpos($directory_name, './') === 0) {
106 1
                            $from = './';
107 1
                            $from = '/'.preg_quote($from, '/').'/';
108 1
                            $directory_name = preg_replace($from, "", $directory_name, 1);
109
                        }
110
111 4
                        $allContents[$directory_name] =
112 4
                            $this->getContents($directory.'/'.$i, $fileCallback, $dirCallback);
113
114 4
                        $this->buffer = $directory.'/'.$i;
115 6
                        call_user_func($dirCallback, $this);
116
                    }
117
                }
118
            }
119
        } elseif (is_file($directory)) {
120
            throw new \InvalidArgumentException("'$directory' is actually a file");
121
        } else {
122
            throw new \InvalidArgumentException("The directory '$directory' does not exists");
123
        }
124
125 6
        if (!is_null($callback)) {
126 5
            call_user_func($callback, $this);
127
        }
128
129 6
        return $allContents;
130
    }
131
132
    /**
133
     * Returns the curent directory
134
     *
135
     * @return string|boolean
136
     */
137 4
    public function pwd()
138
    {
139 4
        if (getcwd()) {
140 4
            $this->buffer = getcwd();
141
        } else {
142
            return false;
143
        }
144
145 4
        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 7
    public function ls($path = null, $recursive = false)
157
    {
158 7
        $filesToReturn = [];
159
160 7
        $path = (is_null($path) || empty($path)) ? '.' : $path;
161
162 7
        if (is_file($path)) {
163
            $filesToReturn = [$path];
164 7
        } elseif (is_dir($path)) {
165 7
            $pathIns = dir($path);
166
167 7
            if ($recursive) {
168 1
                $filesToReturn = $this->getContents($path);
169
            } else {
170 7
                while (($item = $pathIns->read()) !== false) {
171 7
                    if ($item != '.' && $item != '..') {
172 7
                        $filesToReturn[] = $item;
173
                    }
174
                }
175
176 7
                $pathIns->close();
177
            }
178
        } else {
179
            $contents = $this->ls();
180
181
            foreach ($contents as $item) {
182
                if (!empty($path)) {
183
                    if (!strlen(stristr($item, $path)) > 0) {
184
                        continue;
185
                    }
186
                }
187
                if (strstr($item, '~') === false && $item != '.' && $item != '..') {
188
                    $filesToReturn[] = $item;
189
                }
190
            }
191
        }
192
193 7
        return $filesToReturn;
194
    }
195
196
    /**
197
     * Changes the current directory
198
     *
199
     * @param string|null $path
200
     *
201
     * @return boolean
202
     */
203 15
    public function cd($path = null)
204
    {
205 15
        $path = (is_null($path) || empty($path)) ? $this->home : $path;
206
207 15
        if (is_dir($path)) {
208 15
            if (chdir($path)) {
209 15
                return true;
210
            }
211
        }
212
213
        return false;
214
    }
215
216
    /**
217
     * Changes the file's date
218
     *
219
     * @param string
220
     * @param mixed $file
221
     *
222
     * @return boolean
223
     */
224 2
    public function touch($file)
225
    {
226 2
        $contents = file_exists($file) ? file_get_contents($file) : "";
227
228 2
        $hd = @fopen($file, "w+");
229
230 2
        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...
231
            $this->error(Errno::FILE_PERMISSION_DENIED, $file);
0 ignored issues
show
Bug introduced by
The method error() does not exist on Drone\FileSystem\Shell. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

231
            $this->/** @scrutinizer ignore-call */ 
232
                   error(Errno::FILE_PERMISSION_DENIED, $file);
Loading history...
232
233
            return false;
234
        }
235
236 2
        @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

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

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