@@ -20,35 +20,35 @@ |
||
20 | 20 | */ |
21 | 21 | class ProcessFailedException extends RuntimeException |
22 | 22 | { |
23 | - private $process; |
|
24 | - |
|
25 | - public function __construct(Process $process) |
|
26 | - { |
|
27 | - if ($process->isSuccessful()) { |
|
28 | - throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); |
|
29 | - } |
|
30 | - |
|
31 | - $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", |
|
32 | - $process->getCommandLine(), |
|
33 | - $process->getExitCode(), |
|
34 | - $process->getExitCodeText(), |
|
35 | - $process->getWorkingDirectory() |
|
36 | - ); |
|
37 | - |
|
38 | - if (!$process->isOutputDisabled()) { |
|
39 | - $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", |
|
40 | - $process->getOutput(), |
|
41 | - $process->getErrorOutput() |
|
42 | - ); |
|
43 | - } |
|
44 | - |
|
45 | - parent::__construct($error); |
|
46 | - |
|
47 | - $this->process = $process; |
|
48 | - } |
|
49 | - |
|
50 | - public function getProcess() |
|
51 | - { |
|
52 | - return $this->process; |
|
53 | - } |
|
23 | + private $process; |
|
24 | + |
|
25 | + public function __construct(Process $process) |
|
26 | + { |
|
27 | + if ($process->isSuccessful()) { |
|
28 | + throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); |
|
29 | + } |
|
30 | + |
|
31 | + $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", |
|
32 | + $process->getCommandLine(), |
|
33 | + $process->getExitCode(), |
|
34 | + $process->getExitCodeText(), |
|
35 | + $process->getWorkingDirectory() |
|
36 | + ); |
|
37 | + |
|
38 | + if (!$process->isOutputDisabled()) { |
|
39 | + $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", |
|
40 | + $process->getOutput(), |
|
41 | + $process->getErrorOutput() |
|
42 | + ); |
|
43 | + } |
|
44 | + |
|
45 | + parent::__construct($error); |
|
46 | + |
|
47 | + $this->process = $process; |
|
48 | + } |
|
49 | + |
|
50 | + public function getProcess() |
|
51 | + { |
|
52 | + return $this->process; |
|
53 | + } |
|
54 | 54 | } |
@@ -22,27 +22,27 @@ |
||
22 | 22 | { |
23 | 23 | private $process; |
24 | 24 | |
25 | - public function __construct(Process $process) |
|
25 | + public function __construct( Process $process ) |
|
26 | 26 | { |
27 | - if ($process->isSuccessful()) { |
|
28 | - throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); |
|
27 | + if ( $process->isSuccessful() ) { |
|
28 | + throw new InvalidArgumentException( 'Expected a failed process, but the given process was successful.' ); |
|
29 | 29 | } |
30 | 30 | |
31 | - $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", |
|
31 | + $error = sprintf( 'The command "%s" failed.' . "\n\nExit Code: %s(%s)\n\nWorking directory: %s", |
|
32 | 32 | $process->getCommandLine(), |
33 | 33 | $process->getExitCode(), |
34 | 34 | $process->getExitCodeText(), |
35 | 35 | $process->getWorkingDirectory() |
36 | 36 | ); |
37 | 37 | |
38 | - if (!$process->isOutputDisabled()) { |
|
39 | - $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", |
|
38 | + if ( ! $process->isOutputDisabled() ) { |
|
39 | + $error .= sprintf( "\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", |
|
40 | 40 | $process->getOutput(), |
41 | 41 | $process->getErrorOutput() |
42 | 42 | ); |
43 | 43 | } |
44 | 44 | |
45 | - parent::__construct($error); |
|
45 | + parent::__construct( $error ); |
|
46 | 46 | |
47 | 47 | $this->process = $process; |
48 | 48 | } |
@@ -18,12 +18,10 @@ discard block |
||
18 | 18 | * |
19 | 19 | * @author Johannes M. Schmitt <[email protected]> |
20 | 20 | */ |
21 | -class ProcessFailedException extends RuntimeException |
|
22 | -{ |
|
21 | +class ProcessFailedException extends RuntimeException { |
|
23 | 22 | private $process; |
24 | 23 | |
25 | - public function __construct(Process $process) |
|
26 | - { |
|
24 | + public function __construct(Process $process) { |
|
27 | 25 | if ($process->isSuccessful()) { |
28 | 26 | throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); |
29 | 27 | } |
@@ -47,8 +45,7 @@ discard block |
||
47 | 45 | $this->process = $process; |
48 | 46 | } |
49 | 47 | |
50 | - public function getProcess() |
|
51 | - { |
|
48 | + public function getProcess() { |
|
52 | 49 | return $this->process; |
53 | 50 | } |
54 | 51 | } |
@@ -16,6 +16,5 @@ |
||
16 | 16 | * |
17 | 17 | * @author Johannes M. Schmitt <[email protected]> |
18 | 18 | */ |
19 | -class RuntimeException extends \RuntimeException implements ExceptionInterface |
|
20 | -{ |
|
19 | +class RuntimeException extends \RuntimeException implements ExceptionInterface { |
|
21 | 20 | } |
@@ -20,22 +20,22 @@ |
||
20 | 20 | */ |
21 | 21 | final class ProcessSignaledException extends RuntimeException |
22 | 22 | { |
23 | - private $process; |
|
23 | + private $process; |
|
24 | 24 | |
25 | - public function __construct(Process $process) |
|
26 | - { |
|
27 | - $this->process = $process; |
|
25 | + public function __construct(Process $process) |
|
26 | + { |
|
27 | + $this->process = $process; |
|
28 | 28 | |
29 | - parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); |
|
30 | - } |
|
29 | + parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); |
|
30 | + } |
|
31 | 31 | |
32 | - public function getProcess(): Process |
|
33 | - { |
|
34 | - return $this->process; |
|
35 | - } |
|
32 | + public function getProcess(): Process |
|
33 | + { |
|
34 | + return $this->process; |
|
35 | + } |
|
36 | 36 | |
37 | - public function getSignal(): int |
|
38 | - { |
|
39 | - return $this->getProcess()->getTermSignal(); |
|
40 | - } |
|
37 | + public function getSignal(): int |
|
38 | + { |
|
39 | + return $this->getProcess()->getTermSignal(); |
|
40 | + } |
|
41 | 41 | } |
@@ -22,11 +22,11 @@ |
||
22 | 22 | { |
23 | 23 | private $process; |
24 | 24 | |
25 | - public function __construct(Process $process) |
|
25 | + public function __construct( Process $process ) |
|
26 | 26 | { |
27 | 27 | $this->process = $process; |
28 | 28 | |
29 | - parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); |
|
29 | + parent::__construct( sprintf( 'The process has been signaled with signal "%s".', $process->getTermSignal() ) ); |
|
30 | 30 | } |
31 | 31 | |
32 | 32 | public function getProcess(): Process |
@@ -18,12 +18,10 @@ |
||
18 | 18 | * |
19 | 19 | * @author Sullivan Senechal <[email protected]> |
20 | 20 | */ |
21 | -final class ProcessSignaledException extends RuntimeException |
|
22 | -{ |
|
21 | +final class ProcessSignaledException extends RuntimeException { |
|
23 | 22 | private $process; |
24 | 23 | |
25 | - public function __construct(Process $process) |
|
26 | - { |
|
24 | + public function __construct(Process $process) { |
|
27 | 25 | $this->process = $process; |
28 | 26 | |
29 | 27 | parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); |
@@ -16,6 +16,5 @@ |
||
16 | 16 | * |
17 | 17 | * @author Romain Neutron <[email protected]> |
18 | 18 | */ |
19 | -class LogicException extends \LogicException implements ExceptionInterface |
|
20 | -{ |
|
19 | +class LogicException extends \LogicException implements ExceptionInterface { |
|
21 | 20 | } |
@@ -22,48 +22,48 @@ |
||
22 | 22 | */ |
23 | 23 | class ProcessUtils |
24 | 24 | { |
25 | - /** |
|
26 | - * This class should not be instantiated. |
|
27 | - */ |
|
28 | - private function __construct() |
|
29 | - { |
|
30 | - } |
|
25 | + /** |
|
26 | + * This class should not be instantiated. |
|
27 | + */ |
|
28 | + private function __construct() |
|
29 | + { |
|
30 | + } |
|
31 | 31 | |
32 | - /** |
|
33 | - * Validates and normalizes a Process input. |
|
34 | - * |
|
35 | - * @param string $caller The name of method call that validates the input |
|
36 | - * @param mixed $input The input to validate |
|
37 | - * |
|
38 | - * @return mixed The validated input |
|
39 | - * |
|
40 | - * @throws InvalidArgumentException In case the input is not valid |
|
41 | - */ |
|
42 | - public static function validateInput(string $caller, $input) |
|
43 | - { |
|
44 | - if (null !== $input) { |
|
45 | - if (\is_resource($input)) { |
|
46 | - return $input; |
|
47 | - } |
|
48 | - if (\is_string($input)) { |
|
49 | - return $input; |
|
50 | - } |
|
51 | - if (is_scalar($input)) { |
|
52 | - return (string) $input; |
|
53 | - } |
|
54 | - if ($input instanceof Process) { |
|
55 | - return $input->getIterator($input::ITER_SKIP_ERR); |
|
56 | - } |
|
57 | - if ($input instanceof \Iterator) { |
|
58 | - return $input; |
|
59 | - } |
|
60 | - if ($input instanceof \Traversable) { |
|
61 | - return new \IteratorIterator($input); |
|
62 | - } |
|
32 | + /** |
|
33 | + * Validates and normalizes a Process input. |
|
34 | + * |
|
35 | + * @param string $caller The name of method call that validates the input |
|
36 | + * @param mixed $input The input to validate |
|
37 | + * |
|
38 | + * @return mixed The validated input |
|
39 | + * |
|
40 | + * @throws InvalidArgumentException In case the input is not valid |
|
41 | + */ |
|
42 | + public static function validateInput(string $caller, $input) |
|
43 | + { |
|
44 | + if (null !== $input) { |
|
45 | + if (\is_resource($input)) { |
|
46 | + return $input; |
|
47 | + } |
|
48 | + if (\is_string($input)) { |
|
49 | + return $input; |
|
50 | + } |
|
51 | + if (is_scalar($input)) { |
|
52 | + return (string) $input; |
|
53 | + } |
|
54 | + if ($input instanceof Process) { |
|
55 | + return $input->getIterator($input::ITER_SKIP_ERR); |
|
56 | + } |
|
57 | + if ($input instanceof \Iterator) { |
|
58 | + return $input; |
|
59 | + } |
|
60 | + if ($input instanceof \Traversable) { |
|
61 | + return new \IteratorIterator($input); |
|
62 | + } |
|
63 | 63 | |
64 | - throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); |
|
65 | - } |
|
64 | + throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); |
|
65 | + } |
|
66 | 66 | |
67 | - return $input; |
|
68 | - } |
|
67 | + return $input; |
|
68 | + } |
|
69 | 69 | } |
@@ -39,29 +39,29 @@ |
||
39 | 39 | * |
40 | 40 | * @throws InvalidArgumentException In case the input is not valid |
41 | 41 | */ |
42 | - public static function validateInput(string $caller, $input) |
|
42 | + public static function validateInput( string $caller, $input ) |
|
43 | 43 | { |
44 | - if (null !== $input) { |
|
45 | - if (\is_resource($input)) { |
|
44 | + if ( null !== $input ) { |
|
45 | + if ( \is_resource( $input ) ) { |
|
46 | 46 | return $input; |
47 | 47 | } |
48 | - if (\is_string($input)) { |
|
48 | + if ( \is_string( $input ) ) { |
|
49 | 49 | return $input; |
50 | 50 | } |
51 | - if (is_scalar($input)) { |
|
52 | - return (string) $input; |
|
51 | + if ( is_scalar( $input ) ) { |
|
52 | + return (string)$input; |
|
53 | 53 | } |
54 | - if ($input instanceof Process) { |
|
55 | - return $input->getIterator($input::ITER_SKIP_ERR); |
|
54 | + if ( $input instanceof Process ) { |
|
55 | + return $input->getIterator( $input::ITER_SKIP_ERR ); |
|
56 | 56 | } |
57 | - if ($input instanceof \Iterator) { |
|
57 | + if ( $input instanceof \Iterator ) { |
|
58 | 58 | return $input; |
59 | 59 | } |
60 | - if ($input instanceof \Traversable) { |
|
61 | - return new \IteratorIterator($input); |
|
60 | + if ( $input instanceof \Traversable ) { |
|
61 | + return new \IteratorIterator( $input ); |
|
62 | 62 | } |
63 | 63 | |
64 | - throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); |
|
64 | + throw new InvalidArgumentException( sprintf( '"%s" only accepts strings, Traversable objects or stream resources.', $caller ) ); |
|
65 | 65 | } |
66 | 66 | |
67 | 67 | return $input; |
@@ -20,13 +20,11 @@ discard block |
||
20 | 20 | * |
21 | 21 | * @author Martin Hasoň <[email protected]> |
22 | 22 | */ |
23 | -class ProcessUtils |
|
24 | -{ |
|
23 | +class ProcessUtils { |
|
25 | 24 | /** |
26 | 25 | * This class should not be instantiated. |
27 | 26 | */ |
28 | - private function __construct() |
|
29 | - { |
|
27 | + private function __construct() { |
|
30 | 28 | } |
31 | 29 | |
32 | 30 | /** |
@@ -39,8 +37,7 @@ discard block |
||
39 | 37 | * |
40 | 38 | * @throws InvalidArgumentException In case the input is not valid |
41 | 39 | */ |
42 | - public static function validateInput(string $caller, $input) |
|
43 | - { |
|
40 | + public static function validateInput(string $caller, $input) { |
|
44 | 41 | if (null !== $input) { |
45 | 42 | if (\is_resource($input)) { |
46 | 43 | return $input; |
@@ -20,42 +20,42 @@ |
||
20 | 20 | */ |
21 | 21 | interface PipesInterface |
22 | 22 | { |
23 | - public const CHUNK_SIZE = 16384; |
|
24 | - |
|
25 | - /** |
|
26 | - * Returns an array of descriptors for the use of proc_open. |
|
27 | - */ |
|
28 | - public function getDescriptors(): array; |
|
29 | - |
|
30 | - /** |
|
31 | - * Returns an array of filenames indexed by their related stream in case these pipes use temporary files. |
|
32 | - * |
|
33 | - * @return string[] |
|
34 | - */ |
|
35 | - public function getFiles(): array; |
|
36 | - |
|
37 | - /** |
|
38 | - * Reads data in file handles and pipes. |
|
39 | - * |
|
40 | - * @param bool $blocking Whether to use blocking calls or not |
|
41 | - * @param bool $close Whether to close pipes if they've reached EOF |
|
42 | - * |
|
43 | - * @return string[] An array of read data indexed by their fd |
|
44 | - */ |
|
45 | - public function readAndWrite(bool $blocking, bool $close = false): array; |
|
46 | - |
|
47 | - /** |
|
48 | - * Returns if the current state has open file handles or pipes. |
|
49 | - */ |
|
50 | - public function areOpen(): bool; |
|
51 | - |
|
52 | - /** |
|
53 | - * Returns if pipes are able to read output. |
|
54 | - */ |
|
55 | - public function haveReadSupport(): bool; |
|
56 | - |
|
57 | - /** |
|
58 | - * Closes file handles and pipes. |
|
59 | - */ |
|
60 | - public function close(); |
|
23 | + public const CHUNK_SIZE = 16384; |
|
24 | + |
|
25 | + /** |
|
26 | + * Returns an array of descriptors for the use of proc_open. |
|
27 | + */ |
|
28 | + public function getDescriptors(): array; |
|
29 | + |
|
30 | + /** |
|
31 | + * Returns an array of filenames indexed by their related stream in case these pipes use temporary files. |
|
32 | + * |
|
33 | + * @return string[] |
|
34 | + */ |
|
35 | + public function getFiles(): array; |
|
36 | + |
|
37 | + /** |
|
38 | + * Reads data in file handles and pipes. |
|
39 | + * |
|
40 | + * @param bool $blocking Whether to use blocking calls or not |
|
41 | + * @param bool $close Whether to close pipes if they've reached EOF |
|
42 | + * |
|
43 | + * @return string[] An array of read data indexed by their fd |
|
44 | + */ |
|
45 | + public function readAndWrite(bool $blocking, bool $close = false): array; |
|
46 | + |
|
47 | + /** |
|
48 | + * Returns if the current state has open file handles or pipes. |
|
49 | + */ |
|
50 | + public function areOpen(): bool; |
|
51 | + |
|
52 | + /** |
|
53 | + * Returns if pipes are able to read output. |
|
54 | + */ |
|
55 | + public function haveReadSupport(): bool; |
|
56 | + |
|
57 | + /** |
|
58 | + * Closes file handles and pipes. |
|
59 | + */ |
|
60 | + public function close(); |
|
61 | 61 | } |
@@ -42,7 +42,7 @@ |
||
42 | 42 | * |
43 | 43 | * @return string[] An array of read data indexed by their fd |
44 | 44 | */ |
45 | - public function readAndWrite(bool $blocking, bool $close = false): array; |
|
45 | + public function readAndWrite( bool $blocking, bool $close = false ): array; |
|
46 | 46 | |
47 | 47 | /** |
48 | 48 | * Returns if the current state has open file handles or pipes. |
@@ -18,8 +18,7 @@ |
||
18 | 18 | * |
19 | 19 | * @internal |
20 | 20 | */ |
21 | -interface PipesInterface |
|
22 | -{ |
|
21 | +interface PipesInterface { |
|
23 | 22 | public const CHUNK_SIZE = 16384; |
24 | 23 | |
25 | 24 | /** |
@@ -20,159 +20,159 @@ |
||
20 | 20 | */ |
21 | 21 | abstract class AbstractPipes implements PipesInterface |
22 | 22 | { |
23 | - public $pipes = []; |
|
24 | - |
|
25 | - private $inputBuffer = ''; |
|
26 | - private $input; |
|
27 | - private $blocked = true; |
|
28 | - private $lastError; |
|
29 | - |
|
30 | - /** |
|
31 | - * @param resource|string|int|float|bool|\Iterator|null $input |
|
32 | - */ |
|
33 | - public function __construct($input) |
|
34 | - { |
|
35 | - if (\is_resource($input) || $input instanceof \Iterator) { |
|
36 | - $this->input = $input; |
|
37 | - } elseif (\is_string($input)) { |
|
38 | - $this->inputBuffer = $input; |
|
39 | - } else { |
|
40 | - $this->inputBuffer = (string) $input; |
|
41 | - } |
|
42 | - } |
|
43 | - |
|
44 | - /** |
|
45 | - * {@inheritdoc} |
|
46 | - */ |
|
47 | - public function close() |
|
48 | - { |
|
49 | - foreach ($this->pipes as $pipe) { |
|
50 | - fclose($pipe); |
|
51 | - } |
|
52 | - $this->pipes = []; |
|
53 | - } |
|
54 | - |
|
55 | - /** |
|
56 | - * Returns true if a system call has been interrupted. |
|
57 | - */ |
|
58 | - protected function hasSystemCallBeenInterrupted(): bool |
|
59 | - { |
|
60 | - $lastError = $this->lastError; |
|
61 | - $this->lastError = null; |
|
62 | - |
|
63 | - // stream_select returns false when the `select` system call is interrupted by an incoming signal |
|
64 | - return null !== $lastError && false !== stripos($lastError, 'interrupted system call'); |
|
65 | - } |
|
66 | - |
|
67 | - /** |
|
68 | - * Unblocks streams. |
|
69 | - */ |
|
70 | - protected function unblock() |
|
71 | - { |
|
72 | - if (!$this->blocked) { |
|
73 | - return; |
|
74 | - } |
|
75 | - |
|
76 | - foreach ($this->pipes as $pipe) { |
|
77 | - stream_set_blocking($pipe, 0); |
|
78 | - } |
|
79 | - if (\is_resource($this->input)) { |
|
80 | - stream_set_blocking($this->input, 0); |
|
81 | - } |
|
82 | - |
|
83 | - $this->blocked = false; |
|
84 | - } |
|
85 | - |
|
86 | - /** |
|
87 | - * Writes input to stdin. |
|
88 | - * |
|
89 | - * @throws InvalidArgumentException When an input iterator yields a non supported value |
|
90 | - */ |
|
91 | - protected function write(): ?array |
|
92 | - { |
|
93 | - if (!isset($this->pipes[0])) { |
|
94 | - return null; |
|
95 | - } |
|
96 | - $input = $this->input; |
|
97 | - |
|
98 | - if ($input instanceof \Iterator) { |
|
99 | - if (!$input->valid()) { |
|
100 | - $input = null; |
|
101 | - } elseif (\is_resource($input = $input->current())) { |
|
102 | - stream_set_blocking($input, 0); |
|
103 | - } elseif (!isset($this->inputBuffer[0])) { |
|
104 | - if (!\is_string($input)) { |
|
105 | - if (!is_scalar($input)) { |
|
106 | - throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); |
|
107 | - } |
|
108 | - $input = (string) $input; |
|
109 | - } |
|
110 | - $this->inputBuffer = $input; |
|
111 | - $this->input->next(); |
|
112 | - $input = null; |
|
113 | - } else { |
|
114 | - $input = null; |
|
115 | - } |
|
116 | - } |
|
117 | - |
|
118 | - $r = $e = []; |
|
119 | - $w = [$this->pipes[0]]; |
|
120 | - |
|
121 | - // let's have a look if something changed in streams |
|
122 | - if (false === @stream_select($r, $w, $e, 0, 0)) { |
|
123 | - return null; |
|
124 | - } |
|
125 | - |
|
126 | - foreach ($w as $stdin) { |
|
127 | - if (isset($this->inputBuffer[0])) { |
|
128 | - $written = fwrite($stdin, $this->inputBuffer); |
|
129 | - $this->inputBuffer = substr($this->inputBuffer, $written); |
|
130 | - if (isset($this->inputBuffer[0])) { |
|
131 | - return [$this->pipes[0]]; |
|
132 | - } |
|
133 | - } |
|
134 | - |
|
135 | - if ($input) { |
|
136 | - for (;;) { |
|
137 | - $data = fread($input, self::CHUNK_SIZE); |
|
138 | - if (!isset($data[0])) { |
|
139 | - break; |
|
140 | - } |
|
141 | - $written = fwrite($stdin, $data); |
|
142 | - $data = substr($data, $written); |
|
143 | - if (isset($data[0])) { |
|
144 | - $this->inputBuffer = $data; |
|
145 | - |
|
146 | - return [$this->pipes[0]]; |
|
147 | - } |
|
148 | - } |
|
149 | - if (feof($input)) { |
|
150 | - if ($this->input instanceof \Iterator) { |
|
151 | - $this->input->next(); |
|
152 | - } else { |
|
153 | - $this->input = null; |
|
154 | - } |
|
155 | - } |
|
156 | - } |
|
157 | - } |
|
158 | - |
|
159 | - // no input to read on resource, buffer is empty |
|
160 | - if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) { |
|
161 | - $this->input = null; |
|
162 | - fclose($this->pipes[0]); |
|
163 | - unset($this->pipes[0]); |
|
164 | - } elseif (!$w) { |
|
165 | - return [$this->pipes[0]]; |
|
166 | - } |
|
167 | - |
|
168 | - return null; |
|
169 | - } |
|
170 | - |
|
171 | - /** |
|
172 | - * @internal |
|
173 | - */ |
|
174 | - public function handleError(int $type, string $msg) |
|
175 | - { |
|
176 | - $this->lastError = $msg; |
|
177 | - } |
|
23 | + public $pipes = []; |
|
24 | + |
|
25 | + private $inputBuffer = ''; |
|
26 | + private $input; |
|
27 | + private $blocked = true; |
|
28 | + private $lastError; |
|
29 | + |
|
30 | + /** |
|
31 | + * @param resource|string|int|float|bool|\Iterator|null $input |
|
32 | + */ |
|
33 | + public function __construct($input) |
|
34 | + { |
|
35 | + if (\is_resource($input) || $input instanceof \Iterator) { |
|
36 | + $this->input = $input; |
|
37 | + } elseif (\is_string($input)) { |
|
38 | + $this->inputBuffer = $input; |
|
39 | + } else { |
|
40 | + $this->inputBuffer = (string) $input; |
|
41 | + } |
|
42 | + } |
|
43 | + |
|
44 | + /** |
|
45 | + * {@inheritdoc} |
|
46 | + */ |
|
47 | + public function close() |
|
48 | + { |
|
49 | + foreach ($this->pipes as $pipe) { |
|
50 | + fclose($pipe); |
|
51 | + } |
|
52 | + $this->pipes = []; |
|
53 | + } |
|
54 | + |
|
55 | + /** |
|
56 | + * Returns true if a system call has been interrupted. |
|
57 | + */ |
|
58 | + protected function hasSystemCallBeenInterrupted(): bool |
|
59 | + { |
|
60 | + $lastError = $this->lastError; |
|
61 | + $this->lastError = null; |
|
62 | + |
|
63 | + // stream_select returns false when the `select` system call is interrupted by an incoming signal |
|
64 | + return null !== $lastError && false !== stripos($lastError, 'interrupted system call'); |
|
65 | + } |
|
66 | + |
|
67 | + /** |
|
68 | + * Unblocks streams. |
|
69 | + */ |
|
70 | + protected function unblock() |
|
71 | + { |
|
72 | + if (!$this->blocked) { |
|
73 | + return; |
|
74 | + } |
|
75 | + |
|
76 | + foreach ($this->pipes as $pipe) { |
|
77 | + stream_set_blocking($pipe, 0); |
|
78 | + } |
|
79 | + if (\is_resource($this->input)) { |
|
80 | + stream_set_blocking($this->input, 0); |
|
81 | + } |
|
82 | + |
|
83 | + $this->blocked = false; |
|
84 | + } |
|
85 | + |
|
86 | + /** |
|
87 | + * Writes input to stdin. |
|
88 | + * |
|
89 | + * @throws InvalidArgumentException When an input iterator yields a non supported value |
|
90 | + */ |
|
91 | + protected function write(): ?array |
|
92 | + { |
|
93 | + if (!isset($this->pipes[0])) { |
|
94 | + return null; |
|
95 | + } |
|
96 | + $input = $this->input; |
|
97 | + |
|
98 | + if ($input instanceof \Iterator) { |
|
99 | + if (!$input->valid()) { |
|
100 | + $input = null; |
|
101 | + } elseif (\is_resource($input = $input->current())) { |
|
102 | + stream_set_blocking($input, 0); |
|
103 | + } elseif (!isset($this->inputBuffer[0])) { |
|
104 | + if (!\is_string($input)) { |
|
105 | + if (!is_scalar($input)) { |
|
106 | + throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); |
|
107 | + } |
|
108 | + $input = (string) $input; |
|
109 | + } |
|
110 | + $this->inputBuffer = $input; |
|
111 | + $this->input->next(); |
|
112 | + $input = null; |
|
113 | + } else { |
|
114 | + $input = null; |
|
115 | + } |
|
116 | + } |
|
117 | + |
|
118 | + $r = $e = []; |
|
119 | + $w = [$this->pipes[0]]; |
|
120 | + |
|
121 | + // let's have a look if something changed in streams |
|
122 | + if (false === @stream_select($r, $w, $e, 0, 0)) { |
|
123 | + return null; |
|
124 | + } |
|
125 | + |
|
126 | + foreach ($w as $stdin) { |
|
127 | + if (isset($this->inputBuffer[0])) { |
|
128 | + $written = fwrite($stdin, $this->inputBuffer); |
|
129 | + $this->inputBuffer = substr($this->inputBuffer, $written); |
|
130 | + if (isset($this->inputBuffer[0])) { |
|
131 | + return [$this->pipes[0]]; |
|
132 | + } |
|
133 | + } |
|
134 | + |
|
135 | + if ($input) { |
|
136 | + for (;;) { |
|
137 | + $data = fread($input, self::CHUNK_SIZE); |
|
138 | + if (!isset($data[0])) { |
|
139 | + break; |
|
140 | + } |
|
141 | + $written = fwrite($stdin, $data); |
|
142 | + $data = substr($data, $written); |
|
143 | + if (isset($data[0])) { |
|
144 | + $this->inputBuffer = $data; |
|
145 | + |
|
146 | + return [$this->pipes[0]]; |
|
147 | + } |
|
148 | + } |
|
149 | + if (feof($input)) { |
|
150 | + if ($this->input instanceof \Iterator) { |
|
151 | + $this->input->next(); |
|
152 | + } else { |
|
153 | + $this->input = null; |
|
154 | + } |
|
155 | + } |
|
156 | + } |
|
157 | + } |
|
158 | + |
|
159 | + // no input to read on resource, buffer is empty |
|
160 | + if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) { |
|
161 | + $this->input = null; |
|
162 | + fclose($this->pipes[0]); |
|
163 | + unset($this->pipes[0]); |
|
164 | + } elseif (!$w) { |
|
165 | + return [$this->pipes[0]]; |
|
166 | + } |
|
167 | + |
|
168 | + return null; |
|
169 | + } |
|
170 | + |
|
171 | + /** |
|
172 | + * @internal |
|
173 | + */ |
|
174 | + public function handleError(int $type, string $msg) |
|
175 | + { |
|
176 | + $this->lastError = $msg; |
|
177 | + } |
|
178 | 178 | } |
@@ -20,7 +20,7 @@ discard block |
||
20 | 20 | */ |
21 | 21 | abstract class AbstractPipes implements PipesInterface |
22 | 22 | { |
23 | - public $pipes = []; |
|
23 | + public $pipes = [ ]; |
|
24 | 24 | |
25 | 25 | private $inputBuffer = ''; |
26 | 26 | private $input; |
@@ -30,14 +30,14 @@ discard block |
||
30 | 30 | /** |
31 | 31 | * @param resource|string|int|float|bool|\Iterator|null $input |
32 | 32 | */ |
33 | - public function __construct($input) |
|
33 | + public function __construct( $input ) |
|
34 | 34 | { |
35 | - if (\is_resource($input) || $input instanceof \Iterator) { |
|
35 | + if ( \is_resource( $input ) || $input instanceof \Iterator ) { |
|
36 | 36 | $this->input = $input; |
37 | - } elseif (\is_string($input)) { |
|
37 | + } elseif ( \is_string( $input ) ) { |
|
38 | 38 | $this->inputBuffer = $input; |
39 | 39 | } else { |
40 | - $this->inputBuffer = (string) $input; |
|
40 | + $this->inputBuffer = (string)$input; |
|
41 | 41 | } |
42 | 42 | } |
43 | 43 | |
@@ -46,10 +46,10 @@ discard block |
||
46 | 46 | */ |
47 | 47 | public function close() |
48 | 48 | { |
49 | - foreach ($this->pipes as $pipe) { |
|
50 | - fclose($pipe); |
|
49 | + foreach ( $this->pipes as $pipe ) { |
|
50 | + fclose( $pipe ); |
|
51 | 51 | } |
52 | - $this->pipes = []; |
|
52 | + $this->pipes = [ ]; |
|
53 | 53 | } |
54 | 54 | |
55 | 55 | /** |
@@ -61,7 +61,7 @@ discard block |
||
61 | 61 | $this->lastError = null; |
62 | 62 | |
63 | 63 | // stream_select returns false when the `select` system call is interrupted by an incoming signal |
64 | - return null !== $lastError && false !== stripos($lastError, 'interrupted system call'); |
|
64 | + return null !== $lastError && false !== stripos( $lastError, 'interrupted system call' ); |
|
65 | 65 | } |
66 | 66 | |
67 | 67 | /** |
@@ -69,15 +69,15 @@ discard block |
||
69 | 69 | */ |
70 | 70 | protected function unblock() |
71 | 71 | { |
72 | - if (!$this->blocked) { |
|
72 | + if ( ! $this->blocked ) { |
|
73 | 73 | return; |
74 | 74 | } |
75 | 75 | |
76 | - foreach ($this->pipes as $pipe) { |
|
77 | - stream_set_blocking($pipe, 0); |
|
76 | + foreach ( $this->pipes as $pipe ) { |
|
77 | + stream_set_blocking( $pipe, 0 ); |
|
78 | 78 | } |
79 | - if (\is_resource($this->input)) { |
|
80 | - stream_set_blocking($this->input, 0); |
|
79 | + if ( \is_resource( $this->input ) ) { |
|
80 | + stream_set_blocking( $this->input, 0 ); |
|
81 | 81 | } |
82 | 82 | |
83 | 83 | $this->blocked = false; |
@@ -90,22 +90,22 @@ discard block |
||
90 | 90 | */ |
91 | 91 | protected function write(): ?array |
92 | 92 | { |
93 | - if (!isset($this->pipes[0])) { |
|
93 | + if ( ! isset( $this->pipes[ 0 ] ) ) { |
|
94 | 94 | return null; |
95 | 95 | } |
96 | 96 | $input = $this->input; |
97 | 97 | |
98 | - if ($input instanceof \Iterator) { |
|
99 | - if (!$input->valid()) { |
|
98 | + if ( $input instanceof \Iterator ) { |
|
99 | + if ( ! $input->valid() ) { |
|
100 | 100 | $input = null; |
101 | - } elseif (\is_resource($input = $input->current())) { |
|
102 | - stream_set_blocking($input, 0); |
|
103 | - } elseif (!isset($this->inputBuffer[0])) { |
|
104 | - if (!\is_string($input)) { |
|
105 | - if (!is_scalar($input)) { |
|
106 | - throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); |
|
101 | + } elseif ( \is_resource( $input = $input->current() ) ) { |
|
102 | + stream_set_blocking( $input, 0 ); |
|
103 | + } elseif ( ! isset( $this->inputBuffer[ 0 ] ) ) { |
|
104 | + if ( ! \is_string( $input ) ) { |
|
105 | + if ( ! is_scalar( $input ) ) { |
|
106 | + throw new InvalidArgumentException( sprintf( '"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type( $this->input ), get_debug_type( $input ) ) ); |
|
107 | 107 | } |
108 | - $input = (string) $input; |
|
108 | + $input = (string)$input; |
|
109 | 109 | } |
110 | 110 | $this->inputBuffer = $input; |
111 | 111 | $this->input->next(); |
@@ -115,39 +115,39 @@ discard block |
||
115 | 115 | } |
116 | 116 | } |
117 | 117 | |
118 | - $r = $e = []; |
|
119 | - $w = [$this->pipes[0]]; |
|
118 | + $r = $e = [ ]; |
|
119 | + $w = [ $this->pipes[ 0 ] ]; |
|
120 | 120 | |
121 | 121 | // let's have a look if something changed in streams |
122 | - if (false === @stream_select($r, $w, $e, 0, 0)) { |
|
122 | + if ( false === @stream_select( $r, $w, $e, 0, 0 ) ) { |
|
123 | 123 | return null; |
124 | 124 | } |
125 | 125 | |
126 | - foreach ($w as $stdin) { |
|
127 | - if (isset($this->inputBuffer[0])) { |
|
128 | - $written = fwrite($stdin, $this->inputBuffer); |
|
129 | - $this->inputBuffer = substr($this->inputBuffer, $written); |
|
130 | - if (isset($this->inputBuffer[0])) { |
|
131 | - return [$this->pipes[0]]; |
|
126 | + foreach ( $w as $stdin ) { |
|
127 | + if ( isset( $this->inputBuffer[ 0 ] ) ) { |
|
128 | + $written = fwrite( $stdin, $this->inputBuffer ); |
|
129 | + $this->inputBuffer = substr( $this->inputBuffer, $written ); |
|
130 | + if ( isset( $this->inputBuffer[ 0 ] ) ) { |
|
131 | + return [ $this->pipes[ 0 ] ]; |
|
132 | 132 | } |
133 | 133 | } |
134 | 134 | |
135 | - if ($input) { |
|
136 | - for (;;) { |
|
137 | - $data = fread($input, self::CHUNK_SIZE); |
|
138 | - if (!isset($data[0])) { |
|
135 | + if ( $input ) { |
|
136 | + for ( ;; ) { |
|
137 | + $data = fread( $input, self::CHUNK_SIZE ); |
|
138 | + if ( ! isset( $data[ 0 ] ) ) { |
|
139 | 139 | break; |
140 | 140 | } |
141 | - $written = fwrite($stdin, $data); |
|
142 | - $data = substr($data, $written); |
|
143 | - if (isset($data[0])) { |
|
141 | + $written = fwrite( $stdin, $data ); |
|
142 | + $data = substr( $data, $written ); |
|
143 | + if ( isset( $data[ 0 ] ) ) { |
|
144 | 144 | $this->inputBuffer = $data; |
145 | 145 | |
146 | - return [$this->pipes[0]]; |
|
146 | + return [ $this->pipes[ 0 ] ]; |
|
147 | 147 | } |
148 | 148 | } |
149 | - if (feof($input)) { |
|
150 | - if ($this->input instanceof \Iterator) { |
|
149 | + if ( feof( $input ) ) { |
|
150 | + if ( $this->input instanceof \Iterator ) { |
|
151 | 151 | $this->input->next(); |
152 | 152 | } else { |
153 | 153 | $this->input = null; |
@@ -157,12 +157,12 @@ discard block |
||
157 | 157 | } |
158 | 158 | |
159 | 159 | // no input to read on resource, buffer is empty |
160 | - if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) { |
|
160 | + if ( ! isset( $this->inputBuffer[ 0 ] ) && ! ( $this->input instanceof \Iterator ? $this->input->valid() : $this->input ) ) { |
|
161 | 161 | $this->input = null; |
162 | - fclose($this->pipes[0]); |
|
163 | - unset($this->pipes[0]); |
|
164 | - } elseif (!$w) { |
|
165 | - return [$this->pipes[0]]; |
|
162 | + fclose( $this->pipes[ 0 ] ); |
|
163 | + unset( $this->pipes[ 0 ] ); |
|
164 | + } elseif ( ! $w ) { |
|
165 | + return [ $this->pipes[ 0 ] ]; |
|
166 | 166 | } |
167 | 167 | |
168 | 168 | return null; |
@@ -171,7 +171,7 @@ discard block |
||
171 | 171 | /** |
172 | 172 | * @internal |
173 | 173 | */ |
174 | - public function handleError(int $type, string $msg) |
|
174 | + public function handleError( int $type, string $msg ) |
|
175 | 175 | { |
176 | 176 | $this->lastError = $msg; |
177 | 177 | } |
@@ -18,8 +18,7 @@ discard block |
||
18 | 18 | * |
19 | 19 | * @internal |
20 | 20 | */ |
21 | -abstract class AbstractPipes implements PipesInterface |
|
22 | -{ |
|
21 | +abstract class AbstractPipes implements PipesInterface { |
|
23 | 22 | public $pipes = []; |
24 | 23 | |
25 | 24 | private $inputBuffer = ''; |
@@ -30,8 +29,7 @@ discard block |
||
30 | 29 | /** |
31 | 30 | * @param resource|string|int|float|bool|\Iterator|null $input |
32 | 31 | */ |
33 | - public function __construct($input) |
|
34 | - { |
|
32 | + public function __construct($input) { |
|
35 | 33 | if (\is_resource($input) || $input instanceof \Iterator) { |
36 | 34 | $this->input = $input; |
37 | 35 | } elseif (\is_string($input)) { |
@@ -44,8 +42,7 @@ discard block |
||
44 | 42 | /** |
45 | 43 | * {@inheritdoc} |
46 | 44 | */ |
47 | - public function close() |
|
48 | - { |
|
45 | + public function close() { |
|
49 | 46 | foreach ($this->pipes as $pipe) { |
50 | 47 | fclose($pipe); |
51 | 48 | } |
@@ -67,8 +64,7 @@ discard block |
||
67 | 64 | /** |
68 | 65 | * Unblocks streams. |
69 | 66 | */ |
70 | - protected function unblock() |
|
71 | - { |
|
67 | + protected function unblock() { |
|
72 | 68 | if (!$this->blocked) { |
73 | 69 | return; |
74 | 70 | } |
@@ -171,8 +167,7 @@ discard block |
||
171 | 167 | /** |
172 | 168 | * @internal |
173 | 169 | */ |
174 | - public function handleError(int $type, string $msg) |
|
175 | - { |
|
170 | + public function handleError(int $type, string $msg) { |
|
176 | 171 | $this->lastError = $msg; |
177 | 172 | } |
178 | 173 | } |
@@ -22,145 +22,145 @@ |
||
22 | 22 | */ |
23 | 23 | class UnixPipes extends AbstractPipes |
24 | 24 | { |
25 | - private $ttyMode; |
|
26 | - private $ptyMode; |
|
27 | - private $haveReadSupport; |
|
28 | - |
|
29 | - public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport) |
|
30 | - { |
|
31 | - $this->ttyMode = $ttyMode; |
|
32 | - $this->ptyMode = $ptyMode; |
|
33 | - $this->haveReadSupport = $haveReadSupport; |
|
34 | - |
|
35 | - parent::__construct($input); |
|
36 | - } |
|
37 | - |
|
38 | - /** |
|
39 | - * @return array |
|
40 | - */ |
|
41 | - public function __sleep() |
|
42 | - { |
|
43 | - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
|
44 | - } |
|
45 | - |
|
46 | - public function __wakeup() |
|
47 | - { |
|
48 | - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
|
49 | - } |
|
50 | - |
|
51 | - public function __destruct() |
|
52 | - { |
|
53 | - $this->close(); |
|
54 | - } |
|
55 | - |
|
56 | - /** |
|
57 | - * {@inheritdoc} |
|
58 | - */ |
|
59 | - public function getDescriptors(): array |
|
60 | - { |
|
61 | - if (!$this->haveReadSupport) { |
|
62 | - $nullstream = fopen('/dev/null', 'c'); |
|
63 | - |
|
64 | - return [ |
|
65 | - ['pipe', 'r'], |
|
66 | - $nullstream, |
|
67 | - $nullstream, |
|
68 | - ]; |
|
69 | - } |
|
70 | - |
|
71 | - if ($this->ttyMode) { |
|
72 | - return [ |
|
73 | - ['file', '/dev/tty', 'r'], |
|
74 | - ['file', '/dev/tty', 'w'], |
|
75 | - ['file', '/dev/tty', 'w'], |
|
76 | - ]; |
|
77 | - } |
|
78 | - |
|
79 | - if ($this->ptyMode && Process::isPtySupported()) { |
|
80 | - return [ |
|
81 | - ['pty'], |
|
82 | - ['pty'], |
|
83 | - ['pty'], |
|
84 | - ]; |
|
85 | - } |
|
86 | - |
|
87 | - return [ |
|
88 | - ['pipe', 'r'], |
|
89 | - ['pipe', 'w'], // stdout |
|
90 | - ['pipe', 'w'], // stderr |
|
91 | - ]; |
|
92 | - } |
|
93 | - |
|
94 | - /** |
|
95 | - * {@inheritdoc} |
|
96 | - */ |
|
97 | - public function getFiles(): array |
|
98 | - { |
|
99 | - return []; |
|
100 | - } |
|
101 | - |
|
102 | - /** |
|
103 | - * {@inheritdoc} |
|
104 | - */ |
|
105 | - public function readAndWrite(bool $blocking, bool $close = false): array |
|
106 | - { |
|
107 | - $this->unblock(); |
|
108 | - $w = $this->write(); |
|
109 | - |
|
110 | - $read = $e = []; |
|
111 | - $r = $this->pipes; |
|
112 | - unset($r[0]); |
|
113 | - |
|
114 | - // let's have a look if something changed in streams |
|
115 | - set_error_handler([$this, 'handleError']); |
|
116 | - if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { |
|
117 | - restore_error_handler(); |
|
118 | - // if a system call has been interrupted, forget about it, let's try again |
|
119 | - // otherwise, an error occurred, let's reset pipes |
|
120 | - if (!$this->hasSystemCallBeenInterrupted()) { |
|
121 | - $this->pipes = []; |
|
122 | - } |
|
123 | - |
|
124 | - return $read; |
|
125 | - } |
|
126 | - restore_error_handler(); |
|
127 | - |
|
128 | - foreach ($r as $pipe) { |
|
129 | - // prior PHP 5.4 the array passed to stream_select is modified and |
|
130 | - // lose key association, we have to find back the key |
|
131 | - $read[$type = array_search($pipe, $this->pipes, true)] = ''; |
|
132 | - |
|
133 | - do { |
|
134 | - $data = @fread($pipe, self::CHUNK_SIZE); |
|
135 | - $read[$type] .= $data; |
|
136 | - } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); |
|
137 | - |
|
138 | - if (!isset($read[$type][0])) { |
|
139 | - unset($read[$type]); |
|
140 | - } |
|
141 | - |
|
142 | - if ($close && feof($pipe)) { |
|
143 | - fclose($pipe); |
|
144 | - unset($this->pipes[$type]); |
|
145 | - } |
|
146 | - } |
|
147 | - |
|
148 | - return $read; |
|
149 | - } |
|
150 | - |
|
151 | - /** |
|
152 | - * {@inheritdoc} |
|
153 | - */ |
|
154 | - public function haveReadSupport(): bool |
|
155 | - { |
|
156 | - return $this->haveReadSupport; |
|
157 | - } |
|
158 | - |
|
159 | - /** |
|
160 | - * {@inheritdoc} |
|
161 | - */ |
|
162 | - public function areOpen(): bool |
|
163 | - { |
|
164 | - return (bool) $this->pipes; |
|
165 | - } |
|
25 | + private $ttyMode; |
|
26 | + private $ptyMode; |
|
27 | + private $haveReadSupport; |
|
28 | + |
|
29 | + public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport) |
|
30 | + { |
|
31 | + $this->ttyMode = $ttyMode; |
|
32 | + $this->ptyMode = $ptyMode; |
|
33 | + $this->haveReadSupport = $haveReadSupport; |
|
34 | + |
|
35 | + parent::__construct($input); |
|
36 | + } |
|
37 | + |
|
38 | + /** |
|
39 | + * @return array |
|
40 | + */ |
|
41 | + public function __sleep() |
|
42 | + { |
|
43 | + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
|
44 | + } |
|
45 | + |
|
46 | + public function __wakeup() |
|
47 | + { |
|
48 | + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
|
49 | + } |
|
50 | + |
|
51 | + public function __destruct() |
|
52 | + { |
|
53 | + $this->close(); |
|
54 | + } |
|
55 | + |
|
56 | + /** |
|
57 | + * {@inheritdoc} |
|
58 | + */ |
|
59 | + public function getDescriptors(): array |
|
60 | + { |
|
61 | + if (!$this->haveReadSupport) { |
|
62 | + $nullstream = fopen('/dev/null', 'c'); |
|
63 | + |
|
64 | + return [ |
|
65 | + ['pipe', 'r'], |
|
66 | + $nullstream, |
|
67 | + $nullstream, |
|
68 | + ]; |
|
69 | + } |
|
70 | + |
|
71 | + if ($this->ttyMode) { |
|
72 | + return [ |
|
73 | + ['file', '/dev/tty', 'r'], |
|
74 | + ['file', '/dev/tty', 'w'], |
|
75 | + ['file', '/dev/tty', 'w'], |
|
76 | + ]; |
|
77 | + } |
|
78 | + |
|
79 | + if ($this->ptyMode && Process::isPtySupported()) { |
|
80 | + return [ |
|
81 | + ['pty'], |
|
82 | + ['pty'], |
|
83 | + ['pty'], |
|
84 | + ]; |
|
85 | + } |
|
86 | + |
|
87 | + return [ |
|
88 | + ['pipe', 'r'], |
|
89 | + ['pipe', 'w'], // stdout |
|
90 | + ['pipe', 'w'], // stderr |
|
91 | + ]; |
|
92 | + } |
|
93 | + |
|
94 | + /** |
|
95 | + * {@inheritdoc} |
|
96 | + */ |
|
97 | + public function getFiles(): array |
|
98 | + { |
|
99 | + return []; |
|
100 | + } |
|
101 | + |
|
102 | + /** |
|
103 | + * {@inheritdoc} |
|
104 | + */ |
|
105 | + public function readAndWrite(bool $blocking, bool $close = false): array |
|
106 | + { |
|
107 | + $this->unblock(); |
|
108 | + $w = $this->write(); |
|
109 | + |
|
110 | + $read = $e = []; |
|
111 | + $r = $this->pipes; |
|
112 | + unset($r[0]); |
|
113 | + |
|
114 | + // let's have a look if something changed in streams |
|
115 | + set_error_handler([$this, 'handleError']); |
|
116 | + if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { |
|
117 | + restore_error_handler(); |
|
118 | + // if a system call has been interrupted, forget about it, let's try again |
|
119 | + // otherwise, an error occurred, let's reset pipes |
|
120 | + if (!$this->hasSystemCallBeenInterrupted()) { |
|
121 | + $this->pipes = []; |
|
122 | + } |
|
123 | + |
|
124 | + return $read; |
|
125 | + } |
|
126 | + restore_error_handler(); |
|
127 | + |
|
128 | + foreach ($r as $pipe) { |
|
129 | + // prior PHP 5.4 the array passed to stream_select is modified and |
|
130 | + // lose key association, we have to find back the key |
|
131 | + $read[$type = array_search($pipe, $this->pipes, true)] = ''; |
|
132 | + |
|
133 | + do { |
|
134 | + $data = @fread($pipe, self::CHUNK_SIZE); |
|
135 | + $read[$type] .= $data; |
|
136 | + } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); |
|
137 | + |
|
138 | + if (!isset($read[$type][0])) { |
|
139 | + unset($read[$type]); |
|
140 | + } |
|
141 | + |
|
142 | + if ($close && feof($pipe)) { |
|
143 | + fclose($pipe); |
|
144 | + unset($this->pipes[$type]); |
|
145 | + } |
|
146 | + } |
|
147 | + |
|
148 | + return $read; |
|
149 | + } |
|
150 | + |
|
151 | + /** |
|
152 | + * {@inheritdoc} |
|
153 | + */ |
|
154 | + public function haveReadSupport(): bool |
|
155 | + { |
|
156 | + return $this->haveReadSupport; |
|
157 | + } |
|
158 | + |
|
159 | + /** |
|
160 | + * {@inheritdoc} |
|
161 | + */ |
|
162 | + public function areOpen(): bool |
|
163 | + { |
|
164 | + return (bool) $this->pipes; |
|
165 | + } |
|
166 | 166 | } |
@@ -26,13 +26,13 @@ discard block |
||
26 | 26 | private $ptyMode; |
27 | 27 | private $haveReadSupport; |
28 | 28 | |
29 | - public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport) |
|
29 | + public function __construct( ?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport ) |
|
30 | 30 | { |
31 | 31 | $this->ttyMode = $ttyMode; |
32 | 32 | $this->ptyMode = $ptyMode; |
33 | 33 | $this->haveReadSupport = $haveReadSupport; |
34 | 34 | |
35 | - parent::__construct($input); |
|
35 | + parent::__construct( $input ); |
|
36 | 36 | } |
37 | 37 | |
38 | 38 | /** |
@@ -40,12 +40,12 @@ discard block |
||
40 | 40 | */ |
41 | 41 | public function __sleep() |
42 | 42 | { |
43 | - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
|
43 | + throw new \BadMethodCallException( 'Cannot serialize ' . __CLASS__ ); |
|
44 | 44 | } |
45 | 45 | |
46 | 46 | public function __wakeup() |
47 | 47 | { |
48 | - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
|
48 | + throw new \BadMethodCallException( 'Cannot unserialize ' . __CLASS__ ); |
|
49 | 49 | } |
50 | 50 | |
51 | 51 | public function __destruct() |
@@ -58,36 +58,36 @@ discard block |
||
58 | 58 | */ |
59 | 59 | public function getDescriptors(): array |
60 | 60 | { |
61 | - if (!$this->haveReadSupport) { |
|
62 | - $nullstream = fopen('/dev/null', 'c'); |
|
61 | + if ( ! $this->haveReadSupport ) { |
|
62 | + $nullstream = fopen( '/dev/null', 'c' ); |
|
63 | 63 | |
64 | 64 | return [ |
65 | - ['pipe', 'r'], |
|
65 | + [ 'pipe', 'r' ], |
|
66 | 66 | $nullstream, |
67 | 67 | $nullstream, |
68 | 68 | ]; |
69 | 69 | } |
70 | 70 | |
71 | - if ($this->ttyMode) { |
|
71 | + if ( $this->ttyMode ) { |
|
72 | 72 | return [ |
73 | - ['file', '/dev/tty', 'r'], |
|
74 | - ['file', '/dev/tty', 'w'], |
|
75 | - ['file', '/dev/tty', 'w'], |
|
73 | + [ 'file', '/dev/tty', 'r' ], |
|
74 | + [ 'file', '/dev/tty', 'w' ], |
|
75 | + [ 'file', '/dev/tty', 'w' ], |
|
76 | 76 | ]; |
77 | 77 | } |
78 | 78 | |
79 | - if ($this->ptyMode && Process::isPtySupported()) { |
|
79 | + if ( $this->ptyMode && Process::isPtySupported() ) { |
|
80 | 80 | return [ |
81 | - ['pty'], |
|
82 | - ['pty'], |
|
83 | - ['pty'], |
|
81 | + [ 'pty' ], |
|
82 | + [ 'pty' ], |
|
83 | + [ 'pty' ], |
|
84 | 84 | ]; |
85 | 85 | } |
86 | 86 | |
87 | 87 | return [ |
88 | - ['pipe', 'r'], |
|
89 | - ['pipe', 'w'], // stdout |
|
90 | - ['pipe', 'w'], // stderr |
|
88 | + [ 'pipe', 'r' ], |
|
89 | + [ 'pipe', 'w' ], // stdout |
|
90 | + [ 'pipe', 'w' ], // stderr |
|
91 | 91 | ]; |
92 | 92 | } |
93 | 93 | |
@@ -96,52 +96,52 @@ discard block |
||
96 | 96 | */ |
97 | 97 | public function getFiles(): array |
98 | 98 | { |
99 | - return []; |
|
99 | + return [ ]; |
|
100 | 100 | } |
101 | 101 | |
102 | 102 | /** |
103 | 103 | * {@inheritdoc} |
104 | 104 | */ |
105 | - public function readAndWrite(bool $blocking, bool $close = false): array |
|
105 | + public function readAndWrite( bool $blocking, bool $close = false ): array |
|
106 | 106 | { |
107 | 107 | $this->unblock(); |
108 | 108 | $w = $this->write(); |
109 | 109 | |
110 | - $read = $e = []; |
|
110 | + $read = $e = [ ]; |
|
111 | 111 | $r = $this->pipes; |
112 | - unset($r[0]); |
|
112 | + unset( $r[ 0 ] ); |
|
113 | 113 | |
114 | 114 | // let's have a look if something changed in streams |
115 | - set_error_handler([$this, 'handleError']); |
|
116 | - if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { |
|
115 | + set_error_handler( [ $this, 'handleError' ] ); |
|
116 | + if ( ( $r || $w ) && false === stream_select( $r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0 ) ) { |
|
117 | 117 | restore_error_handler(); |
118 | 118 | // if a system call has been interrupted, forget about it, let's try again |
119 | 119 | // otherwise, an error occurred, let's reset pipes |
120 | - if (!$this->hasSystemCallBeenInterrupted()) { |
|
121 | - $this->pipes = []; |
|
120 | + if ( ! $this->hasSystemCallBeenInterrupted() ) { |
|
121 | + $this->pipes = [ ]; |
|
122 | 122 | } |
123 | 123 | |
124 | 124 | return $read; |
125 | 125 | } |
126 | 126 | restore_error_handler(); |
127 | 127 | |
128 | - foreach ($r as $pipe) { |
|
128 | + foreach ( $r as $pipe ) { |
|
129 | 129 | // prior PHP 5.4 the array passed to stream_select is modified and |
130 | 130 | // lose key association, we have to find back the key |
131 | - $read[$type = array_search($pipe, $this->pipes, true)] = ''; |
|
131 | + $read[ $type = array_search( $pipe, $this->pipes, true ) ] = ''; |
|
132 | 132 | |
133 | 133 | do { |
134 | - $data = @fread($pipe, self::CHUNK_SIZE); |
|
135 | - $read[$type] .= $data; |
|
136 | - } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); |
|
134 | + $data = @fread( $pipe, self::CHUNK_SIZE ); |
|
135 | + $read[ $type ] .= $data; |
|
136 | + } while ( isset( $data[ 0 ] ) && ( $close || isset( $data[ self::CHUNK_SIZE - 1 ] ) ) ); |
|
137 | 137 | |
138 | - if (!isset($read[$type][0])) { |
|
139 | - unset($read[$type]); |
|
138 | + if ( ! isset( $read[ $type ][ 0 ] ) ) { |
|
139 | + unset( $read[ $type ] ); |
|
140 | 140 | } |
141 | 141 | |
142 | - if ($close && feof($pipe)) { |
|
143 | - fclose($pipe); |
|
144 | - unset($this->pipes[$type]); |
|
142 | + if ( $close && feof( $pipe ) ) { |
|
143 | + fclose( $pipe ); |
|
144 | + unset( $this->pipes[ $type ] ); |
|
145 | 145 | } |
146 | 146 | } |
147 | 147 | |
@@ -161,6 +161,6 @@ discard block |
||
161 | 161 | */ |
162 | 162 | public function areOpen(): bool |
163 | 163 | { |
164 | - return (bool) $this->pipes; |
|
164 | + return (bool)$this->pipes; |
|
165 | 165 | } |
166 | 166 | } |
@@ -20,14 +20,12 @@ discard block |
||
20 | 20 | * |
21 | 21 | * @internal |
22 | 22 | */ |
23 | -class UnixPipes extends AbstractPipes |
|
24 | -{ |
|
23 | +class UnixPipes extends AbstractPipes { |
|
25 | 24 | private $ttyMode; |
26 | 25 | private $ptyMode; |
27 | 26 | private $haveReadSupport; |
28 | 27 | |
29 | - public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport) |
|
30 | - { |
|
28 | + public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport) { |
|
31 | 29 | $this->ttyMode = $ttyMode; |
32 | 30 | $this->ptyMode = $ptyMode; |
33 | 31 | $this->haveReadSupport = $haveReadSupport; |
@@ -38,18 +36,15 @@ discard block |
||
38 | 36 | /** |
39 | 37 | * @return array |
40 | 38 | */ |
41 | - public function __sleep() |
|
42 | - { |
|
39 | + public function __sleep() { |
|
43 | 40 | throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
44 | 41 | } |
45 | 42 | |
46 | - public function __wakeup() |
|
47 | - { |
|
43 | + public function __wakeup() { |
|
48 | 44 | throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
49 | 45 | } |
50 | 46 | |
51 | - public function __destruct() |
|
52 | - { |
|
47 | + public function __destruct() { |
|
53 | 48 | $this->close(); |
54 | 49 | } |
55 | 50 |
@@ -26,182 +26,182 @@ |
||
26 | 26 | */ |
27 | 27 | class WindowsPipes extends AbstractPipes |
28 | 28 | { |
29 | - private $files = []; |
|
30 | - private $fileHandles = []; |
|
31 | - private $lockHandles = []; |
|
32 | - private $readBytes = [ |
|
33 | - Process::STDOUT => 0, |
|
34 | - Process::STDERR => 0, |
|
35 | - ]; |
|
36 | - private $haveReadSupport; |
|
37 | - |
|
38 | - public function __construct($input, bool $haveReadSupport) |
|
39 | - { |
|
40 | - $this->haveReadSupport = $haveReadSupport; |
|
41 | - |
|
42 | - if ($this->haveReadSupport) { |
|
43 | - // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. |
|
44 | - // Workaround for this problem is to use temporary files instead of pipes on Windows platform. |
|
45 | - // |
|
46 | - // @see https://bugs.php.net/51800 |
|
47 | - $pipes = [ |
|
48 | - Process::STDOUT => Process::OUT, |
|
49 | - Process::STDERR => Process::ERR, |
|
50 | - ]; |
|
51 | - $tmpDir = sys_get_temp_dir(); |
|
52 | - $lastError = 'unknown reason'; |
|
53 | - set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); |
|
54 | - for ($i = 0;; ++$i) { |
|
55 | - foreach ($pipes as $pipe => $name) { |
|
56 | - $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); |
|
57 | - |
|
58 | - if (!$h = fopen($file.'.lock', 'w')) { |
|
59 | - if (file_exists($file.'.lock')) { |
|
60 | - continue 2; |
|
61 | - } |
|
62 | - restore_error_handler(); |
|
63 | - throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError); |
|
64 | - } |
|
65 | - if (!flock($h, \LOCK_EX | \LOCK_NB)) { |
|
66 | - continue 2; |
|
67 | - } |
|
68 | - if (isset($this->lockHandles[$pipe])) { |
|
69 | - flock($this->lockHandles[$pipe], \LOCK_UN); |
|
70 | - fclose($this->lockHandles[$pipe]); |
|
71 | - } |
|
72 | - $this->lockHandles[$pipe] = $h; |
|
73 | - |
|
74 | - if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) { |
|
75 | - flock($this->lockHandles[$pipe], \LOCK_UN); |
|
76 | - fclose($this->lockHandles[$pipe]); |
|
77 | - unset($this->lockHandles[$pipe]); |
|
78 | - continue 2; |
|
79 | - } |
|
80 | - $this->fileHandles[$pipe] = $h; |
|
81 | - $this->files[$pipe] = $file; |
|
82 | - } |
|
83 | - break; |
|
84 | - } |
|
85 | - restore_error_handler(); |
|
86 | - } |
|
87 | - |
|
88 | - parent::__construct($input); |
|
89 | - } |
|
90 | - |
|
91 | - /** |
|
92 | - * @return array |
|
93 | - */ |
|
94 | - public function __sleep() |
|
95 | - { |
|
96 | - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
|
97 | - } |
|
98 | - |
|
99 | - public function __wakeup() |
|
100 | - { |
|
101 | - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
|
102 | - } |
|
103 | - |
|
104 | - public function __destruct() |
|
105 | - { |
|
106 | - $this->close(); |
|
107 | - } |
|
108 | - |
|
109 | - /** |
|
110 | - * {@inheritdoc} |
|
111 | - */ |
|
112 | - public function getDescriptors(): array |
|
113 | - { |
|
114 | - if (!$this->haveReadSupport) { |
|
115 | - $nullstream = fopen('NUL', 'c'); |
|
116 | - |
|
117 | - return [ |
|
118 | - ['pipe', 'r'], |
|
119 | - $nullstream, |
|
120 | - $nullstream, |
|
121 | - ]; |
|
122 | - } |
|
123 | - |
|
124 | - // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800) |
|
125 | - // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650 |
|
126 | - // So we redirect output within the commandline and pass the nul device to the process |
|
127 | - return [ |
|
128 | - ['pipe', 'r'], |
|
129 | - ['file', 'NUL', 'w'], |
|
130 | - ['file', 'NUL', 'w'], |
|
131 | - ]; |
|
132 | - } |
|
133 | - |
|
134 | - /** |
|
135 | - * {@inheritdoc} |
|
136 | - */ |
|
137 | - public function getFiles(): array |
|
138 | - { |
|
139 | - return $this->files; |
|
140 | - } |
|
141 | - |
|
142 | - /** |
|
143 | - * {@inheritdoc} |
|
144 | - */ |
|
145 | - public function readAndWrite(bool $blocking, bool $close = false): array |
|
146 | - { |
|
147 | - $this->unblock(); |
|
148 | - $w = $this->write(); |
|
149 | - $read = $r = $e = []; |
|
150 | - |
|
151 | - if ($blocking) { |
|
152 | - if ($w) { |
|
153 | - @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); |
|
154 | - } elseif ($this->fileHandles) { |
|
155 | - usleep(Process::TIMEOUT_PRECISION * 1E6); |
|
156 | - } |
|
157 | - } |
|
158 | - foreach ($this->fileHandles as $type => $fileHandle) { |
|
159 | - $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]); |
|
160 | - |
|
161 | - if (isset($data[0])) { |
|
162 | - $this->readBytes[$type] += \strlen($data); |
|
163 | - $read[$type] = $data; |
|
164 | - } |
|
165 | - if ($close) { |
|
166 | - ftruncate($fileHandle, 0); |
|
167 | - fclose($fileHandle); |
|
168 | - flock($this->lockHandles[$type], \LOCK_UN); |
|
169 | - fclose($this->lockHandles[$type]); |
|
170 | - unset($this->fileHandles[$type], $this->lockHandles[$type]); |
|
171 | - } |
|
172 | - } |
|
173 | - |
|
174 | - return $read; |
|
175 | - } |
|
176 | - |
|
177 | - /** |
|
178 | - * {@inheritdoc} |
|
179 | - */ |
|
180 | - public function haveReadSupport(): bool |
|
181 | - { |
|
182 | - return $this->haveReadSupport; |
|
183 | - } |
|
184 | - |
|
185 | - /** |
|
186 | - * {@inheritdoc} |
|
187 | - */ |
|
188 | - public function areOpen(): bool |
|
189 | - { |
|
190 | - return $this->pipes && $this->fileHandles; |
|
191 | - } |
|
192 | - |
|
193 | - /** |
|
194 | - * {@inheritdoc} |
|
195 | - */ |
|
196 | - public function close() |
|
197 | - { |
|
198 | - parent::close(); |
|
199 | - foreach ($this->fileHandles as $type => $handle) { |
|
200 | - ftruncate($handle, 0); |
|
201 | - fclose($handle); |
|
202 | - flock($this->lockHandles[$type], \LOCK_UN); |
|
203 | - fclose($this->lockHandles[$type]); |
|
204 | - } |
|
205 | - $this->fileHandles = $this->lockHandles = []; |
|
206 | - } |
|
29 | + private $files = []; |
|
30 | + private $fileHandles = []; |
|
31 | + private $lockHandles = []; |
|
32 | + private $readBytes = [ |
|
33 | + Process::STDOUT => 0, |
|
34 | + Process::STDERR => 0, |
|
35 | + ]; |
|
36 | + private $haveReadSupport; |
|
37 | + |
|
38 | + public function __construct($input, bool $haveReadSupport) |
|
39 | + { |
|
40 | + $this->haveReadSupport = $haveReadSupport; |
|
41 | + |
|
42 | + if ($this->haveReadSupport) { |
|
43 | + // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. |
|
44 | + // Workaround for this problem is to use temporary files instead of pipes on Windows platform. |
|
45 | + // |
|
46 | + // @see https://bugs.php.net/51800 |
|
47 | + $pipes = [ |
|
48 | + Process::STDOUT => Process::OUT, |
|
49 | + Process::STDERR => Process::ERR, |
|
50 | + ]; |
|
51 | + $tmpDir = sys_get_temp_dir(); |
|
52 | + $lastError = 'unknown reason'; |
|
53 | + set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); |
|
54 | + for ($i = 0;; ++$i) { |
|
55 | + foreach ($pipes as $pipe => $name) { |
|
56 | + $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); |
|
57 | + |
|
58 | + if (!$h = fopen($file.'.lock', 'w')) { |
|
59 | + if (file_exists($file.'.lock')) { |
|
60 | + continue 2; |
|
61 | + } |
|
62 | + restore_error_handler(); |
|
63 | + throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError); |
|
64 | + } |
|
65 | + if (!flock($h, \LOCK_EX | \LOCK_NB)) { |
|
66 | + continue 2; |
|
67 | + } |
|
68 | + if (isset($this->lockHandles[$pipe])) { |
|
69 | + flock($this->lockHandles[$pipe], \LOCK_UN); |
|
70 | + fclose($this->lockHandles[$pipe]); |
|
71 | + } |
|
72 | + $this->lockHandles[$pipe] = $h; |
|
73 | + |
|
74 | + if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) { |
|
75 | + flock($this->lockHandles[$pipe], \LOCK_UN); |
|
76 | + fclose($this->lockHandles[$pipe]); |
|
77 | + unset($this->lockHandles[$pipe]); |
|
78 | + continue 2; |
|
79 | + } |
|
80 | + $this->fileHandles[$pipe] = $h; |
|
81 | + $this->files[$pipe] = $file; |
|
82 | + } |
|
83 | + break; |
|
84 | + } |
|
85 | + restore_error_handler(); |
|
86 | + } |
|
87 | + |
|
88 | + parent::__construct($input); |
|
89 | + } |
|
90 | + |
|
91 | + /** |
|
92 | + * @return array |
|
93 | + */ |
|
94 | + public function __sleep() |
|
95 | + { |
|
96 | + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
|
97 | + } |
|
98 | + |
|
99 | + public function __wakeup() |
|
100 | + { |
|
101 | + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
|
102 | + } |
|
103 | + |
|
104 | + public function __destruct() |
|
105 | + { |
|
106 | + $this->close(); |
|
107 | + } |
|
108 | + |
|
109 | + /** |
|
110 | + * {@inheritdoc} |
|
111 | + */ |
|
112 | + public function getDescriptors(): array |
|
113 | + { |
|
114 | + if (!$this->haveReadSupport) { |
|
115 | + $nullstream = fopen('NUL', 'c'); |
|
116 | + |
|
117 | + return [ |
|
118 | + ['pipe', 'r'], |
|
119 | + $nullstream, |
|
120 | + $nullstream, |
|
121 | + ]; |
|
122 | + } |
|
123 | + |
|
124 | + // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800) |
|
125 | + // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650 |
|
126 | + // So we redirect output within the commandline and pass the nul device to the process |
|
127 | + return [ |
|
128 | + ['pipe', 'r'], |
|
129 | + ['file', 'NUL', 'w'], |
|
130 | + ['file', 'NUL', 'w'], |
|
131 | + ]; |
|
132 | + } |
|
133 | + |
|
134 | + /** |
|
135 | + * {@inheritdoc} |
|
136 | + */ |
|
137 | + public function getFiles(): array |
|
138 | + { |
|
139 | + return $this->files; |
|
140 | + } |
|
141 | + |
|
142 | + /** |
|
143 | + * {@inheritdoc} |
|
144 | + */ |
|
145 | + public function readAndWrite(bool $blocking, bool $close = false): array |
|
146 | + { |
|
147 | + $this->unblock(); |
|
148 | + $w = $this->write(); |
|
149 | + $read = $r = $e = []; |
|
150 | + |
|
151 | + if ($blocking) { |
|
152 | + if ($w) { |
|
153 | + @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); |
|
154 | + } elseif ($this->fileHandles) { |
|
155 | + usleep(Process::TIMEOUT_PRECISION * 1E6); |
|
156 | + } |
|
157 | + } |
|
158 | + foreach ($this->fileHandles as $type => $fileHandle) { |
|
159 | + $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]); |
|
160 | + |
|
161 | + if (isset($data[0])) { |
|
162 | + $this->readBytes[$type] += \strlen($data); |
|
163 | + $read[$type] = $data; |
|
164 | + } |
|
165 | + if ($close) { |
|
166 | + ftruncate($fileHandle, 0); |
|
167 | + fclose($fileHandle); |
|
168 | + flock($this->lockHandles[$type], \LOCK_UN); |
|
169 | + fclose($this->lockHandles[$type]); |
|
170 | + unset($this->fileHandles[$type], $this->lockHandles[$type]); |
|
171 | + } |
|
172 | + } |
|
173 | + |
|
174 | + return $read; |
|
175 | + } |
|
176 | + |
|
177 | + /** |
|
178 | + * {@inheritdoc} |
|
179 | + */ |
|
180 | + public function haveReadSupport(): bool |
|
181 | + { |
|
182 | + return $this->haveReadSupport; |
|
183 | + } |
|
184 | + |
|
185 | + /** |
|
186 | + * {@inheritdoc} |
|
187 | + */ |
|
188 | + public function areOpen(): bool |
|
189 | + { |
|
190 | + return $this->pipes && $this->fileHandles; |
|
191 | + } |
|
192 | + |
|
193 | + /** |
|
194 | + * {@inheritdoc} |
|
195 | + */ |
|
196 | + public function close() |
|
197 | + { |
|
198 | + parent::close(); |
|
199 | + foreach ($this->fileHandles as $type => $handle) { |
|
200 | + ftruncate($handle, 0); |
|
201 | + fclose($handle); |
|
202 | + flock($this->lockHandles[$type], \LOCK_UN); |
|
203 | + fclose($this->lockHandles[$type]); |
|
204 | + } |
|
205 | + $this->fileHandles = $this->lockHandles = []; |
|
206 | + } |
|
207 | 207 | } |
@@ -26,20 +26,20 @@ discard block |
||
26 | 26 | */ |
27 | 27 | class WindowsPipes extends AbstractPipes |
28 | 28 | { |
29 | - private $files = []; |
|
30 | - private $fileHandles = []; |
|
31 | - private $lockHandles = []; |
|
29 | + private $files = [ ]; |
|
30 | + private $fileHandles = [ ]; |
|
31 | + private $lockHandles = [ ]; |
|
32 | 32 | private $readBytes = [ |
33 | 33 | Process::STDOUT => 0, |
34 | 34 | Process::STDERR => 0, |
35 | 35 | ]; |
36 | 36 | private $haveReadSupport; |
37 | 37 | |
38 | - public function __construct($input, bool $haveReadSupport) |
|
38 | + public function __construct( $input, bool $haveReadSupport ) |
|
39 | 39 | { |
40 | 40 | $this->haveReadSupport = $haveReadSupport; |
41 | 41 | |
42 | - if ($this->haveReadSupport) { |
|
42 | + if ( $this->haveReadSupport ) { |
|
43 | 43 | // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. |
44 | 44 | // Workaround for this problem is to use temporary files instead of pipes on Windows platform. |
45 | 45 | // |
@@ -50,42 +50,42 @@ discard block |
||
50 | 50 | ]; |
51 | 51 | $tmpDir = sys_get_temp_dir(); |
52 | 52 | $lastError = 'unknown reason'; |
53 | - set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); |
|
54 | - for ($i = 0;; ++$i) { |
|
55 | - foreach ($pipes as $pipe => $name) { |
|
56 | - $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); |
|
53 | + set_error_handler( function( $type, $msg ) use ( &$lastError ) { $lastError = $msg; }); |
|
54 | + for ( $i = 0; ; ++$i ) { |
|
55 | + foreach ( $pipes as $pipe => $name ) { |
|
56 | + $file = sprintf( '%s\\sf_proc_%02X.%s', $tmpDir, $i, $name ); |
|
57 | 57 | |
58 | - if (!$h = fopen($file.'.lock', 'w')) { |
|
59 | - if (file_exists($file.'.lock')) { |
|
58 | + if ( ! $h = fopen( $file . '.lock', 'w' ) ) { |
|
59 | + if ( file_exists( $file . '.lock' ) ) { |
|
60 | 60 | continue 2; |
61 | 61 | } |
62 | 62 | restore_error_handler(); |
63 | - throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError); |
|
63 | + throw new RuntimeException( 'A temporary file could not be opened to write the process output: ' . $lastError ); |
|
64 | 64 | } |
65 | - if (!flock($h, \LOCK_EX | \LOCK_NB)) { |
|
65 | + if ( ! flock( $h, \LOCK_EX | \LOCK_NB ) ) { |
|
66 | 66 | continue 2; |
67 | 67 | } |
68 | - if (isset($this->lockHandles[$pipe])) { |
|
69 | - flock($this->lockHandles[$pipe], \LOCK_UN); |
|
70 | - fclose($this->lockHandles[$pipe]); |
|
68 | + if ( isset( $this->lockHandles[ $pipe ] ) ) { |
|
69 | + flock( $this->lockHandles[ $pipe ], \LOCK_UN ); |
|
70 | + fclose( $this->lockHandles[ $pipe ] ); |
|
71 | 71 | } |
72 | - $this->lockHandles[$pipe] = $h; |
|
72 | + $this->lockHandles[ $pipe ] = $h; |
|
73 | 73 | |
74 | - if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) { |
|
75 | - flock($this->lockHandles[$pipe], \LOCK_UN); |
|
76 | - fclose($this->lockHandles[$pipe]); |
|
77 | - unset($this->lockHandles[$pipe]); |
|
74 | + if ( ! ( $h = fopen( $file, 'w' ) ) || ! fclose( $h ) || ! $h = fopen( $file, 'r' ) ) { |
|
75 | + flock( $this->lockHandles[ $pipe ], \LOCK_UN ); |
|
76 | + fclose( $this->lockHandles[ $pipe ] ); |
|
77 | + unset( $this->lockHandles[ $pipe ] ); |
|
78 | 78 | continue 2; |
79 | 79 | } |
80 | - $this->fileHandles[$pipe] = $h; |
|
81 | - $this->files[$pipe] = $file; |
|
80 | + $this->fileHandles[ $pipe ] = $h; |
|
81 | + $this->files[ $pipe ] = $file; |
|
82 | 82 | } |
83 | 83 | break; |
84 | 84 | } |
85 | 85 | restore_error_handler(); |
86 | 86 | } |
87 | 87 | |
88 | - parent::__construct($input); |
|
88 | + parent::__construct( $input ); |
|
89 | 89 | } |
90 | 90 | |
91 | 91 | /** |
@@ -93,12 +93,12 @@ discard block |
||
93 | 93 | */ |
94 | 94 | public function __sleep() |
95 | 95 | { |
96 | - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
|
96 | + throw new \BadMethodCallException( 'Cannot serialize ' . __CLASS__ ); |
|
97 | 97 | } |
98 | 98 | |
99 | 99 | public function __wakeup() |
100 | 100 | { |
101 | - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
|
101 | + throw new \BadMethodCallException( 'Cannot unserialize ' . __CLASS__ ); |
|
102 | 102 | } |
103 | 103 | |
104 | 104 | public function __destruct() |
@@ -111,11 +111,11 @@ discard block |
||
111 | 111 | */ |
112 | 112 | public function getDescriptors(): array |
113 | 113 | { |
114 | - if (!$this->haveReadSupport) { |
|
115 | - $nullstream = fopen('NUL', 'c'); |
|
114 | + if ( ! $this->haveReadSupport ) { |
|
115 | + $nullstream = fopen( 'NUL', 'c' ); |
|
116 | 116 | |
117 | 117 | return [ |
118 | - ['pipe', 'r'], |
|
118 | + [ 'pipe', 'r' ], |
|
119 | 119 | $nullstream, |
120 | 120 | $nullstream, |
121 | 121 | ]; |
@@ -125,9 +125,9 @@ discard block |
||
125 | 125 | // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650 |
126 | 126 | // So we redirect output within the commandline and pass the nul device to the process |
127 | 127 | return [ |
128 | - ['pipe', 'r'], |
|
129 | - ['file', 'NUL', 'w'], |
|
130 | - ['file', 'NUL', 'w'], |
|
128 | + [ 'pipe', 'r' ], |
|
129 | + [ 'file', 'NUL', 'w' ], |
|
130 | + [ 'file', 'NUL', 'w' ], |
|
131 | 131 | ]; |
132 | 132 | } |
133 | 133 | |
@@ -142,32 +142,32 @@ discard block |
||
142 | 142 | /** |
143 | 143 | * {@inheritdoc} |
144 | 144 | */ |
145 | - public function readAndWrite(bool $blocking, bool $close = false): array |
|
145 | + public function readAndWrite( bool $blocking, bool $close = false ): array |
|
146 | 146 | { |
147 | 147 | $this->unblock(); |
148 | 148 | $w = $this->write(); |
149 | - $read = $r = $e = []; |
|
149 | + $read = $r = $e = [ ]; |
|
150 | 150 | |
151 | - if ($blocking) { |
|
152 | - if ($w) { |
|
153 | - @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); |
|
154 | - } elseif ($this->fileHandles) { |
|
155 | - usleep(Process::TIMEOUT_PRECISION * 1E6); |
|
151 | + if ( $blocking ) { |
|
152 | + if ( $w ) { |
|
153 | + @stream_select( $r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6 ); |
|
154 | + } elseif ( $this->fileHandles ) { |
|
155 | + usleep( Process::TIMEOUT_PRECISION * 1E6 ); |
|
156 | 156 | } |
157 | 157 | } |
158 | - foreach ($this->fileHandles as $type => $fileHandle) { |
|
159 | - $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]); |
|
158 | + foreach ( $this->fileHandles as $type => $fileHandle ) { |
|
159 | + $data = stream_get_contents( $fileHandle, -1, $this->readBytes[ $type ] ); |
|
160 | 160 | |
161 | - if (isset($data[0])) { |
|
162 | - $this->readBytes[$type] += \strlen($data); |
|
163 | - $read[$type] = $data; |
|
161 | + if ( isset( $data[ 0 ] ) ) { |
|
162 | + $this->readBytes[ $type ] += \strlen( $data ); |
|
163 | + $read[ $type ] = $data; |
|
164 | 164 | } |
165 | - if ($close) { |
|
166 | - ftruncate($fileHandle, 0); |
|
167 | - fclose($fileHandle); |
|
168 | - flock($this->lockHandles[$type], \LOCK_UN); |
|
169 | - fclose($this->lockHandles[$type]); |
|
170 | - unset($this->fileHandles[$type], $this->lockHandles[$type]); |
|
165 | + if ( $close ) { |
|
166 | + ftruncate( $fileHandle, 0 ); |
|
167 | + fclose( $fileHandle ); |
|
168 | + flock( $this->lockHandles[ $type ], \LOCK_UN ); |
|
169 | + fclose( $this->lockHandles[ $type ] ); |
|
170 | + unset( $this->fileHandles[ $type ], $this->lockHandles[ $type ] ); |
|
171 | 171 | } |
172 | 172 | } |
173 | 173 | |
@@ -196,12 +196,12 @@ discard block |
||
196 | 196 | public function close() |
197 | 197 | { |
198 | 198 | parent::close(); |
199 | - foreach ($this->fileHandles as $type => $handle) { |
|
200 | - ftruncate($handle, 0); |
|
201 | - fclose($handle); |
|
202 | - flock($this->lockHandles[$type], \LOCK_UN); |
|
203 | - fclose($this->lockHandles[$type]); |
|
199 | + foreach ( $this->fileHandles as $type => $handle ) { |
|
200 | + ftruncate( $handle, 0 ); |
|
201 | + fclose( $handle ); |
|
202 | + flock( $this->lockHandles[ $type ], \LOCK_UN ); |
|
203 | + fclose( $this->lockHandles[ $type ] ); |
|
204 | 204 | } |
205 | - $this->fileHandles = $this->lockHandles = []; |
|
205 | + $this->fileHandles = $this->lockHandles = [ ]; |
|
206 | 206 | } |
207 | 207 | } |
@@ -24,8 +24,7 @@ discard block |
||
24 | 24 | * |
25 | 25 | * @internal |
26 | 26 | */ |
27 | -class WindowsPipes extends AbstractPipes |
|
28 | -{ |
|
27 | +class WindowsPipes extends AbstractPipes { |
|
29 | 28 | private $files = []; |
30 | 29 | private $fileHandles = []; |
31 | 30 | private $lockHandles = []; |
@@ -35,8 +34,7 @@ discard block |
||
35 | 34 | ]; |
36 | 35 | private $haveReadSupport; |
37 | 36 | |
38 | - public function __construct($input, bool $haveReadSupport) |
|
39 | - { |
|
37 | + public function __construct($input, bool $haveReadSupport) { |
|
40 | 38 | $this->haveReadSupport = $haveReadSupport; |
41 | 39 | |
42 | 40 | if ($this->haveReadSupport) { |
@@ -91,18 +89,15 @@ discard block |
||
91 | 89 | /** |
92 | 90 | * @return array |
93 | 91 | */ |
94 | - public function __sleep() |
|
95 | - { |
|
92 | + public function __sleep() { |
|
96 | 93 | throw new \BadMethodCallException('Cannot serialize '.__CLASS__); |
97 | 94 | } |
98 | 95 | |
99 | - public function __wakeup() |
|
100 | - { |
|
96 | + public function __wakeup() { |
|
101 | 97 | throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); |
102 | 98 | } |
103 | 99 | |
104 | - public function __destruct() |
|
105 | - { |
|
100 | + public function __destruct() { |
|
106 | 101 | $this->close(); |
107 | 102 | } |
108 | 103 | |
@@ -193,8 +188,7 @@ discard block |
||
193 | 188 | /** |
194 | 189 | * {@inheritdoc} |
195 | 190 | */ |
196 | - public function close() |
|
197 | - { |
|
191 | + public function close() { |
|
198 | 192 | parent::close(); |
199 | 193 | foreach ($this->fileHandles as $type => $handle) { |
200 | 194 | ftruncate($handle, 0); |