Skip to main content

popen for cli commands and pipes in php

Source: Pipes 1/3 by Jonah G.S. on Flickr.com
I got a question today about using commands that pipe output to other commands within PHP applications.

There are two functions in PHP that are perfect for the task: popen and proc_open.

The function "popen" opens a process file pointer, basically you have a pointer during the execution of a process. This functionality is often useful when you have one-way traffic (like piping commands on command line).

The function "proc_open" behaves the same as popen, but gives you access to the input and the output, which makes it very useful for reading and writing as you go along.

So let's say you have logic that generates a crontab entry, you can always do this using the commandline.

/usr/bin/php crontab.php | /usr/bin/crontab
But when you want to run it as a complete process, you can go about using exec, shell_exec, passthru or system and fiddle with escapeshellcmd. But often this looks messy and not reusable.

A better approach would be to use "popen". A small example would look something like this:

<?php

$output = '*/5 * * * * /bin/echo "Hello World!" 2>&1' . PHP_EOL;
$command = '/usr/bin/crontab';

var_dump(cmdPipe($output, $command));
/**
 * Functionality to pipe output
 *
 * @param string $input The command that needs to be executed
 * @param string $commandline The command the first command needs to be
 * piped to
 * @return string The output of the given command
 * @throws \RuntimeException
 */
function cmdPipe($input, $commandline)
{
    if (false === ($pipe = popen("echo \"$input\"|$commandline", 'r'))) {
        throw new \RuntimeException('Cannot open pipe');
    }
    $output = '';
    while (!feof($pipe)) {
        $output .= fread($pipe, 1024);
    }
    pclose($pipe);
    return $output;
}
DISCLAIMER: This is not secure code and should not be used as-is in production environments!

Build it as a feature element and you now have a piping functionality you can nest, embed but most of all: reuse.

Comments

  1. I suppose you say that this is no secure code because of the statement `"echo \"$input\"|$commandline"` that could inject commands into the shell. You can fix that by encoding $input with base64_encode() and to sent that to the pipe, adding `| base64 --decode` before `|$commandline`.

    ReplyDelete
    Replies
    1. I wouldn't use base64 encoding/decoding as your defence against malicious commands as you just convert strings into another format: base64_encode('evil-script') → base64_decode('ZXZpbC1zY3JpcHQK') → 'evil-script'.

      I would definitely look at filtering and validation functions like "filter_var", "ctype_*" and "is_*", or use filtering and validation features of a PHP framework as they offer custom types like credit cards, uuid, barcode, url and more.

      The reason I say the code is not secure is that you cannot trust any data, no matter where it comes from: OCR converted images to text, phone numbers on a PBX, urls in RSS feeds, XML from a service, … all things that are not hard-coded can be modified, and nowadays even hard-coded things can be circumvented. So don't trust any data and you'll be safe.

      Delete

Post a Comment

Popular posts from this blog

PHP Arrays - Associative Arrays or Hash Maps

Associative array or hash maps are listings of key and value pairs with a posibility to nest additional keys and values. An associative array is a very powerful construct within PHP.

In our previous article we discussed simple arrays, which in their turn are indexed associative arrays under the hood. Take the following example:

$array = [
'apple',
'banana',
'chocolate',
]; 

Is in fact an indexed associative array under the hood:

$array = [
0 => 'apple',
1 => 'banana',
2 => 'chocolate',
]; 

But associative arrays can be so much more than just an indexed array, and you will find many database operations returning arrays where the fields of a table are the keys in the array while their values are also the values within the array.

$productRowData = [
'product_id' => 1234,
'brand_id' => 321,
'product_name' => 'Our awesome product',
'prodcut_description' => 'This is our most awesome product.&#…

Speeding up database calls with PDO and iterators

When you review lots of code, you often wonder why things were written the way they were. Especially when making expensive calls to a database, I still see things that could and should be improved.
No framework development When working with a framework, mostly these database calls are optimized for the developer and abstract the complex logic to improve and optimize the retrieval and usage of data. But then developers need to build something without a framework and end up using the basics of PHP in a sub-optimal way.

$pdo = new \PDO( $config['db']['dsn'], $config['db']['username'], $config['db']['password'] ); $sql = 'SELECT * FROM `gen_contact` ORDER BY `contact_modified` DESC'; $stmt = $pdo->prepare($sql); $stmt->execute(); $data = $stmt->fetchAll(\PDO::FETCH_OBJ); echo 'Getting the contacts that changed the last 3 months' . PHP_EOL; foreach ($data as $row) { $dt = new \DateTime('2015-04-…

Deploy Docker containers fast to Microsoft Azure

DEPLOY DOCKER CONTAINERS FAST TO MICROSOFT AZURE It’s hard to ignore the fact thatDockeris a way to move forward for rapid application development, distributed architectures and microservices. For developersDockeroffers great advantages as they can build their containers specifically for the task they work on. They grab a base image of a container, modify it for their purpose and prepare the functionality inside the container. Quality, testing and security teams now have a single instance to look at and ensure all functional and regulatory requirements are met. System engineers now don’t have to worry about providing a system with the required specs as the container is already provisioned for that purpose. But where do you deploy yourDockercontainers? You can set up your existing bare metal infrastructure to allow them to run containers, but this also means you need to learn about securing your container infrastructure, which is not an easy task. Luckily “the cloud” offers container …