Passed
Push — master ( 90d55d...0e16d5 )
by Carlos C
03:42 queued 10s
created

ShellExec::getEnvironment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
namespace CfdiUtils\Utils\Internal;
3
4
use Symfony\Component\Process\Process;
5
6
/**
7
 * Execute a command and retrieve results
8
 *
9
 * NOTE: Changes on this file will not be considering a BC since this utility class is for internal usage only
10
 *
11
 * @internal
12
 */
13
class ShellExec
14
{
15
    /** @var array */
16
    private $command;
17
18
    /** @var array */
19
    private $environment;
20
21 34
    public function __construct(array $command, array $environment = [])
22
    {
23
        // command validation
24 34
        if ([] === $command) {
25 1
            throw new \InvalidArgumentException('Command definition is empty');
26
        }
27 33
        $command = array_values($command);
28 33
        $this->checkArrayStrings($command, true, 'Command definition has elements that are invalid');
29
        // executable must not be empty
30 30
        if ('' === reset($command)) {
31 1
            throw new \InvalidArgumentException('Command executable is empty');
32
        }
33
        // environment keys validation
34 29
        $this->checkArrayStrings(array_keys($environment), false, 'Environment has keys that are invalid');
35
        // environment values validation
36 26
        $this->checkArrayStrings($environment, true, 'Environment has values that are invalid');
37
38
        // command allocation
39 23
        $this->command = $command;
40 23
        $this->environment = $environment;
41 23
    }
42
43 33
    private function checkArrayStrings(array $input, bool $allowEmpty, string $exceptionMessage)
44
    {
45
        try {
46 33
            foreach ($input as $index => $value) {
47 33
                $this->checkString($value, $allowEmpty, "Element $index");
48
            }
49 9
        } catch (\Throwable $exception) {
50 9
            throw new \InvalidArgumentException($exceptionMessage, 0, $exception);
51
        }
52 30
    }
53
54 33
    private function checkString($value, bool $allowEmpty, string $exceptionMessagePrefix)
55
    {
56 33
        if (! is_string($value)) {
57 3
            throw new \InvalidArgumentException($exceptionMessagePrefix . ' is not a string');
58
        }
59 33
        if (! $allowEmpty && '' === $value) {
60 1
            throw new \InvalidArgumentException($exceptionMessagePrefix . ' is empty');
61
        }
62 33
        if (boolval(preg_match('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/u', $value))) {
63 5
            throw new \InvalidArgumentException($exceptionMessagePrefix . ' contains control characters');
64
        }
65 33
    }
66
67 21
    public function getCommand(): array
68
    {
69 21
        return $this->command;
70
    }
71
72 21
    public function getEnvironment(): array
73
    {
74 21
        return $this->environment;
75
    }
76
77 20
    public function run(): ShellExecResult
78
    {
79 20
        $process = new Process($this->getCommand());
80 20
        $process->setEnv($this->getEnvironment());
81 20
        $process->run();
82 20
        return new ShellExecResult(
83 20
            $process->getCommandLine(),
84 20
            $process->getExitCode() ?? -1,
85 20
            $process->getOutput(),
86 20
            $process->getErrorOutput()
87
        );
88
    }
89
}
90