public function Process::start

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.

Parameters

Closure|string|array $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

\RuntimeException When process is already running

1 call to Process::start()

File

drupal/core/vendor/symfony/process/Symfony/Component/Process/Process.php, line 193

Class

Process
Process is a thin wrapper around proc_* functions to ease start independent PHP processes.

Namespace

Symfony\Component\Process

Code

public function start($callback = null) {
  if ($this
    ->isRunning()) {
    throw new \RuntimeException('Process is already running');
  }
  $this->stdout = '';
  $this->stderr = '';
  $callback = $this
    ->buildCallback($callback);

  //Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.

  //Workaround for this problem is to use temporary files instead of pipes on Windows platform.

  //@see https://bugs.php.net/bug.php?id=51800
  if (defined('PHP_WINDOWS_VERSION_BUILD')) {
    $this->fileHandles = array(
      self::STDOUT => tmpfile(),
    );
    $this->readBytes = array(
      self::STDOUT => 0,
    );
    $descriptors = array(
      array(
        'pipe',
        'r',
      ),
      $this->fileHandles[self::STDOUT],
      array(
        'pipe',
        'w',
      ),
    );
  }
  else {
    $descriptors = array(
      array(
        'pipe',
        'r',
      ),
      // stdin
      array(
        'pipe',
        'w',
      ),
      // stdout
      array(
        'pipe',
        'w',
      ),
      // stderr
      array(
        'pipe',
        'w',
      ),
    );
    $this->commandline = '(' . $this->commandline . ') 3>/dev/null; echo $? >&3';
  }
  $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->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;
  foreach ($this->pipes as $pipe) {
    stream_set_blocking($pipe, false);
  }
  if (null === $this->stdin) {
    fclose($this->pipes[0]);
    unset($this->pipes[0]);
    return;
  }
  $writePipes = array(
    $this->pipes[0],
  );
  unset($this->pipes[0]);
  $stdinLen = strlen($this->stdin);
  $stdinOffset = 0;
  while ($writePipes) {
    if (defined('PHP_WINDOWS_VERSION_BUILD')) {
      $this
        ->processFileHandles($callback);
    }
    $r = $this->pipes;
    $w = $writePipes;
    $e = null;
    $n = @stream_select($r, $w, $e, $this->timeout);
    if (false === $n) {
      break;
    }
    if ($n === 0) {
      proc_terminate($this->process);
      throw new \RuntimeException('The process timed out.');
    }
    if ($w) {
      $written = fwrite($writePipes[0], (string) substr($this->stdin, $stdinOffset), 8192);
      if (false !== $written) {
        $stdinOffset += $written;
      }
      if ($stdinOffset >= $stdinLen) {
        fclose($writePipes[0]);
        $writePipes = null;
      }
    }
    foreach ($r as $pipe) {
      $type = array_search($pipe, $this->pipes);
      $data = fread($pipe, 8192);
      if (strlen($data) > 0) {
        call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
      }
      if (false === $data || feof($pipe)) {
        fclose($pipe);
        unset($this->pipes[$type]);
      }
    }
  }
  $this
    ->updateStatus();
}