Passed
Push — master ( c34495...8adf73 )
by Darío
03:13
created

Shell::mkdir()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 7.7656

Importance

Changes 0
Metric Value
cc 7
eloc 12
nc 17
nop 3
dl 0
loc 22
ccs 9
cts 12
cp 0.75
crap 7.7656
rs 8.8333
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 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 = array($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
     *
221
     * @return boolean
222
     */
223 2
    public function touch($file)
224
    {
225 2
        $contents = file_exists($file) ? file_get_contents($file) : "";
226
227 2
        $hd = @fopen($file, "w+");
228
229 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...
230
            $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

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

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

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