Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
ShellExec
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
9.37
0.00% covered (danger)
0.00%
0 / 1
 exec
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
9.37
1<?php
2
3namespace ExecWithFallback;
4
5/**
6 * Emulate exec() with system()
7 *
8 * @package    ExecWithFallback
9 * @author     Bjørn Rosell <it@rosell.dk>
10 */
11class ShellExec
12{
13
14  /**
15   * Emulate exec() with shell_exec()
16   *
17   * @param string $command  The command to execute
18   * @param string &$output (optional)
19   * @param int &$result_code (optional)
20   *
21   * @return string | false   The last line of output or false in case of failure
22   */
23    public static function exec($command, &$output = null, &$result_code = null)
24    {
25        $resultCodeSupplied = (func_num_args() >= 3);
26        if ($resultCodeSupplied) {
27            throw new \Exception('ShellExec::exec() does not support $result_code argument');
28        }
29
30        $result = shell_exec($command);
31
32        // result:
33        // - A string containing the output from the executed command,
34        // - false if the pipe cannot be established
35        // - or null if an error occurs or the command produces no output.
36        // PHP stan complains on systems which reports that shell_exec returns string|null (not false)
37        // So, we added the ignore line AND we have set "reportUnmatchedIgnoredErrors: false" in phpstan config
38
39        /** @phpstan-ignore-next-line */
40        if ($result === false) {
41            return false;
42        }
43
44        if (is_null($result)) {
45            // hm, "null if an error occurs or the command produces no output."
46            // What were they thinking?
47            // And yes, it does return null, when no output, which is confirmed in the test "echo hi 1>/dev/null"
48            // What should we do? Throw or accept?
49            // Perhaps shell_exec throws in newer versions of PHP instead of returning null.
50            // We are counting on it until proved wrong.
51            return '';
52        }
53
54        $theOutput = preg_split('/\s*\r\n|\s*\n\r|\s*\n|\s*\r/', $result);
55
56        // remove the last element if it is blank
57        if ((count($theOutput) > 0) && ($theOutput[count($theOutput) -1] == '')) {
58            array_pop($theOutput);
59        }
60
61        if (count($theOutput) == 0) {
62            return '';
63        }
64        if (gettype($output) == 'array') {
65            foreach ($theOutput as $line) {
66                $output[] = $line;
67            }
68        } else {
69            $output = $theOutput;
70        }
71        return $theOutput[count($theOutput) -1];
72    }
73}