public function start(callable $callback = null)
{
if ($this->isRunning()) {
throw new RuntimeException('Process is already running');
}
$this->resetProcessData();
$this->starttime = $this->lastOutputTime = microtime(true);
$this->callback = $this->buildCallback($callback);
$this->hasCallback = null !== $callback;
$descriptors = $this->getDescriptors();
$commandline = $this->commandline;
$envline = '';
if (null !== $this->env && $this->inheritEnv) {
if ('\\' === DIRECTORY_SEPARATOR && !empty($this->options['bypass_shell']) && !$this->enhanceWindowsCompatibility) {
throw new LogicException('The "bypass_shell" option must be false to inherit environment variables while enhanced Windows compatibility is off');
}
$env = '\\' === DIRECTORY_SEPARATOR ? '(SET %s)&&' : 'export %s;';
foreach ($this->env as $k => $v) {
$envline .= sprintf($env, ProcessUtils::escapeArgument("{$k}={$v}"));
}
$env = null;
} else {
$env = $this->env;
}
if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
$commandline = 'cmd /V:ON /E:ON /D /C "(' . $envline . $commandline . ')';
foreach ($this->processPipes->getFiles() as $offset => $filename) {
$commandline .= ' ' . $offset . '>' . ProcessUtils::escapeArgument($filename);
}
$commandline .= '"';
if (!isset($this->options['bypass_shell'])) {
$this->options['bypass_shell'] = true;
}
} elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
$descriptors[3] = array('pipe', 'w');
// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
$commandline = $envline . '{ (' . $this->commandline . ') <&3 3<&- 3>/dev/null & } 3<&0;';
$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
// Workaround for the bug, when PTS functionality is enabled.
// @see : https://bugs.php.net/69442
$ptsWorkaround = fopen(__FILE__, 'r');
} elseif ('' !== $envline) {
$commandline = $envline . $commandline;
}
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $env, $this->options);
if (!is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
}
$this->status = self::STATUS_STARTED;
if (isset($descriptors[3])) {
$this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
}
if ($this->tty) {
return;
}
$this->updateStatus(false);
$this->checkTimeout();
}