1 | <?php |
||
12 | class Exec |
||
13 | { |
||
14 | /** |
||
15 | * @var string |
||
16 | */ |
||
17 | const REDIRECT_STDERR_TO_STDOUT = ' 2>&1'; |
||
18 | |||
19 | /** |
||
20 | * @var int (0-255) |
||
21 | */ |
||
22 | const CODE_CLEAN_EXIT = 0; |
||
23 | |||
24 | /** |
||
25 | * Every error in a pipe will be exited with an error code |
||
26 | */ |
||
27 | const SET_O_PIPEFAIL = 'set -o pipefail;'; |
||
28 | |||
29 | /** |
||
30 | * @param string $command |
||
31 | * @param string|null $output |
||
32 | * @param int $returnCode |
||
33 | */ |
||
34 | public static function run($command, &$output = null, &$returnCode = null) |
||
35 | { |
||
36 | if (!self::allowed()) { |
||
37 | $message = sprintf("No PHP exec(), can not execute command '%s'.", $command); |
||
38 | throw new RuntimeException($message); |
||
39 | } |
||
40 | |||
41 | if (OperatingSystem::isBashCompatibleShell() && self::isPipefailOptionAvailable()) { |
||
42 | $command = self::SET_O_PIPEFAIL . $command; |
||
43 | } |
||
44 | |||
45 | $command .= self::REDIRECT_STDERR_TO_STDOUT; |
||
46 | |||
47 | exec($command, $outputArray, $returnCode); |
||
48 | $output = self::parseCommandOutput((array) $outputArray); |
||
49 | |||
50 | if ($returnCode !== self::CODE_CLEAN_EXIT) { |
||
51 | throw new RuntimeException( |
||
52 | sprintf("Exit status %d for command %s. Output was: %s", $returnCode, $command, $output) |
||
53 | ); |
||
54 | } |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Exec class is allowed to run |
||
59 | * |
||
60 | * @return bool |
||
61 | */ |
||
62 | public static function allowed() |
||
66 | |||
67 | /** |
||
68 | * string from array of strings representing one line per entry |
||
69 | * |
||
70 | * @param array $commandOutput |
||
71 | * @return string |
||
72 | */ |
||
73 | private static function parseCommandOutput(array $commandOutput) |
||
77 | |||
78 | /** |
||
79 | * @return bool |
||
80 | */ |
||
81 | private static function isPipefailOptionAvailable() |
||
87 | } |
||
88 |