Subprocess::stream_to_stdout()   A
last analyzed

Complexity

Conditions 3
Paths 1

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 1
nop 1
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Filesystem;
3
4
use Symfony\Component\Process\Exception\ProcessFailedException;
5
use Symfony\Component\Process\Process;
6
7
/**
8
 * Subprocess class.
9
 *
10
 * @package Filesystem
11
 */
12
class Subprocess
13
{
14
    /**
15
     * Stream STDOUT and/or STDERR to file.
16
     *
17
     * @var int
18
     */
19
    const STREAM_FILE = 1;
20
21
    /**
22
     * Stream STDOUT and/or STDERR to STDOUT.
23
     *
24
     * @var int
25
     */
26
    const STREAM_STDOUT = 2;
27
28
    /**
29
     * Stream STDOUT and/or STDERR to file and STDOUT.
30
     *
31
     * @var int
32
     */
33
    const STREAM_BOTH = 3;
34
35
    /**
36
     * Stream STDOUT and/or STDERR to STDOUT (wait for process to finish).
37
     *
38
     * @var int
39
     */
40
    const STREAM_STDOUT_WAIT = 4;
41
42
    /**
43
     * Stream STDOUT and/or STDERR to STDOUT (interactive mode).
44
     *
45
     * @var int
46
     */
47
    const STREAM_STDOUT_TTY = 5;
48
49
    /**
50
     * Initiate subprocess.
51
     *
52
     * @param  mixed   $cmd           command(s) being executed
53
     * @param  boolean $stream        whether or not to stream results to console
54
     * @param  boolean $fail_on_error whether or not to fail on error or pass
55
     * @param  mixed   $stdoutfile    STDOUT file for output or NULL
56
     * @param  mixed   $stderrfile    STDERR file for output or NULL
57
     * @return array   STDOUT, STDERR and RETVAL or just RETVAL if streamed
58
     */
59
    final public function run($cmd, $stream = self::STREAM_STDOUT_WAIT, $fail_on_error = false, $stdoutfile = null, $stderrfile = null)
60
    {
61
        $process = new Process($cmd);
62
        $process->setTimeout(10800);
63
        $process->setIdleTimeout(3600);
64
65
        switch ($stream)
66
        {
67
            case '1':
68
                return $this->stream_to_file($process, $stdoutfile, $stderrfile);
69
70
            case '2':
71
                return $this->stream_to_stdout($process);
72
                
73
            case '3':
74
                return $this->stream_to_both($process, $stdoutfile, $stderrfile);
75
                
76
            case '4':
77
                return $this->stream_stdout_wait($process, $fail_on_error);
78
                
79
            case '5':
80
                return $this->stream_stdout_tty($process);
81
        }
82
    }
83
84
    /**
85
     * Stream STDOUT and/or STDERR to console.
86
     *
87
     * @param  object $process    process object
88
     * @param  string $stdoutfile STDOUT file for output
89
     * @param  string $stderrfile STDERR file for output
90
     * @return array
91
     */
92
    final protected function stream_to_file(Process $process, $stdoutfile, $stderrfile)
93
    {
94
        if (!isset($stdoutfile))
95
        {
96
            throw new \RuntimeException("Missing output file for STDOUT stream.");
97
        }
98
99
        $GLOBALS['stdoutfile'] = $stdoutfile;
100
        $GLOBALS['stderrfile'] = $stderrfile;
101
102
        $process->run(function($type, $buffer)
103
        {
104
            if (Process::ERR === $type)
105
            {
106
                if ($GLOBALS['stderrfile'] !== null)
107
                {
108
                    file_put_contents($GLOBALS['stderrfile'], $buffer, FILE_APPEND | LOCK_EX);
109
                } else
110
                {
111
                    file_put_contents($GLOBALS['stdoutfile'], $buffer, FILE_APPEND | LOCK_EX);
112
                }
113
            } else
114
            {
115
                file_put_contents($GLOBALS['stdoutfile'], $buffer, FILE_APPEND | LOCK_EX);
116
            }
117
        });
118
        return $this->get_process_info($process);
119
    }
120
121
    /**
122
     * Stream STDOUT and STDERR to console.
123
     *
124
     * @param  object $process process object
125
     * @return array
126
     */
127
    final protected function stream_to_stdout(Process $process)
128
    {
129
        $process->run(function($type, $buffer)
130
        {
131
            if (Process::ERR === $type)
132
            {
133
                fwrite(STDERR, $buffer);
134
            }
135
136
            if (Process::ERR !== $type)
137
            {
138
                fwrite(STDOUT, $buffer);
139
            }
140
        });
141
        return $this->get_process_info($process);
142
    }
143
144
    /**
145
     * Stream STDOUT and STDERR to console.
146
     *
147
     * @param  object $process    Process object
148
     * @param  string $stdoutfile STDOUT file for output
149
     * @param  string $stderrfile STDERR file for output
150
     * @return array
151
     */
152
    final protected function stream_to_both(Process $process, $stdoutfile, $stderrfile)
153
    {
154
        if (!isset($stdoutfile))
155
        {
156
            throw new \RuntimeException("Missing output file for STDOUT stream.");
157
        }
158
159
        $GLOBALS['stdoutfile'] = $stdoutfile;
160
        $GLOBALS['stderrfile'] = $stderrfile;
161
162
        $process->run(function($type, $buffer)
163
        {
164
            if (Process::ERR === $type)
165
            {
166
                if ($GLOBALS['stderrfile'] !== null)
167
                {
168
                    file_put_contents($GLOBALS['stderrfile'], $buffer, FILE_APPEND | LOCK_EX);
169
                }
170
171
                if ($GLOBALS['stderrfile'] === null)
172
                {
173
                    file_put_contents($GLOBALS['stdoutfile'], $buffer, FILE_APPEND | LOCK_EX);
174
                }
175
                fwrite(STDERR, $buffer);
176
            }
177
178
            if (Process::ERR !== $type)
179
            {
180
                file_put_contents($GLOBALS['stdoutfile'], $buffer, FILE_APPEND | LOCK_EX);
181
                fwrite(STDOUT, $buffer);
182
            }
183
        });
184
        return $this->get_process_info($process);
185
    }
186
187
    /**
188
     * Wait for process to finish and return.
189
     *
190
     * @param  object  $process       process object
191
     * @param  boolean $fail_on_error whether or not to fail on error or pass
192
     * @return array
193
     */
194
    final protected function stream_stdout_wait(Process $process, $fail_on_error)
195
    {
196
        $process->run();
197
        if ($fail_on_error && !$process->isSuccessful())
198
        {
199
            throw new ProcessFailedException($process);
200
        }
201
        return $this->get_process_info($process);
202
    }
203
204
    /**
205
     * Stream STDOUT and STDERR to console (interactive mode).
206
     *
207
     * @param  object $process process object
208
     * @return array
209
     */
210
    final protected function stream_stdout_tty(Process $process)
211
    {
212
        $process->setTty(true);
213
        $process->start();
214
        $process->wait();
215
        return $this->get_process_info($process);
216
    }
217
218
    /**
219
     * Returns process information.
220
     *
221
     * @param  object $process process object
222
     * @return array
223
     */
224
    final protected function get_process_info(Process $process)
225
    {
226
        $cmd_executed = $process->getCommandLine();
227
        $stdout = $process->getOutput();
228
        $stderr = $process->getErrorOutput();
229
        $return_value = $process->getExitCode();
230
        $return_value_text = $process->getExitCodeText();
231
232
        return [
233
            'command'    => $cmd_executed,
234
            'stdout'     => $stdout,
235
            'stderr'     => $stderr,
236
            'error_code' => [$return_value, $return_value_text]
237
        ];
238
    }
239
}
240