Unix.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: yunwuxin <448901948@qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace think\process\pipes;
  12. use think\Process;
  13. class Unix extends Pipes
  14. {
  15. /** @var bool */
  16. private $ttyMode;
  17. /** @var bool */
  18. private $ptyMode;
  19. /** @var bool */
  20. private $disableOutput;
  21. public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
  22. {
  23. $this->ttyMode = (bool) $ttyMode;
  24. $this->ptyMode = (bool) $ptyMode;
  25. $this->disableOutput = (bool) $disableOutput;
  26. if (is_resource($input)) {
  27. $this->input = $input;
  28. } else {
  29. $this->inputBuffer = (string) $input;
  30. }
  31. }
  32. public function __destruct()
  33. {
  34. $this->close();
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function getDescriptors()
  40. {
  41. if ($this->disableOutput) {
  42. $nullstream = fopen('/dev/null', 'c');
  43. return [
  44. ['pipe', 'r'],
  45. $nullstream,
  46. $nullstream,
  47. ];
  48. }
  49. if ($this->ttyMode) {
  50. return [
  51. ['file', '/dev/tty', 'r'],
  52. ['file', '/dev/tty', 'w'],
  53. ['file', '/dev/tty', 'w'],
  54. ];
  55. }
  56. if ($this->ptyMode && Process::isPtySupported()) {
  57. return [
  58. ['pty'],
  59. ['pty'],
  60. ['pty'],
  61. ];
  62. }
  63. return [
  64. ['pipe', 'r'],
  65. ['pipe', 'w'], // stdout
  66. ['pipe', 'w'], // stderr
  67. ];
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. public function getFiles()
  73. {
  74. return [];
  75. }
  76. /**
  77. * {@inheritdoc}
  78. */
  79. public function readAndWrite($blocking, $close = false)
  80. {
  81. if (1 === count($this->pipes) && [0] === array_keys($this->pipes)) {
  82. fclose($this->pipes[0]);
  83. unset($this->pipes[0]);
  84. }
  85. if (empty($this->pipes)) {
  86. return [];
  87. }
  88. $this->unblock();
  89. $read = [];
  90. if (null !== $this->input) {
  91. $r = array_merge($this->pipes, ['input' => $this->input]);
  92. } else {
  93. $r = $this->pipes;
  94. }
  95. unset($r[0]);
  96. $w = isset($this->pipes[0]) ? [$this->pipes[0]] : null;
  97. $e = null;
  98. if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
  99. if (!$this->hasSystemCallBeenInterrupted()) {
  100. $this->pipes = [];
  101. }
  102. return $read;
  103. }
  104. if (0 === $n) {
  105. return $read;
  106. }
  107. foreach ($r as $pipe) {
  108. $type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input';
  109. $data = '';
  110. while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {
  111. $data .= $dataread;
  112. }
  113. if ('' !== $data) {
  114. if ('input' === $type) {
  115. $this->inputBuffer .= $data;
  116. } else {
  117. $read[$type] = $data;
  118. }
  119. }
  120. if (false === $data || (true === $close && feof($pipe) && '' === $data)) {
  121. if ('input' === $type) {
  122. $this->input = null;
  123. } else {
  124. fclose($this->pipes[$type]);
  125. unset($this->pipes[$type]);
  126. }
  127. }
  128. }
  129. if (null !== $w && 0 < count($w)) {
  130. while (strlen($this->inputBuffer)) {
  131. $written = fwrite($w[0], $this->inputBuffer, 2 << 18); // write 512k
  132. if ($written > 0) {
  133. $this->inputBuffer = (string) substr($this->inputBuffer, $written);
  134. } else {
  135. break;
  136. }
  137. }
  138. }
  139. if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
  140. fclose($this->pipes[0]);
  141. unset($this->pipes[0]);
  142. }
  143. return $read;
  144. }
  145. /**
  146. * {@inheritdoc}
  147. */
  148. public function areOpen()
  149. {
  150. return (bool) $this->pipes;
  151. }
  152. /**
  153. * 创建一个新的 UnixPipes 实例
  154. * @param Process $process
  155. * @param string|resource $input
  156. * @return self
  157. */
  158. public static function create(Process $process, $input)
  159. {
  160. return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
  161. }
  162. }