How to call shell programs as functions with PHP


I’m a big fan of Symfony’s Process Component. I’ve used intensively this component within a project and I noticed that I needed a wrapper to avoid to write again and again the same code. Suddenly a cool python library came to my head: sh. With python’s sh we can call any program as if it were a function:

from sh import ifconfig
print(ifconfig("wlan0"))

Outputs:

wlan0   Link encap:Ethernet  HWaddr 00:00:00:00:00:00
        inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
        inet6 addr: ffff::ffff:ffff:ffff:fff/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:0 errors:0 dropped:0 overruns:0 frame:0
        TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000
        RX bytes:0 (0 GB)  TX bytes:0 (0 GB)

So I decided to develop something similar in PHP. This library is not exactly the same than python one. Python’s sh allows more cool things such as non-blocking processes, baking, … not available in my PHP one’s, but at least I can call shell programs as functions in a simple way (and that’s was my scope). Let’s start.

One simple example of Process:

use Symfony\Component\Process\Process;

$process = new Process('-latr ~');
$process->setTimeout(3600);
$process->run();

echo $process->getOutput();

With sh library we can do:

use Sh/Sh;

$sh  = new Sh();
echo $sh->ls('-latr ~');

You can check the source code in github, but it’s very simple one. Basically it’s a parser that creates the command line string, and another class that calls to the parser and sends the output to Process component. Whit the magic function __call we can use shell commands as functions.

The command’s arguments can be one string ‘-latr ~’ or one array [‘-latr’, ‘~’]. You can see more example in the unit tests here

Symfony/Process also allows us to get feedback in real time:

use Symfony\Component\Process\Process;

$process = new Process('ls -lsa');
$process->run(function ($type, $buffer) {
    if ('err' === $type) {
        echo 'ERR > '.$buffer;
    } else {
        echo 'OUT > '.$buffer;
    }
});

Sh uses this feature, so we can do things like that:

$sh->tail('/var/log/messages', function ($buffer)  {
    echo $buffer;
});

We can see more examples here:

<?php
error_reporting(-1);
include __DIR__ . '/../vendor/autoload.php';
use Sh\Sh;

echo Sh::factory()->runCommnad('notify-send', ['-t', 5000, 'title', 'HOLA']);
$sh  = new Sh();
echo $sh->ifconfig("eth0");
echo $sh->ls('-latr ~');
echo $sh->ls(['-latr', '~']);
$sh->tail('-f /var/log/apache2/access.log', function ($buffer)  {
    echo $buffer;
});

As I said before the library is in github and also you can use with composer:

require: "gonzalo123/sh": "dev-master"

Updated!

Now Sh library supports chained arguments (baking)

// chainable commands (baking)
$sh->ssh(array('myserver.com', '-p' => 1393))->whoami();
// executes: ssh myserver.com -p 1393 whoami

$sh->ssh(array('myserver.com', '-p' => 1393))->tail(array("/var/log/dumb_daemon.log", 'n' => 100));
// executes: ssh myserver.com -p 1393 tail /var/log/dumb_daemon.log -n 100
});
Advertisement

4 thoughts on “How to call shell programs as functions with PHP

  1. Thanks for sharing! This info was included into a digest of the best PHP news and releases: http://www.zfort.com/blog/php-digest-december-4-2012/ Check it out, I bet this digest is going to be interesting for you!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.