/** * Starts the process and returns after sending the STDIN. * * This method blocks until all STDIN data is sent to the process then it * returns while the process runs in the background. * * The termination of the process can be awaited with wait(). * * The callback receives the type of output (out or err) and some bytes from * the output in real-time while writing the standard input to the process. * It allows to have feedback from the independent process during execution. * If there is no callback passed, the wait() method can be called * with true as a second parameter then the callback will get all data occurred * in (and since) the start call. * * @param callback|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * * @throws RuntimeException When process can't be launch or is stopped * @throws RuntimeException When process is already running */ public function start($callback = null) { if ($this->isRunning()) { throw new RuntimeException('Process is already running'); } $this->resetProcessData(); $this->starttime = microtime(true); $this->callback = $this->buildCallback($callback); $this->processPipes = new ProcessPipes($this->useFileHandles); $descriptors = $this->processPipes->getDescriptors(); if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { // last exit code is output on the fourth pipe and caught to work around --enable-sigchild $descriptors = array_merge($descriptors, array(array('pipe', 'w'))); $this->commandline = '(' . $this->commandline . ') 3>/dev/null; code=$?; echo $code >&3; exit $code'; } $commandline = $this->commandline; if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->enhanceWindowsCompatibility) { $commandline = 'cmd /V:ON /E:ON /C "' . $commandline . '"'; if (!isset($this->options['bypass_shell'])) { $this->options['bypass_shell'] = true; } } $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options); if (!is_resource($this->process)) { throw new RuntimeException('Unable to launch a new process.'); } $this->status = self::STATUS_STARTED; $this->processPipes->unblock(); $this->processPipes->write(false, $this->stdin); $this->updateStatus(false); $this->checkTimeout(); }
/** * Creates the descriptors needed by the proc_open. * * @return array */ private function getDescriptors() { $this->processPipes = new ProcessPipes($this->useFileHandles, $this->tty); $descriptors = $this->processPipes->getDescriptors(); if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { // last exit code is output on the fourth pipe and caught to work around --enable-sigchild $descriptors = array_merge($descriptors, array(array('pipe', 'w'))); $this->commandline = '(' . $this->commandline . ') 3>/dev/null; code=$?; echo $code >&3; exit $code'; } return $descriptors; }
/** * Creates the descriptors needed by the proc_open. * * @return array */ private function getDescriptors() { $this->processPipes = new ProcessPipes($this->useFileHandles, $this->tty); return $this->processPipes->getDescriptors(); }