1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Process\Pipes; 13 14use Symfony\Component\Process\Process; 15 16/** 17 * UnixPipes implementation uses unix pipes as handles. 18 * 19 * @author Romain Neutron <imprec@gmail.com> 20 * 21 * @internal 22 */ 23class UnixPipes extends AbstractPipes 24{ 25 private $ttyMode; 26 private $ptyMode; 27 private $haveReadSupport; 28 29 public function __construct($ttyMode, $ptyMode, $input, $haveReadSupport) 30 { 31 $this->ttyMode = (bool) $ttyMode; 32 $this->ptyMode = (bool) $ptyMode; 33 $this->haveReadSupport = (bool) $haveReadSupport; 34 35 parent::__construct($input); 36 } 37 38 public function __destruct() 39 { 40 $this->close(); 41 } 42 43 /** 44 * {@inheritdoc} 45 */ 46 public function getDescriptors() 47 { 48 if (!$this->haveReadSupport) { 49 $nullstream = fopen('/dev/null', 'c'); 50 51 return [ 52 ['pipe', 'r'], 53 $nullstream, 54 $nullstream, 55 ]; 56 } 57 58 if ($this->ttyMode) { 59 return [ 60 ['file', '/dev/tty', 'r'], 61 ['file', '/dev/tty', 'w'], 62 ['file', '/dev/tty', 'w'], 63 ]; 64 } 65 66 if ($this->ptyMode && Process::isPtySupported()) { 67 return [ 68 ['pty'], 69 ['pty'], 70 ['pty'], 71 ]; 72 } 73 74 return [ 75 ['pipe', 'r'], 76 ['pipe', 'w'], // stdout 77 ['pipe', 'w'], // stderr 78 ]; 79 } 80 81 /** 82 * {@inheritdoc} 83 */ 84 public function getFiles() 85 { 86 return []; 87 } 88 89 /** 90 * {@inheritdoc} 91 */ 92 public function readAndWrite($blocking, $close = false) 93 { 94 $this->unblock(); 95 $w = $this->write(); 96 97 $read = $e = []; 98 $r = $this->pipes; 99 unset($r[0]); 100 101 // let's have a look if something changed in streams 102 set_error_handler([$this, 'handleError']); 103 if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { 104 restore_error_handler(); 105 // if a system call has been interrupted, forget about it, let's try again 106 // otherwise, an error occurred, let's reset pipes 107 if (!$this->hasSystemCallBeenInterrupted()) { 108 $this->pipes = []; 109 } 110 111 return $read; 112 } 113 restore_error_handler(); 114 115 foreach ($r as $pipe) { 116 // prior PHP 5.4 the array passed to stream_select is modified and 117 // lose key association, we have to find back the key 118 $read[$type = array_search($pipe, $this->pipes, true)] = ''; 119 120 do { 121 $data = @fread($pipe, self::CHUNK_SIZE); 122 $read[$type] .= $data; 123 } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); 124 125 if (!isset($read[$type][0])) { 126 unset($read[$type]); 127 } 128 129 if ($close && feof($pipe)) { 130 fclose($pipe); 131 unset($this->pipes[$type]); 132 } 133 } 134 135 return $read; 136 } 137 138 /** 139 * {@inheritdoc} 140 */ 141 public function haveReadSupport() 142 { 143 return $this->haveReadSupport; 144 } 145 146 /** 147 * {@inheritdoc} 148 */ 149 public function areOpen() 150 { 151 return (bool) $this->pipes; 152 } 153} 154