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 $disableOutput; 28 29 public function __construct($ttyMode, $ptyMode, $input, $disableOutput) 30 { 31 $this->ttyMode = (bool) $ttyMode; 32 $this->ptyMode = (bool) $ptyMode; 33 $this->disableOutput = (bool) $disableOutput; 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->disableOutput) { 49 $nullstream = fopen('/dev/null', 'c'); 50 51 return array( 52 array('pipe', 'r'), 53 $nullstream, 54 $nullstream, 55 ); 56 } 57 58 if ($this->ttyMode) { 59 return array( 60 array('file', '/dev/tty', 'r'), 61 array('file', '/dev/tty', 'w'), 62 array('file', '/dev/tty', 'w'), 63 ); 64 } 65 66 if ($this->ptyMode && Process::isPtySupported()) { 67 return array( 68 array('pty'), 69 array('pty'), 70 array('pty'), 71 ); 72 } 73 74 return array( 75 array('pipe', 'r'), 76 array('pipe', 'w'), // stdout 77 array('pipe', 'w'), // stderr 78 ); 79 } 80 81 /** 82 * {@inheritdoc} 83 */ 84 public function getFiles() 85 { 86 return array(); 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 = array(); 98 $r = $this->pipes; 99 unset($r[0]); 100 101 // let's have a look if something changed in streams 102 if (($r || $w) && false === @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { 103 // if a system call has been interrupted, forget about it, let's try again 104 // otherwise, an error occurred, let's reset pipes 105 if (!$this->hasSystemCallBeenInterrupted()) { 106 $this->pipes = array(); 107 } 108 109 return $read; 110 } 111 112 foreach ($r as $pipe) { 113 // prior PHP 5.4 the array passed to stream_select is modified and 114 // lose key association, we have to find back the key 115 $read[$type = array_search($pipe, $this->pipes, true)] = ''; 116 117 do { 118 $data = fread($pipe, self::CHUNK_SIZE); 119 $read[$type] .= $data; 120 } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); 121 122 if (!isset($read[$type][0])) { 123 unset($read[$type]); 124 } 125 126 if ($close && feof($pipe)) { 127 fclose($pipe); 128 unset($this->pipes[$type]); 129 } 130 } 131 132 return $read; 133 } 134 135 /** 136 * {@inheritdoc} 137 */ 138 public function areOpen() 139 { 140 return (bool) $this->pipes; 141 } 142 143 /** 144 * Creates a new UnixPipes instance. 145 * 146 * @param Process $process 147 * @param string|resource $input 148 * 149 * @return static 150 */ 151 public static function create(Process $process, $input) 152 { 153 return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled()); 154 } 155} 156