kamermans / command
External command runner / executor for PHP
Installs: 8 721
Dependents: 3
Suggesters: 1
Security: 0
Stars: 6
Watchers: 3
Forks: 2
Open Issues: 1
Requires
- php: >=5.4
Requires (Dev)
- php: >=5.5
- phpunit/phpunit: 4.*
README
External command runner / executor for PHP. This is an object oriented, robust replacement for exec
, shell_exec
, the backtick operator and the like.
This package does not work reliably in Windows due to a lack of complete proc_open()
support in PHP
This package is inspired by http://pollinimini.net/blog/php-command-runner/.
Running Commands
At its simplest form, you can execute commands like this:
$cmd = Command::factory('ls')->run();
Adding Arguments and Options
Here we are safely adding arguments:
use kamermans\Command\Command; $cmd = Command::factory('/usr/bin/svn') ->option('--username', 'drslump') ->option('-r', 'HEAD') ->option('log') ->argument('http://code.google.com/drslump/trunk') ->run(); echo $cmd->getStdOut();
Using a Callback for Incremental Updates
Normally all command output is buffered and once the command completes you can access it. By using a callback, the output is buffered until the desired number of bytes is received (see Command::setReadBuffer(int $bytes)
), then it is passed to your callback function:
use kamermans\Command\Command; $cmd = Command::factory('ls') ->setCallback(function($pipe, $data) { // Gets run for every 4096 bytes echo $data; }) ->setReadBuffer(4096) ->setDirectory('/tmp') ->option('-l') ->run();
Alternately, you can set the second argument for Command::run(string $stdin, bool $lines)
to true
to execute your callback once for every line of output:
use kamermans\Command\Command; $cmd = Command::factory('ls') ->setCallback(function($pipe, $data){ // Gets run for each line of output echo $data; }) ->setDirectory('/tmp') ->option('-l') ->run(null, true);
Streaming large command output
The STDOUT and STDERR is collected inside PHP by default. If you have a large amount of data to pass into the command, you should stream it in (see STDIN from a stream below). If you have a large amount of output from the command, you should stream it out using a callback:
use kamermans\Command\Command; require_once __DIR__.'/../vendor/autoload.php'; $filename = __DIR__.'/../README.md'; $stdin = fopen($filename, 'r'); // This will read README.md and grep for lines containing 'the' $cmd = Command::factory("grep 'the'") ->setCallback(function($pipe, $data) { // Change the text to uppercase $data = strtoupper($data); if ($pipe === Command::STDERR) { Command::echoStdErr($data); } else { echo $data; } }) ->run($stdin); fclose($stdin);
Running a Command without Escaping
By default, the command passed to Command::factory(string $command, bool $escape)
is escaped, so characters like |
and >
will replaced with \|
and \>
respectively. To prevent the command factory from escaping your command, you can pass true
as the second argument:
use kamermans\Command\Command; $cmd = Command::factory('grep CRON < /var/log/syslog | head', true)->run(); echo $cmd->getStdOut();
Outputting to STDERR
To output content to your STDERR
there is a helper function Command::echoStdErr(string $content)
:
use kamermans\Command\Command; $cmd = Command::factory('grep CRON < /var/log/syslog | head', true) ->setCallback(function($pipe,$data) { if ($pipe === Command::STDERR) { Command::echoStdErr($data); } else { echo $data; } }) ->run();
Using STDIN
You can provide data for STDIN using a string or a stream resource (like a file handle)
STDIN from a String
use kamermans\Command\Command; $stdin = "banana orange apple pear "; $cmd = Command::factory("sort") ->run($stdin); echo $cmd->getStdOut();
STDIN from a Stream
use kamermans\Command\Command; $filename = __DIR__.'/../README.md'; $stdin = fopen($filename, 'r'); // This will count the number of words in the README.md file $cmd = Command::factory("wc") ->option("--words") ->run($stdin); fclose($stdin); $words = trim($cmd->getStdOut()); echo "File $filename contains $words words\n";
Your system's STDIN
is also a stream, so you can accept input that is typed on the command line or piped into your script as well:
use kamermans\Command\Command; echo "Type some words, one per line, then press CTRL-D and they will be sorted:\n"; $cmd = Command::factory("sort") // This causes Command to use the real STDIN ->run(STDIN); echo "\n"; echo $cmd->getStdOut();
Some more features:
StdIn
data can be provided to the process as a parameter torun()
- Set environment variables for the process with
setEnv()
- Second argument to
option()
and argument toargument()
are automatically escaped. - Options separator is white space by default, it can be changed by manually setting it as third argument to
option()
or setting a new default withsetOptionSeparator()
. - The
proc_open
wrapper is exposed as a static method for your convenienceCommand::exec()