Page MenuHomePhorge

Command Execution
Arcanist Technical Documentation (exec)

This document describes best practices for executing system commands in PHP using libphutil.

Overview

PHP has several built-in mechanisms for executing system commands, like exec(), system(), and the backtick operator. However, these mechanisms often make it difficult to get all the information you need to handle error conditions, properly escaping commands is cumbersome, and they do not provide more advanced features like parallel execution and timeouts.

This document describes how to use the APIs in libphutil to execute commands without encountering these problems.

Simple Commands: execx() and exec_manual()

execx() and exec_manual() are replacements for exec(), system(), shell_exec(), and the backtick operator. The APIs look like this:

list($stdout, $stderr) = execx('ls %s', $path);
list($err, $stdout, $stderr) = exec_manual('ls %s', $path);

The major advantages of these methods over the exec() family are that you can easily check return codes, capture both stdout and stderr, and use a simple sprintf()-style formatting string to properly escape commands.

execx() will throw a CommandException if the command you execute terminates with a nonzero exit code, while exec_manual() returns the error code. If you use exec_manual(), you must manually check the error code.

Advanced Commands: ExecFutures

If you need more advanced features like parallel execution, command timeouts, and asynchronous I/O, use ExecFuture.

$future = new ExecFuture('ls %s', $path);
list($stdout, $stderr) = $future->resolvex();

ExecFuture is a Future, and can be used with constructs like FutureIterator to achieve and manage parallelism. See Using Futures for general information on how to use futures in libphutil.

In addition to futures-based parallelism, you can set a timeout on an ExecFuture, which will kill the command if it takes longer than the specified number of seconds to execute:

$future->setTimeout(30);

If the command runs longer than the timeout, the process will be killed and the future will resolve with a failure code (ExecFuture::TIMED_OUT_EXIT_CODE).

You can also write to the stdin of a process by using the ExecFuture::write() method.

$future = new ExecFuture('bc');
$future->write('2+2');
list($stdout) = $future->resolvex();

See ExecFuture for complete capability documentation.