Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Process\Pipes; Chris@0: Chris@0: use Symfony\Component\Process\Process; Chris@0: Chris@0: /** Chris@0: * UnixPipes implementation uses unix pipes as handles. Chris@0: * Chris@0: * @author Romain Neutron Chris@0: * Chris@0: * @internal Chris@0: */ Chris@0: class UnixPipes extends AbstractPipes Chris@0: { Chris@0: private $ttyMode; Chris@0: private $ptyMode; Chris@0: private $haveReadSupport; Chris@0: Chris@0: public function __construct($ttyMode, $ptyMode, $input, $haveReadSupport) Chris@0: { Chris@0: $this->ttyMode = (bool) $ttyMode; Chris@0: $this->ptyMode = (bool) $ptyMode; Chris@0: $this->haveReadSupport = (bool) $haveReadSupport; Chris@0: Chris@0: parent::__construct($input); Chris@0: } Chris@0: Chris@0: public function __destruct() Chris@0: { Chris@0: $this->close(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDescriptors() Chris@0: { Chris@0: if (!$this->haveReadSupport) { Chris@0: $nullstream = fopen('/dev/null', 'c'); Chris@0: Chris@17: return [ Chris@17: ['pipe', 'r'], Chris@0: $nullstream, Chris@0: $nullstream, Chris@17: ]; Chris@0: } Chris@0: Chris@0: if ($this->ttyMode) { Chris@17: return [ Chris@17: ['file', '/dev/tty', 'r'], Chris@17: ['file', '/dev/tty', 'w'], Chris@17: ['file', '/dev/tty', 'w'], Chris@17: ]; Chris@0: } Chris@0: Chris@0: if ($this->ptyMode && Process::isPtySupported()) { Chris@17: return [ Chris@17: ['pty'], Chris@17: ['pty'], Chris@17: ['pty'], Chris@17: ]; Chris@0: } Chris@0: Chris@17: return [ Chris@17: ['pipe', 'r'], Chris@17: ['pipe', 'w'], // stdout Chris@17: ['pipe', 'w'], // stderr Chris@17: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getFiles() Chris@0: { Chris@17: return []; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function readAndWrite($blocking, $close = false) Chris@0: { Chris@0: $this->unblock(); Chris@0: $w = $this->write(); Chris@0: Chris@17: $read = $e = []; Chris@0: $r = $this->pipes; Chris@0: unset($r[0]); Chris@0: Chris@0: // let's have a look if something changed in streams Chris@17: set_error_handler([$this, 'handleError']); Chris@16: if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { Chris@16: restore_error_handler(); Chris@0: // if a system call has been interrupted, forget about it, let's try again Chris@0: // otherwise, an error occurred, let's reset pipes Chris@0: if (!$this->hasSystemCallBeenInterrupted()) { Chris@17: $this->pipes = []; Chris@0: } Chris@0: Chris@0: return $read; Chris@0: } Chris@16: restore_error_handler(); Chris@0: Chris@0: foreach ($r as $pipe) { Chris@0: // prior PHP 5.4 the array passed to stream_select is modified and Chris@0: // lose key association, we have to find back the key Chris@0: $read[$type = array_search($pipe, $this->pipes, true)] = ''; Chris@0: Chris@0: do { Chris@0: $data = fread($pipe, self::CHUNK_SIZE); Chris@0: $read[$type] .= $data; Chris@0: } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); Chris@0: Chris@0: if (!isset($read[$type][0])) { Chris@0: unset($read[$type]); Chris@0: } Chris@0: Chris@0: if ($close && feof($pipe)) { Chris@0: fclose($pipe); Chris@0: unset($this->pipes[$type]); Chris@0: } Chris@0: } Chris@0: Chris@0: return $read; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function haveReadSupport() Chris@0: { Chris@0: return $this->haveReadSupport; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function areOpen() Chris@0: { Chris@0: return (bool) $this->pipes; Chris@0: } Chris@0: }