104fd306cSNickeau<?php 204fd306cSNickeau 304fd306cSNickeau/* 404fd306cSNickeau * This file is part of the Symfony package. 504fd306cSNickeau * 604fd306cSNickeau * (c) Fabien Potencier <fabien@symfony.com> 704fd306cSNickeau * 804fd306cSNickeau * For the full copyright and license information, please view the LICENSE 904fd306cSNickeau * file that was distributed with this source code. 1004fd306cSNickeau */ 1104fd306cSNickeau 1204fd306cSNickeaunamespace Symfony\Component\Process\Pipes; 1304fd306cSNickeau 1404fd306cSNickeauuse Symfony\Component\Process\Exception\InvalidArgumentException; 1504fd306cSNickeau 1604fd306cSNickeau/** 1704fd306cSNickeau * @author Romain Neutron <imprec@gmail.com> 1804fd306cSNickeau * 1904fd306cSNickeau * @internal 2004fd306cSNickeau */ 2104fd306cSNickeauabstract class AbstractPipes implements PipesInterface 2204fd306cSNickeau{ 2304fd306cSNickeau public $pipes = []; 2404fd306cSNickeau 2504fd306cSNickeau private $inputBuffer = ''; 2604fd306cSNickeau private $input; 2704fd306cSNickeau private $blocked = true; 2804fd306cSNickeau private $lastError; 2904fd306cSNickeau 3004fd306cSNickeau /** 3104fd306cSNickeau * @param resource|string|int|float|bool|\Iterator|null $input 3204fd306cSNickeau */ 3304fd306cSNickeau public function __construct($input) 3404fd306cSNickeau { 3504fd306cSNickeau if (\is_resource($input) || $input instanceof \Iterator) { 3604fd306cSNickeau $this->input = $input; 3704fd306cSNickeau } elseif (\is_string($input)) { 3804fd306cSNickeau $this->inputBuffer = $input; 3904fd306cSNickeau } else { 4004fd306cSNickeau $this->inputBuffer = (string) $input; 4104fd306cSNickeau } 4204fd306cSNickeau } 4304fd306cSNickeau 4404fd306cSNickeau /** 4504fd306cSNickeau * {@inheritdoc} 4604fd306cSNickeau */ 4704fd306cSNickeau public function close() 4804fd306cSNickeau { 4904fd306cSNickeau foreach ($this->pipes as $pipe) { 5004fd306cSNickeau if (\is_resource($pipe)) { 5104fd306cSNickeau fclose($pipe); 5204fd306cSNickeau } 5304fd306cSNickeau } 5404fd306cSNickeau $this->pipes = []; 5504fd306cSNickeau } 5604fd306cSNickeau 5704fd306cSNickeau /** 5804fd306cSNickeau * Returns true if a system call has been interrupted. 5904fd306cSNickeau */ 6004fd306cSNickeau protected function hasSystemCallBeenInterrupted(): bool 6104fd306cSNickeau { 6204fd306cSNickeau $lastError = $this->lastError; 6304fd306cSNickeau $this->lastError = null; 6404fd306cSNickeau 6504fd306cSNickeau // stream_select returns false when the `select` system call is interrupted by an incoming signal 6604fd306cSNickeau return null !== $lastError && false !== stripos($lastError, 'interrupted system call'); 6704fd306cSNickeau } 6804fd306cSNickeau 6904fd306cSNickeau /** 7004fd306cSNickeau * Unblocks streams. 7104fd306cSNickeau */ 7204fd306cSNickeau protected function unblock() 7304fd306cSNickeau { 7404fd306cSNickeau if (!$this->blocked) { 7504fd306cSNickeau return; 7604fd306cSNickeau } 7704fd306cSNickeau 7804fd306cSNickeau foreach ($this->pipes as $pipe) { 7904fd306cSNickeau stream_set_blocking($pipe, 0); 8004fd306cSNickeau } 8104fd306cSNickeau if (\is_resource($this->input)) { 8204fd306cSNickeau stream_set_blocking($this->input, 0); 8304fd306cSNickeau } 8404fd306cSNickeau 8504fd306cSNickeau $this->blocked = false; 8604fd306cSNickeau } 8704fd306cSNickeau 8804fd306cSNickeau /** 8904fd306cSNickeau * Writes input to stdin. 9004fd306cSNickeau * 9104fd306cSNickeau * @throws InvalidArgumentException When an input iterator yields a non supported value 9204fd306cSNickeau */ 9304fd306cSNickeau protected function write(): ?array 9404fd306cSNickeau { 9504fd306cSNickeau if (!isset($this->pipes[0])) { 9604fd306cSNickeau return null; 9704fd306cSNickeau } 9804fd306cSNickeau $input = $this->input; 9904fd306cSNickeau 10004fd306cSNickeau if ($input instanceof \Iterator) { 10104fd306cSNickeau if (!$input->valid()) { 10204fd306cSNickeau $input = null; 10304fd306cSNickeau } elseif (\is_resource($input = $input->current())) { 10404fd306cSNickeau stream_set_blocking($input, 0); 10504fd306cSNickeau } elseif (!isset($this->inputBuffer[0])) { 10604fd306cSNickeau if (!\is_string($input)) { 107*83c68632SNico if (!\is_scalar($input)) { 10804fd306cSNickeau 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))); 10904fd306cSNickeau } 11004fd306cSNickeau $input = (string) $input; 11104fd306cSNickeau } 11204fd306cSNickeau $this->inputBuffer = $input; 11304fd306cSNickeau $this->input->next(); 11404fd306cSNickeau $input = null; 11504fd306cSNickeau } else { 11604fd306cSNickeau $input = null; 11704fd306cSNickeau } 11804fd306cSNickeau } 11904fd306cSNickeau 12004fd306cSNickeau $r = $e = []; 12104fd306cSNickeau $w = [$this->pipes[0]]; 12204fd306cSNickeau 12304fd306cSNickeau // let's have a look if something changed in streams 12404fd306cSNickeau if (false === @stream_select($r, $w, $e, 0, 0)) { 12504fd306cSNickeau return null; 12604fd306cSNickeau } 12704fd306cSNickeau 12804fd306cSNickeau foreach ($w as $stdin) { 12904fd306cSNickeau if (isset($this->inputBuffer[0])) { 13004fd306cSNickeau $written = fwrite($stdin, $this->inputBuffer); 13104fd306cSNickeau $this->inputBuffer = substr($this->inputBuffer, $written); 13204fd306cSNickeau if (isset($this->inputBuffer[0])) { 13304fd306cSNickeau return [$this->pipes[0]]; 13404fd306cSNickeau } 13504fd306cSNickeau } 13604fd306cSNickeau 13704fd306cSNickeau if ($input) { 13804fd306cSNickeau while (true) { 13904fd306cSNickeau $data = fread($input, self::CHUNK_SIZE); 14004fd306cSNickeau if (!isset($data[0])) { 14104fd306cSNickeau break; 14204fd306cSNickeau } 14304fd306cSNickeau $written = fwrite($stdin, $data); 14404fd306cSNickeau $data = substr($data, $written); 14504fd306cSNickeau if (isset($data[0])) { 14604fd306cSNickeau $this->inputBuffer = $data; 14704fd306cSNickeau 14804fd306cSNickeau return [$this->pipes[0]]; 14904fd306cSNickeau } 15004fd306cSNickeau } 15104fd306cSNickeau if (feof($input)) { 15204fd306cSNickeau if ($this->input instanceof \Iterator) { 15304fd306cSNickeau $this->input->next(); 15404fd306cSNickeau } else { 15504fd306cSNickeau $this->input = null; 15604fd306cSNickeau } 15704fd306cSNickeau } 15804fd306cSNickeau } 15904fd306cSNickeau } 16004fd306cSNickeau 16104fd306cSNickeau // no input to read on resource, buffer is empty 16204fd306cSNickeau if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) { 16304fd306cSNickeau $this->input = null; 16404fd306cSNickeau fclose($this->pipes[0]); 16504fd306cSNickeau unset($this->pipes[0]); 16604fd306cSNickeau } elseif (!$w) { 16704fd306cSNickeau return [$this->pipes[0]]; 16804fd306cSNickeau } 16904fd306cSNickeau 17004fd306cSNickeau return null; 17104fd306cSNickeau } 17204fd306cSNickeau 17304fd306cSNickeau /** 17404fd306cSNickeau * @internal 17504fd306cSNickeau */ 17604fd306cSNickeau public function handleError(int $type, string $msg) 17704fd306cSNickeau { 17804fd306cSNickeau $this->lastError = $msg; 17904fd306cSNickeau } 18004fd306cSNickeau} 181