| <?php |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| namespace think\process\pipes; |
|
|
| use think\Process; |
|
|
| class Windows extends Pipes |
| { |
|
|
| |
| private $files = []; |
| |
| private $fileHandles = []; |
| |
| private $readBytes = [ |
| Process::STDOUT => 0, |
| Process::STDERR => 0, |
| ]; |
| |
| private $disableOutput; |
|
|
| public function __construct($disableOutput, $input) |
| { |
| $this->disableOutput = (bool) $disableOutput; |
|
|
| if (!$this->disableOutput) { |
|
|
| $this->files = [ |
| Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'), |
| Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'), |
| ]; |
| foreach ($this->files as $offset => $file) { |
| $this->fileHandles[$offset] = fopen($this->files[$offset], 'rb'); |
| if (false === $this->fileHandles[$offset]) { |
| throw new \RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable'); |
| } |
| } |
| } |
|
|
| if (is_resource($input)) { |
| $this->input = $input; |
| } else { |
| $this->inputBuffer = $input; |
| } |
| } |
|
|
| public function __destruct() |
| { |
| $this->close(); |
| $this->removeFiles(); |
| } |
|
|
| |
| |
| |
| public function getDescriptors() |
| { |
| if ($this->disableOutput) { |
| $nullstream = fopen('NUL', 'c'); |
|
|
| return [ |
| ['pipe', 'r'], |
| $nullstream, |
| $nullstream, |
| ]; |
| } |
|
|
| return [ |
| ['pipe', 'r'], |
| ['file', 'NUL', 'w'], |
| ['file', 'NUL', 'w'], |
| ]; |
| } |
|
|
| |
| |
| |
| public function getFiles() |
| { |
| return $this->files; |
| } |
|
|
| |
| |
| |
| public function readAndWrite($blocking, $close = false) |
| { |
| $this->write($blocking, $close); |
|
|
| $read = []; |
| $fh = $this->fileHandles; |
| foreach ($fh as $type => $fileHandle) { |
| if (0 !== fseek($fileHandle, $this->readBytes[$type])) { |
| continue; |
| } |
| $data = ''; |
| $dataread = null; |
| while (!feof($fileHandle)) { |
| if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) { |
| $data .= $dataread; |
| } |
| } |
| if (0 < $length = strlen($data)) { |
| $this->readBytes[$type] += $length; |
| $read[$type] = $data; |
| } |
|
|
| if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) { |
| fclose($this->fileHandles[$type]); |
| unset($this->fileHandles[$type]); |
| } |
| } |
|
|
| return $read; |
| } |
|
|
| |
| |
| |
| public function areOpen() |
| { |
| return (bool) $this->pipes && (bool) $this->fileHandles; |
| } |
|
|
| |
| |
| |
| public function close() |
| { |
| parent::close(); |
| foreach ($this->fileHandles as $handle) { |
| fclose($handle); |
| } |
| $this->fileHandles = []; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public static function create(Process $process, $input) |
| { |
| return new static($process->isOutputDisabled(), $input); |
| } |
|
|
| |
| |
| |
| private function removeFiles() |
| { |
| foreach ($this->files as $filename) { |
| if (file_exists($filename)) { |
| @unlink($filename); |
| } |
| } |
| $this->files = []; |
| } |
|
|
| |
| |
| |
| |
| |
| private function write($blocking, $close) |
| { |
| if (empty($this->pipes)) { |
| return; |
| } |
|
|
| $this->unblock(); |
|
|
| $r = null !== $this->input ? ['input' => $this->input] : null; |
| $w = isset($this->pipes[0]) ? [$this->pipes[0]] : null; |
| $e = null; |
|
|
| if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { |
| if (!$this->hasSystemCallBeenInterrupted()) { |
| $this->pipes = []; |
| } |
|
|
| return; |
| } |
|
|
| if (0 === $n) { |
| return; |
| } |
|
|
| if (null !== $w && 0 < count($r)) { |
| $data = ''; |
| while ($dataread = fread($r['input'], self::CHUNK_SIZE)) { |
| $data .= $dataread; |
| } |
|
|
| $this->inputBuffer .= $data; |
|
|
| if (false === $data || (true === $close && feof($r['input']) && '' === $data)) { |
| $this->input = null; |
| } |
| } |
|
|
| if (null !== $w && 0 < count($w)) { |
| while (strlen($this->inputBuffer)) { |
| $written = fwrite($w[0], $this->inputBuffer, 2 << 18); |
| if ($written > 0) { |
| $this->inputBuffer = (string) substr($this->inputBuffer, $written); |
| } else { |
| break; |
| } |
| } |
| } |
|
|
| if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) { |
| fclose($this->pipes[0]); |
| unset($this->pipes[0]); |
| } |
| } |
| } |
|
|