summaryrefslogtreecommitdiff
path: root/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php')
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php236
1 files changed, 236 insertions, 0 deletions
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php b/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php
new file mode 100644
index 000000000..c4dc11146
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php
@@ -0,0 +1,236 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\PHP;
+
+use function array_merge;
+use function fclose;
+use function file_put_contents;
+use function fread;
+use function fwrite;
+use function is_array;
+use function is_resource;
+use function proc_close;
+use function proc_open;
+use function proc_terminate;
+use function rewind;
+use function sprintf;
+use function stream_get_contents;
+use function stream_select;
+use function sys_get_temp_dir;
+use function tempnam;
+use function unlink;
+use PHPUnit\Framework\Exception;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class DefaultPhpProcess extends AbstractPhpProcess
+{
+ /**
+ * @var string
+ */
+ protected $tempFile;
+
+ /**
+ * Runs a single job (PHP code) using a separate PHP process.
+ *
+ * @throws Exception
+ */
+ public function runJob(string $job, array $settings = []): array
+ {
+ if ($this->stdin || $this->useTemporaryFile()) {
+ if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) ||
+ file_put_contents($this->tempFile, $job) === false) {
+ throw new Exception(
+ 'Unable to write temporary file'
+ );
+ }
+
+ $job = $this->stdin;
+ }
+
+ return $this->runProcess($job, $settings);
+ }
+
+ /**
+ * Returns an array of file handles to be used in place of pipes.
+ */
+ protected function getHandles(): array
+ {
+ return [];
+ }
+
+ /**
+ * Handles creating the child process and returning the STDOUT and STDERR.
+ *
+ * @throws Exception
+ */
+ protected function runProcess(string $job, array $settings): array
+ {
+ $handles = $this->getHandles();
+
+ $env = null;
+
+ if ($this->env) {
+ $env = $_SERVER ?? [];
+ unset($env['argv'], $env['argc']);
+ $env = array_merge($env, $this->env);
+
+ foreach ($env as $envKey => $envVar) {
+ if (is_array($envVar)) {
+ unset($env[$envKey]);
+ }
+ }
+ }
+
+ $pipeSpec = [
+ 0 => $handles[0] ?? ['pipe', 'r'],
+ 1 => $handles[1] ?? ['pipe', 'w'],
+ 2 => $handles[2] ?? ['pipe', 'w'],
+ ];
+
+ $process = proc_open(
+ $this->getCommand($settings, $this->tempFile),
+ $pipeSpec,
+ $pipes,
+ null,
+ $env
+ );
+
+ if (!is_resource($process)) {
+ throw new Exception(
+ 'Unable to spawn worker process'
+ );
+ }
+
+ if ($job) {
+ $this->process($pipes[0], $job);
+ }
+
+ fclose($pipes[0]);
+
+ $stderr = $stdout = '';
+
+ if ($this->timeout) {
+ unset($pipes[0]);
+
+ while (true) {
+ $r = $pipes;
+ $w = null;
+ $e = null;
+
+ $n = @stream_select($r, $w, $e, $this->timeout);
+
+ if ($n === false) {
+ break;
+ }
+
+ if ($n === 0) {
+ proc_terminate($process, 9);
+
+ throw new Exception(
+ sprintf(
+ 'Job execution aborted after %d seconds',
+ $this->timeout
+ )
+ );
+ }
+
+ if ($n > 0) {
+ foreach ($r as $pipe) {
+ $pipeOffset = 0;
+
+ foreach ($pipes as $i => $origPipe) {
+ if ($pipe === $origPipe) {
+ $pipeOffset = $i;
+
+ break;
+ }
+ }
+
+ if (!$pipeOffset) {
+ break;
+ }
+
+ $line = fread($pipe, 8192);
+
+ if ($line === '' || $line === false) {
+ fclose($pipes[$pipeOffset]);
+
+ unset($pipes[$pipeOffset]);
+ } elseif ($pipeOffset === 1) {
+ $stdout .= $line;
+ } else {
+ $stderr .= $line;
+ }
+ }
+
+ if (empty($pipes)) {
+ break;
+ }
+ }
+ }
+ } else {
+ if (isset($pipes[1])) {
+ $stdout = stream_get_contents($pipes[1]);
+
+ fclose($pipes[1]);
+ }
+
+ if (isset($pipes[2])) {
+ $stderr = stream_get_contents($pipes[2]);
+
+ fclose($pipes[2]);
+ }
+ }
+
+ if (isset($handles[1])) {
+ rewind($handles[1]);
+
+ $stdout = stream_get_contents($handles[1]);
+
+ fclose($handles[1]);
+ }
+
+ if (isset($handles[2])) {
+ rewind($handles[2]);
+
+ $stderr = stream_get_contents($handles[2]);
+
+ fclose($handles[2]);
+ }
+
+ proc_close($process);
+
+ $this->cleanup();
+
+ return ['stdout' => $stdout, 'stderr' => $stderr];
+ }
+
+ /**
+ * @param resource $pipe
+ */
+ protected function process($pipe, string $job): void
+ {
+ fwrite($pipe, $job);
+ }
+
+ protected function cleanup(): void
+ {
+ if ($this->tempFile) {
+ unlink($this->tempFile);
+ }
+ }
+
+ protected function useTemporaryFile(): bool
+ {
+ return false;
+ }
+}