30class 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)) {
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'];
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) {
1244 return $result = (bool) @proc_open(
'echo 1', array(array(
'pty'), array(
'pty'), array(
'pty')), $pipes);
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) {
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'];
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;
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) {
1507 $this->latestSignal = (int) $signal;
1508 $this->fallbackStatus[
'signaled'] =
true;
1509 $this->fallbackStatus[
'exitcode'] = -1;
sprintf('%.4f', $callTime)
An exception for terminatinating execution or to throw for unit testing.
InvalidArgumentException for the Process Component.
LogicException for the Process Component.
Exception for failed processes.
Exception that is thrown when a process times out.
RuntimeException for the Process Component.
UnixPipes implementation uses unix pipes as handles.
WindowsPipes implementation uses temporary files as handles.
static validateInput($caller, $input)
Validates and normalizes a Process input.
static escapeArgument($argument)
Escapes a string to be used as a shell argument.
Process is a thin wrapper around proc_* functions to easily start independent PHP processes.
isTty()
Checks if the TTY mode is enabled.
hasBeenSignaled()
Returns true if the child process has been terminated by an uncaught signal.
getDescriptors()
Creates the descriptors needed by the proc_open.
setCommandLine($commandline)
Sets the command line to be executed.
stop($timeout=10, $signal=null)
Stops the process.
isPty()
Returns PTY state.
getIterator($flags=0)
Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
readPipesForOutput($caller, $blocking=false)
Reads pipes for the freshest output.
enableOutput()
Enables fetching output and error output from the underlying process.
wait(callable $callback=null)
Waits for the process to terminate.
setEnv(array $env)
Sets the environment variables.
isTerminated()
Checks if the process is terminated.
validateTimeout($timeout)
Validates and returns the filtered timeout.
run($callback=null)
Runs the process.
$incrementalErrorOutputOffset
getIncrementalOutput()
Returns the output incrementally.
clearOutput()
Clears the process output.
getInput()
Gets the Process input.
setPty($bool)
Sets PTY mode.
addOutput($line)
Adds a line to the STDOUT stream.
getExitCode()
Returns the exit code returned by the process.
clearErrorOutput()
Clears the process output.
setOptions(array $options)
Sets the options for proc_open.
getErrorOutput()
Returns the current error output of the process (STDERR).
doSignal($signal, $throwException)
Sends a POSIX signal to the process.
getEnhanceWindowsCompatibility()
Gets whether or not Windows compatibility is enabled.
updateStatus($blocking)
Updates the status of the process, reads pipes.
isOutputDisabled()
Returns true in case the output is disabled, false otherwise.
getStopSignal()
Returns the number of the signal that caused the child process to stop its execution.
$enhanceSigchildCompatibility
isStarted()
Checks if the process has been started with no regard to the current state.
isSuccessful()
Checks if the process ended successfully.
restart(callable $callback=null)
Restarts the process.
getCommandLine()
Gets the command line to be executed.
setEnhanceWindowsCompatibility($enhance)
Sets whether or not Windows compatibility is enabled.
buildCallback(callable $callback=null)
Builds up the callback used by wait().
hasBeenStopped()
Returns true if the child process has been stopped by a signal.
$enhanceWindowsCompatibility
setInput($input)
Sets the input.
close()
Closes process resource, closes file handles, sets the exitcode.
mustRun(callable $callback=null)
Runs the process.
start(callable $callback=null)
Starts the process and returns after writing the input to STDIN.
getEnhanceSigchildCompatibility()
Returns whether sigchild compatibility mode is activated or not.
setIdleTimeout($timeout)
Sets the process idle timeout (max.
setTty($tty)
Enables or disables the TTY mode.
addErrorOutput($line)
Adds a line to the STDERR stream.
isRunning()
Checks if the process is currently running.
getPid()
Returns the Pid (process identifier), if applicable.
setWorkingDirectory($cwd)
Sets the current working directory.
getOptions()
Gets the options for proc_open.
getWorkingDirectory()
Gets the working directory.
requireProcessIsStarted($functionName)
Ensures the process is running or terminated, throws a LogicException if the process has a not starte...
getTermSignal()
Returns the number of the signal that caused the child process to terminate its execution.
checkTimeout()
Performs a check between the timeout definition and the time the process started.
getIncrementalErrorOutput()
Returns the errorOutput incrementally.
getStatus()
Gets the process status.
getIdleTimeout()
Gets the process idle timeout (max.
setTimeout($timeout)
Sets the process timeout (max.
requireProcessIsTerminated($functionName)
Ensures the process is terminated, throws a LogicException if the process has a status different than...
getTimeout()
Gets the process timeout (max.
isSigchildEnabled()
Returns whether PHP has been compiled with the '–enable-sigchild' option or not.
static isPtySupported()
Returns whether PTY is supported on the current operating system.
disableOutput()
Disables fetching output and error output from the underlying process.
resetProcessData()
Resets data related to the latest run of the process.
getExitCodeText()
Returns a string representation for the exit code returned by the process.
setEnhanceSigchildCompatibility($enhance)
Activates sigchild compatibility mode.
readPipes($blocking, $close)
Reads pipes, executes callback.
signal($signal)
Sends a POSIX signal to the process.
__construct($commandline, $cwd=null, array $env=null, $input=null, $timeout=60, array $options=array())
Constructor.
getEnv()
Gets the environment variables.
getOutput()
Returns the current output of the process (STDOUT).
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\s+" &#(? foreach( $entity_files as $file) $output
PipesInterface manages descriptors and pipes for the use of proc_open.
defined( 'APPLICATION_ENV')||define( 'APPLICATION_ENV'