Piping to PHP
This blog post is more than 1 year old, so the content may be out of date.
Pipes are cool, super-uber cool. Simple, elegant, and opens up more functionality than you can shake a stick at.
Unfortunately they're rather unused in the PHP community.
Answers like this Ubuntu forums thread suggest using CLI arguments instead:
i want to be able to do something similar but instead of grep, with my php script, for instance:
ls | grep .jpg | myscript.php
you could then use a "dir" in php with the command line argument to pull your ls instead, just call it from the command line in the folder you're wanting it pulled from like this:
myscript.php .jpg
I.e. The answer was "Don't use pipes".
The flexibility of pipeline composition is so great, it makes no sense to ignore. If the answer is "write everything in PHP", you're doing it wrong.
It's very simple to accept piped data to PHP:
$data = ''; while ($input = fread(STDIN, 1024)) { $data .= $input; }
My use case was related to Drush - I have a Drush hook which allows XML content to be imported, creating article nodes. I wanted to support two modes of operation: provide a filename as a command-line argument, or pipe the XML directly to Drush.
drush importarticle foo.xml
cat myarticle.xml | sed 's/foo/bar/' | drush importarticle
The problem is that reading stdin is usually blocking, which means if content isn't piped, the script hangs, waiting for command-line input. However, it's trivial to set this to non-blocking (using stream_set_blocking).
Here's the finished version:
/** * Drush command to import an article. */ function foo__drush__import_article() { // Attempt to check for piped input. if ($data = _foo__drush__get_piped_input()) { // Assume piped data is a single article. mymodule_import_article($data); } // Alternatively, check for filenames provided as CLI arguments. elseif (count(func_get_args())) { $errors = array(); $files = func_get_args(); // Validate each file exists, and exit before importing if any are missing. foreach ($files as $file) { if (!is_file($file)) { $errors[] = $file; } } if (count($errors)) { $msg = dt('Import error: File not found: @files', array('@files' => implode(', ', $errors))); return drush_set_error('DRUSH_FOO_FILE_NOT_FOUND', $msg); } // Attempt to import each file. foreach ($files as $file) { $data = file_get_contents($file); mymodule_import_article($data); } } } /** * Check for piped input. * * @return String * Data piped to Drush. */ function _foo__drush__get_piped_input() { static $data = NULL; if (is_null($data)) { $data = ''; stream_set_blocking(STDIN, FALSE); while ($input = fread(STDIN, 1024)) { $data .= $input; } } return $data; }


Comments
Kris (not verified)
October 13, 2011 - 2:35am
Permalink
Cool beans!
Add new comment