CommandExecuter::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This class help for executing external programs
5
 * This is necessary as PHP Threads are not very popular
6
 * It also requires an extra dependency
7
 * Relying on system execution
8
 */
9
10
use SA\CpeSdk;
11
12
class CommandExecuter
13
{
14
    private $cpeLogger;
15
    private $logKey;
16
17
    const EXEC_FAILED = "EXEC_FAILED";
18
19
    public function __construct($cpeLogger, $logKey = null)
20
    {
21
        $this->cpeLogger = $cpeLogger;
22
        $this->logKey    = $logKey;
23
    }
24
25
    public function execute(
26
        $cmd,
27
        $sleep = 1,
28
        $descriptors = array(
29
            1 => array("pipe", "w"),
30
            2 => array("pipe", "w")
31
        ),
32
        $progressCallback = null,
33
        $progressCallbackParams = null,
34
        $showProgress = false,
35
        $callbackTurns = 0,
36
        $logKey = null)
37
    {
38
        if ($logKey)
39
            $this->logKey = $logKey;
40
        
41
        $this->cpeLogger->logOut("INFO", basename(__FILE__), "Executing: $cmd", $this->logKey);
42
43
        // Start execution of $cmd
44
        if (!($process = proc_open($cmd, $descriptors, $pipes)) ||
45
            !is_resource($process)) {
46
            $this->cpeLogger->logOut("ERROR",
47
                                     basename(__FILE__), "Unable to execute command:\n$cmd",
48
                                     $this->logKey);
49
            throw new CpeSdk\CpeException("Unable to execute command:\n$cmd\n",
50
                                          self::EXEC_FAILED);
51
        }
52
53
        // Set the pipes as non-blocking
54 View Code Duplication
        if (isset($descriptors[1]) &&
55
            $descriptors[1]) {
56
            stream_set_blocking($pipes[1], FALSE);
57
        }
58 View Code Duplication
        if (isset($descriptors[2]) &&
59
            $descriptors[2]) {
60
            stream_set_blocking($pipes[2], FALSE);
61
        }
62
63
        $i = 0;
64
65
        // Used to store all output
66
        $allOut = "";
67
        $allOutErr = "";
68
69
        // Check process status at every turn
70
        do {
71
            sleep($sleep);
72
73
            // If callback only after N turns
74
            if ( !$callbackTurns || in_array($i, array(0, $callbackTurns)) )
75
            {
76
                if ($showProgress) {
77
                    echo ".\n";
78
                }
79
80
                // Call user provided callback.
81
                // Callback should be an array as per doc here:
82
                // http://www.php.net/manual/en/language.types.callable.php
83
                // Type 3: Object method call
84
                if (isset($progressCallback) && $progressCallback) {
85
                    call_user_func($progressCallback, $progressCallbackParams,
86
                                   $allOut, $allOutErr);
87
                }
88
89
                $i = 0;
90
            }
91
92
            // Get latest status
93
            $procStatus = proc_get_status($process);
94
            if ($showProgress) {
95
                echo ".";
96
                flush();
97
            }
98
            
99
            // Read prog output
100 View Code Duplication
            if (isset($pipes[1]) && $pipes[1]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
101
                $out = stream_get_contents($pipes[1], -1);
102
                $allOut .= $out;
103
            }
104
105
            // Read prog errors
106 View Code Duplication
            if (isset($pipes[2]) && $pipes[2]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
                $outErr = stream_get_contents($pipes[2], -1);
108
                $allOutErr .= $outErr;
109
            }
110
111
            $i++;
112
        } while ($procStatus['running']);
113
114
        if (isset($pipes[1]))
115
            fclose($pipes[1]);
116
        if (isset($pipes[2]))
117
            fclose($pipes[2]);
118
119
        if ($procStatus['exitcode'] > 0)
120
        {
121
            $this->cpeLogger->logOut("ERROR",
122
                                     basename(__FILE__),
123
                                     "Can't execute: $cmd. Exit Code: ".$procStatus['exitcode'],
124
                                     $this->logKey);
125
            if ($allOut)
126
                $this->cpeLogger->logOut("ERROR",
127
                                         basename(__FILE__), "COMMAND STDOUT: ".$allOut,
128
                                         $this->logKey);
129
            if ($allOutErr)
130
                $this->cpeLogger->logOut("ERROR",
131
                                         basename(__FILE__), "COMMAND STDERR: ".$allOutErr,
132
                                         $this->logKey);
133
        }
134
135
        if ($showProgress) {
136
            echo "\n";
137
        }
138
139
        // Process is over
140
        proc_close($process);
141
142
        return array('out' => $allOut, 'outErr' => $allOutErr);
143
    }
144
}
145