30 class Process implements \IteratorAggregate
95 2 =>
'Misuse of shell builtins',
97 126 =>
'Invoked command cannot execute',
98 127 =>
'Command not found',
99 128 =>
'Invalid exit argument',
104 131 =>
'Quit and dump core',
105 132 =>
'Illegal instruction',
106 133 =>
'Trace/breakpoint trap',
107 134 =>
'Process aborted',
108 135 =>
'Bus error: "access to undefined portion of memory object"',
109 136 =>
'Floating point exception: "erroneous arithmetic operation"',
110 137 =>
'Kill (terminate immediately)',
111 138 =>
'User-defined 1',
112 139 =>
'Segmentation violation',
113 140 =>
'User-defined 2',
114 141 =>
'Write to pipe with no one reading',
115 142 =>
'Signal raised by alarm',
116 143 =>
'Termination (request to terminate)',
118 145 =>
'Child process terminated, stopped (or continued*)',
119 146 =>
'Continue if stopped',
120 147 =>
'Stop executing temporarily',
121 148 =>
'Terminal stop signal',
122 149 =>
'Background process attempting to read from tty ("in")',
123 150 =>
'Background process attempting to write to tty ("out")',
124 151 =>
'Urgent data available on socket',
125 152 =>
'CPU time limit exceeded',
126 153 =>
'File size limit exceeded',
127 154 =>
'Signal raised by timer counting virtual time: "virtual timer expired"',
128 155 =>
'Profiling timer expired',
130 157 =>
'Pollable event',
132 159 =>
'Bad syscall',
149 if (!function_exists(
'proc_open')) {
150 throw new RuntimeException(
'The Process class relies on proc_open, which is not available on your PHP installation.');
160 if (null === $this->cwd && (
defined(
'ZEND_THREAD_SAFE') ||
'\\' === DIRECTORY_SEPARATOR)) {
161 $this->cwd = getcwd();
169 $this->useFileHandles =
'\\' === DIRECTORY_SEPARATOR;
171 $this->enhanceWindowsCompatibility =
true;
172 $this->enhanceSigchildCompatibility =
'\\' !== DIRECTORY_SEPARATOR && $this->
isSigchildEnabled();
173 $this->options = array_replace(
array(
'suppress_errors' =>
true,
'binary_pipes' =>
true),
$options);
209 return $this->
wait();
228 throw new RuntimeException(
'This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
264 $this->starttime = $this->lastOutputTime = microtime(
true);
271 if (
'\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
272 $commandline =
'cmd /V:ON /E:ON /D /C "('.$commandline.
')';
273 foreach ($this->processPipes->getFiles() as $offset =>
$filename) {
278 if (!isset($this->options[
'bypass_shell'])) {
279 $this->options[
'bypass_shell'] =
true;
281 } elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->
isSigchildEnabled()) {
283 $descriptors[3] =
array(
'pipe',
'w');
286 $commandline =
'{ ('.$this->commandline.
') <&3 3<&- 3>/dev/null & } 3<&0;';
287 $commandline .=
'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
291 $ptsWorkaround = fopen(__FILE__,
'r');
294 $this->process = proc_open(
$commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
296 if (!is_resource($this->process)) {
299 $this->status = self::STATUS_STARTED;
301 if (isset($descriptors[3])) {
302 $this->fallbackStatus[
'pid'] = (int) fgets($this->processPipes->pipes[3]);
362 if (!$this->processPipes->haveReadSupport()) {
364 throw new \LogicException(
'Pass the callback to the Process:start method or enableOutput to use a callback with Process::wait');
371 $running =
'\\' === DIRECTORY_SEPARATOR ? $this->
isRunning() : $this->processPipes->areOpen();
372 $this->
readPipes($running,
'\\' !== DIRECTORY_SEPARATOR || !$running);
379 if ($this->processInformation[
'signaled'] && $this->processInformation[
'termsig'] !== $this->latestSignal) {
380 throw new RuntimeException(sprintf(
'The process has been signaled with signal "%s".', $this->processInformation[
'termsig']));
393 return $this->
isRunning() ? $this->processInformation[
'pid'] : null;
425 throw new RuntimeException(
'Disabling output while the process is running is not possible.');
427 if (null !== $this->idleTimeout) {
428 throw new LogicException(
'Output can not be disabled while an idle timeout is set.');
431 $this->outputDisabled =
true;
446 throw new RuntimeException(
'Enabling output while the process is running is not possible.');
449 $this->outputDisabled =
false;
476 if (
false ===
$ret = stream_get_contents($this->stdout, -1, 0)) {
498 $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
499 $this->incrementalOutputOffset = ftell($this->stdout);
501 if (
false === $latest) {
522 $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
523 $blocking = !(self::ITER_NON_BLOCKING & $flags);
524 $yieldOut = !(self::ITER_SKIP_OUT & $flags);
525 $yieldErr = !(self::ITER_SKIP_ERR & $flags);
527 while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
529 $out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
531 if (isset(
$out[0])) {
535 $this->incrementalOutputOffset = ftell($this->stdout);
538 yield self::OUT =>
$out;
543 $err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
545 if (isset($err[0])) {
549 $this->incrementalErrorOutputOffset = ftell($this->stderr);
552 yield self::ERR => $err;
556 if (!$blocking && !isset(
$out[0]) && !isset($err[0])) {
557 yield self::OUT =>
'';
571 ftruncate($this->stdout, 0);
572 fseek($this->stdout, 0);
573 $this->incrementalOutputOffset = 0;
590 if (
false ===
$ret = stream_get_contents($this->stderr, -1, 0)) {
613 $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
614 $this->incrementalErrorOutputOffset = ftell($this->stderr);
616 if (
false === $latest) {
630 ftruncate($this->stderr, 0);
631 fseek($this->stderr, 0);
632 $this->incrementalErrorOutputOffset = 0;
647 throw new RuntimeException(
'This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
672 return isset(self::$exitCodes[
$exitcode]) ? self::$exitCodes[
$exitcode] :
'Unknown error';
700 throw new RuntimeException(
'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
703 return $this->processInformation[
'signaled'];
720 if ($this->
isSigchildEnabled() && (!$this->enhanceSigchildCompatibility || -1 === $this->processInformation[
'termsig'])) {
721 throw new RuntimeException(
'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
724 return $this->processInformation[
'termsig'];
740 return $this->processInformation[
'stopped'];
756 return $this->processInformation[
'stopsig'];
766 if (self::STATUS_STARTED !== $this->status) {
772 return $this->processInformation[
'running'];
782 return $this->status != self::STATUS_READY;
794 return $this->status == self::STATUS_TERMINATED;
821 $timeoutMicro = microtime(
true) +
$timeout;
827 }
while ($this->
isRunning() && microtime(
true) < $timeoutMicro);
832 $this->
doSignal($signal ?: 9,
false);
837 if (isset($this->fallbackStatus[
'pid'])) {
838 unset($this->fallbackStatus[
'pid']);
840 return $this->
stop(0, $signal);
857 $this->lastOutputTime = microtime(
true);
859 fseek($this->stdout, 0, SEEK_END);
860 fwrite($this->stdout, $line);
861 fseek($this->stdout, $this->incrementalOutputOffset);
873 $this->lastOutputTime = microtime(
true);
875 fseek($this->stderr, 0, SEEK_END);
876 fwrite($this->stderr, $line);
877 fseek($this->stderr, $this->incrementalErrorOutputOffset);
956 if (null !==
$timeout && $this->outputDisabled) {
957 throw new LogicException(
'Idle timeout can not be set while the output is disabled.');
976 if (
'\\' === DIRECTORY_SEPARATOR &&
$tty) {
977 throw new RuntimeException(
'TTY mode is not supported on Windows platform.');
979 if (
$tty && (!file_exists(
'/dev/tty') || !is_readable(
'/dev/tty'))) {
983 $this->tty = (bool)
$tty;
1007 $this->pty = (bool) $bool;
1029 if (null === $this->cwd) {
1032 return getcwd() ?: null;
1078 $env = array_filter($env,
function ($value) {
1079 return !is_array($value);
1082 $this->env =
array();
1083 foreach ($env as $key => $value) {
1084 $this->env[$key] = (
string) $value;
1114 throw new LogicException(
'Input can not be set while the process is running.');
1167 $this->enhanceWindowsCompatibility = (bool) $enhance;
1195 $this->enhanceSigchildCompatibility = (bool) $enhance;
1210 if ($this->status !== self::STATUS_STARTED) {
1214 if (null !== $this->timeout && $this->timeout < microtime(
true) - $this->starttime) {
1220 if (null !== $this->idleTimeout && $this->idleTimeout < microtime(
true) - $this->lastOutputTime) {
1240 if (
'\\' === DIRECTORY_SEPARATOR) {
1255 $this->
input->rewind();
1257 if (
'\\' === DIRECTORY_SEPARATOR) {
1258 $this->processPipes =
new WindowsPipes($this->
input, !$this->outputDisabled || $this->hasCallback);
1260 $this->processPipes =
new UnixPipes($this->
isTty(), $this->
isPty(), $this->
input, !$this->outputDisabled || $this->hasCallback);
1263 return $this->processPipes->getDescriptors();
1278 if ($this->outputDisabled) {
1289 if (
$out == $type) {
1308 if (self::STATUS_STARTED !== $this->status) {
1312 $this->processInformation = proc_get_status($this->process);
1313 $running = $this->processInformation[
'running'];
1315 $this->
readPipes($running && $blocking,
'\\' !== DIRECTORY_SEPARATOR || !$running);
1317 if ($this->fallbackStatus && $this->enhanceSigchildCompatibility && $this->
isSigchildEnabled()) {
1333 if (null !== self::$sigchild) {
1334 return self::$sigchild;
1337 if (!function_exists(
'phpinfo') ||
defined(
'HHVM_VERSION')) {
1338 return self::$sigchild =
false;
1342 phpinfo(INFO_GENERAL);
1344 return self::$sigchild =
false !== strpos(ob_get_clean(),
'--enable-sigchild');
1357 if ($this->outputDisabled) {
1396 $result = $this->processPipes->readAndWrite($blocking, $close);
1401 $callback($type === self::STDOUT ? self::OUT : self::ERR,
$data);
1402 } elseif (!isset($this->fallbackStatus[
'signaled'])) {
1403 $this->fallbackStatus[
'exitcode'] = (int)
$data;
1415 $this->processPipes->close();
1416 if (is_resource($this->process)) {
1417 proc_close($this->process);
1419 $this->exitcode = $this->processInformation[
'exitcode'];
1420 $this->status = self::STATUS_TERMINATED;
1422 if (-1 === $this->exitcode) {
1423 if ($this->processInformation[
'signaled'] && 0 < $this->processInformation[
'termsig']) {
1425 $this->exitcode = 128 + $this->processInformation[
'termsig'];
1427 $this->processInformation[
'signaled'] =
true;
1428 $this->processInformation[
'termsig'] = -1;
1435 $this->callback = null;
1445 $this->starttime = null;
1446 $this->callback = null;
1447 $this->exitcode = null;
1448 $this->fallbackStatus =
array();
1449 $this->processInformation = null;
1450 $this->stdout = fopen(
'php://temp/maxmemory:'.(1024 * 1024),
'wb+');
1451 $this->stderr = fopen(
'php://temp/maxmemory:'.(1024 * 1024),
'wb+');
1452 $this->process = null;
1453 $this->latestSignal = null;
1454 $this->status = self::STATUS_READY;
1455 $this->incrementalOutputOffset = 0;
1456 $this->incrementalErrorOutputOffset = 0;
1473 if (null === $pid = $this->
getPid()) {
1474 if ($throwException) {
1475 throw new LogicException(
'Can not send signal on a non running process.');
1481 if (
'\\' === DIRECTORY_SEPARATOR) {
1482 exec(sprintf(
'taskkill /F /T /PID %d 2>&1', $pid),
$output, $exitCode);
1484 if ($throwException) {
1492 $ok = @proc_terminate($this->process, $signal);
1493 } elseif (function_exists(
'posix_kill')) {
1494 $ok = @posix_kill($pid, $signal);
1495 } elseif (
$ok = proc_open(sprintf(
'kill -%d %d', $signal, $pid),
array(2 =>
array(
'pipe',
'w')), $pipes)) {
1496 $ok =
false === fgets($pipes[2]);
1499 if ($throwException) {
1500 throw new RuntimeException(sprintf(
'Error while sending signal `%s`.', $signal));
1507 $this->latestSignal = (int) $signal;
1508 $this->fallbackStatus[
'signaled'] =
true;
1509 $this->fallbackStatus[
'exitcode'] = -1;
1525 throw new LogicException(sprintf(
'Process must be started before calling %s.', $functionName));
1539 throw new LogicException(sprintf(
'Process must be terminated before calling %s.', $functionName));
run($callback=null)
Runs the process.
setEnv(array $env)
Sets the environment variables.
getOutput()
Returns the current output of the process (STDOUT).
getEnhanceWindowsCompatibility()
Gets whether or not Windows compatibility is enabled.
$incrementalErrorOutputOffset
getEnhanceSigchildCompatibility()
Returns whether sigchild compatibility mode is activated or not.
getInput()
Gets the Process input.
clearErrorOutput()
Clears the process output.
getErrorOutput()
Returns the current error output of the process (STDERR).
addOutput($line)
Adds a line to the STDOUT stream.
requireProcessIsTerminated($functionName)
Ensures the process is terminated, throws a LogicException if the process has a status different than...
hasBeenSignaled()
Returns true if the child process has been terminated by an uncaught signal.
getWorkingDirectory()
Gets the working directory.
requireProcessIsStarted($functionName)
Ensures the process is running or terminated, throws a LogicException if the process has a not starte...
getTimeout()
Gets the process timeout (max.
getTermSignal()
Returns the number of the signal that caused the child process to terminate its execution.
$enhanceSigchildCompatibility
doSignal($signal, $throwException)
Sends a POSIX signal to the process.
isOutputDisabled()
Returns true in case the output is disabled, false otherwise.
resetProcessData()
Resets data related to the latest run of the process.
Exception that is thrown when a process times out.
setTimeout($timeout)
Sets the process timeout (max.
getIdleTimeout()
Gets the process idle timeout (max.
Add rich text string
The name of the decorator.
wait(callable $callback=null)
Waits for the process to terminate.
enableOutput()
Enables fetching output and error output from the underlying process.
getStopSignal()
Returns the number of the signal that caused the child process to stop its execution.
signal($signal)
Sends a POSIX signal to the process.
getOptions()
Gets the options for proc_open.
isSuccessful()
Checks if the process ended successfully.
setEnhanceWindowsCompatibility($enhance)
Sets whether or not Windows compatibility is enabled.
validateTimeout($timeout)
Validates and returns the filtered timeout.
UnixPipes implementation uses unix pipes as handles.
Exception for failed processes.
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\+" &#(? foreach( $entity_files as $file) $output
hasBeenStopped()
Returns true if the child process has been stopped by a signal.
__construct($commandline, $cwd=null, array $env=null, $input=null, $timeout=60, array $options=array())
Constructor.
getStatus()
Gets the process status.
readPipes($blocking, $close)
Reads pipes, executes callback.
disableOutput()
Disables fetching output and error output from the underlying process.
updateStatus($blocking)
Updates the status of the process, reads pipes.
isRunning()
Checks if the process is currently running.
isTerminated()
Checks if the process is terminated.
$enhanceWindowsCompatibility
setEnhanceSigchildCompatibility($enhance)
Activates sigchild compatibility mode.
isStarted()
Checks if the process has been started with no regard to the current state.
getExitCode()
Returns the exit code returned by the process.
checkTimeout()
Performs a check between the timeout definition and the time the process started. ...
setIdleTimeout($timeout)
Sets the process idle timeout (max.
static validateInput($caller, $input)
Validates and normalizes a Process input.
setCommandLine($commandline)
Sets the command line to be executed.
Create styles array
The data for the language used.
LogicException for the Process Component.
restart(callable $callback=null)
Restarts the process.
getCommandLine()
Gets the command line to be executed.
getIterator($flags=0)
Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
close()
Closes process resource, closes file handles, sets the exitcode.
getPid()
Returns the Pid (process identifier), if applicable.
readPipesForOutput($caller, $blocking=false)
Reads pipes for the freshest output.
getIncrementalErrorOutput()
Returns the errorOutput incrementally.
static isPtySupported()
Returns whether PTY is supported on the current operating system.
static escapeArgument($argument)
Escapes a string to be used as a shell argument.
isSigchildEnabled()
Returns whether PHP has been compiled with the '–enable-sigchild' option or not. ...
Process is a thin wrapper around proc_* functions to easily start independent PHP processes...
start(callable $callback=null)
Starts the process and returns after writing the input to STDIN.
getEnv()
Gets the environment variables.
getExitCodeText()
Returns a string representation for the exit code returned by the process.
setInput($input)
Sets the input.
setPty($bool)
Sets PTY mode.
buildCallback(callable $callback=null)
Builds up the callback used by wait().
getIncrementalOutput()
Returns the output incrementally.
isTty()
Checks if the TTY mode is enabled.
stop($timeout=10, $signal=null)
Stops the process.
isPty()
Returns PTY state.
defined( 'APPLICATION_ENV')||define( 'APPLICATION_ENV'
setWorkingDirectory($cwd)
Sets the current working directory.
clearOutput()
Clears the process output.
getDescriptors()
Creates the descriptors needed by the proc_open.
mustRun(callable $callback=null)
Runs the process.
setOptions(array $options)
Sets the options for proc_open.
addErrorOutput($line)
Adds a line to the STDERR stream.
WindowsPipes implementation uses temporary files as handles.
setTty($tty)
Enables or disables the TTY mode.