Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of PHPUnit.
4
 *
5
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PHPUnit\Util\PHP;
11
 
12
use function array_merge;
13
use function fclose;
14
use function file_put_contents;
15
use function fread;
16
use function fwrite;
17
use function is_array;
18
use function is_resource;
19
use function proc_close;
20
use function proc_open;
21
use function proc_terminate;
22
use function rewind;
23
use function sprintf;
24
use function stream_get_contents;
25
use function stream_select;
26
use function sys_get_temp_dir;
27
use function tempnam;
28
use function unlink;
29
use PHPUnit\Framework\Exception;
30
 
31
/**
32
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
33
 */
34
class DefaultPhpProcess extends AbstractPhpProcess
35
{
36
    /**
37
     * @var string
38
     */
39
    protected $tempFile;
40
 
41
    /**
42
     * Runs a single job (PHP code) using a separate PHP process.
43
     *
44
     * @throws Exception
45
     */
46
    public function runJob(string $job, array $settings = []): array
47
    {
48
        if ($this->stdin || $this->useTemporaryFile()) {
49
            if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) ||
50
                file_put_contents($this->tempFile, $job) === false) {
51
                throw new Exception(
52
                    'Unable to write temporary file'
53
                );
54
            }
55
 
56
            $job = $this->stdin;
57
        }
58
 
59
        return $this->runProcess($job, $settings);
60
    }
61
 
62
    /**
63
     * Returns an array of file handles to be used in place of pipes.
64
     */
65
    protected function getHandles(): array
66
    {
67
        return [];
68
    }
69
 
70
    /**
71
     * Handles creating the child process and returning the STDOUT and STDERR.
72
     *
73
     * @throws Exception
74
     */
75
    protected function runProcess(string $job, array $settings): array
76
    {
77
        $handles = $this->getHandles();
78
 
79
        $env = null;
80
 
81
        if ($this->env) {
82
            $env = $_SERVER ?? [];
83
            unset($env['argv'], $env['argc']);
84
            $env = array_merge($env, $this->env);
85
 
86
            foreach ($env as $envKey => $envVar) {
87
                if (is_array($envVar)) {
88
                    unset($env[$envKey]);
89
                }
90
            }
91
        }
92
 
93
        $pipeSpec = [
94
 
95
            1 => $handles[1] ?? ['pipe', 'w'],
96
            2 => $handles[2] ?? ['pipe', 'w'],
97
        ];
98
 
99
        $process = proc_open(
100
            $this->getCommand($settings, $this->tempFile),
101
            $pipeSpec,
102
            $pipes,
103
            null,
104
            $env
105
        );
106
 
107
        if (!is_resource($process)) {
108
            throw new Exception(
109
                'Unable to spawn worker process'
110
            );
111
        }
112
 
113
        if ($job) {
114
            $this->process($pipes[0], $job);
115
        }
116
 
117
        fclose($pipes[0]);
118
 
119
        $stderr = $stdout = '';
120
 
121
        if ($this->timeout) {
122
            unset($pipes[0]);
123
 
124
            while (true) {
125
                $r = $pipes;
126
                $w = null;
127
                $e = null;
128
 
129
                $n = @stream_select($r, $w, $e, $this->timeout);
130
 
131
                if ($n === false) {
132
                    break;
133
                }
134
 
135
                if ($n === 0) {
136
                    proc_terminate($process, 9);
137
 
138
                    throw new Exception(
139
                        sprintf(
140
                            'Job execution aborted after %d seconds',
141
                            $this->timeout
142
                        )
143
                    );
144
                }
145
 
146
                if ($n > 0) {
147
                    foreach ($r as $pipe) {
148
                        $pipeOffset = 0;
149
 
150
                        foreach ($pipes as $i => $origPipe) {
151
                            if ($pipe === $origPipe) {
152
                                $pipeOffset = $i;
153
 
154
                                break;
155
                            }
156
                        }
157
 
158
                        if (!$pipeOffset) {
159
                            break;
160
                        }
161
 
162
                        $line = fread($pipe, 8192);
163
 
164
                        if ($line === '' || $line === false) {
165
                            fclose($pipes[$pipeOffset]);
166
 
167
                            unset($pipes[$pipeOffset]);
168
                        } elseif ($pipeOffset === 1) {
169
                            $stdout .= $line;
170
                        } else {
171
                            $stderr .= $line;
172
                        }
173
                    }
174
 
175
                    if (empty($pipes)) {
176
                        break;
177
                    }
178
                }
179
            }
180
        } else {
181
            if (isset($pipes[1])) {
182
                $stdout = stream_get_contents($pipes[1]);
183
 
184
                fclose($pipes[1]);
185
            }
186
 
187
            if (isset($pipes[2])) {
188
                $stderr = stream_get_contents($pipes[2]);
189
 
190
                fclose($pipes[2]);
191
            }
192
        }
193
 
194
        if (isset($handles[1])) {
195
            rewind($handles[1]);
196
 
197
            $stdout = stream_get_contents($handles[1]);
198
 
199
            fclose($handles[1]);
200
        }
201
 
202
        if (isset($handles[2])) {
203
            rewind($handles[2]);
204
 
205
            $stderr = stream_get_contents($handles[2]);
206
 
207
            fclose($handles[2]);
208
        }
209
 
210
        proc_close($process);
211
 
212
        $this->cleanup();
213
 
214
        return ['stdout' => $stdout, 'stderr' => $stderr];
215
    }
216
 
217
    /**
218
     * @param resource $pipe
219
     */
220
    protected function process($pipe, string $job): void
221
    {
222
        fwrite($pipe, $job);
223
    }
224
 
225
    protected function cleanup(): void
226
    {
227
        if ($this->tempFile) {
228
            unlink($this->tempFile);
229
        }
230
    }
231
 
232
    protected function useTemporaryFile(): bool
233
    {
234
        return false;
235
    }
236
}