From 57ba6f1b3771b713064f081ddb0a7635447f2b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20H=C3=A4rtl?= Date: Sat, 10 Aug 2019 09:23:31 +0200 Subject: [PATCH] Issue #20 Add stream_set_blocking() calls for proc_open() --- README.md | 5 +++++ src/Command.php | 22 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5aac810..c227afd 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,11 @@ $command->setStdIn('string'); PHP working dir. * `$procEnv`: An array with environment variables to pass to `proc_open()`. Default is `null` for none. * `$procOptions`: An array of `other_options` for `proc_open()`. Default is `null` for none. + * `$nonBlockingMode`: Whether to set the stdout/stderr streams to non-blocking + mode when `proc_open()` is used. This can fix issues with long running + commands that hang indefinitely but can cause problems on Windows systems. + The default is `null` in which case non-blocking mode is only enabled on + non-Windows systems. * `$locale`: The locale to (temporarily) set with `setlocale()` before running the command. This can be set to e.g. `en_US.UTF-8` if you have issues with UTF-8 encoded arguments. diff --git a/src/Command.php b/src/Command.php index a14a6e4..49f8ea0 100644 --- a/src/Command.php +++ b/src/Command.php @@ -53,6 +53,15 @@ class Command */ public $procOptions; + /** + * @var bool|null whether to set the stdout/stderr streams to non-blocking mode + * when `proc_open()` is used. This can fix issues with long running + * commands that hang indefinitely but can cause problems on Windows + * systems. The default is `null` in which case non-blocking mode is only + * enabled on non-Windows systems. + */ + public $nonBlockingMode; + /** * @var null|string the locale to temporarily set before calling `escapeshellargs()`. Default is `null` for none. */ @@ -345,6 +354,13 @@ public function execute() $process = proc_open($command, $descriptors, $pipes, $this->procCwd, $this->procEnv, $this->procOptions); if (is_resource($process)) { + // Issue #20 Set non-blocking mode to fix hanging processes + $nonBlocking = $this->nonBlockingMode === null ? + !$this->getIsWindows() : $this->nonBlockingMode; + if ($nonBlocking) { + stream_set_blocking($pipes[1], false); + stream_set_blocking($pipes[2], false); + } if ($this->_stdIn!==null) { if (is_resource($this->_stdIn) && @@ -362,8 +378,10 @@ public function execute() $this->_exitCode = proc_close($process); - if ($this->_exitCode!==0) { - $this->_error = $this->_stdErr ? $this->_stdErr : "Failed without error message: $command"; + if ($this->_exitCode !== 0) { + $this->_error = $this->_stdErr ? + $this->_stdErr : + "Failed without error message: $command (Exit code: {$this->_exitCode})"; return false; } } else {