#!/usr/bin/php -qC
<?php
/**
* title: Shell PHP functions
* description: Pipe from and to PHP functions from the shell.
* type: cli
* version: 0.8
* depends: php:cli
*
* Wrapper script which allows PHP functions to be called directly from the
* shell. Parameters can be supplied directly as arguments, or piped in via
* STDIN - which either becomes the first parameter, or substitutes any
* "-" argument placeholder.
*
* strtolower ABCDE
* echo "x?? 2" | urlencode
* echo "p" | strpos "inpos" -
*
* The simple invocation forms are Most useful with string functions.
* But arrays can be passed in, and results are returned as JSON.
*
* echo [1,2,3] | array_push - 4 | print_r
*
* Mostly function return values are output, but for &$result signatures
* the reference-parameter will be assumed as primary result value.
*
* preg_match /A+/ AAABBBCCC
*
* Setup requires just a few symlinks
* e.g.
* ln -s PhpFunctionCall strtolower
* ln -s PhpFunctionCall base64_decode
* ln -s PhpFunctionCall unserialize
*
* The included Makefile will create the most useful shortcuts.
*
*/
#-- Function name
$func = basename(array_shift($_SERVER["argv"]));
set_error_handler("stderr_color");
#-- Arguments used as function params
$args = $_SERVER["argv"];
$dashes = count(array_intersect($args, ["-"]));
#-- STDIN can be input parameter(s)
if (!posix_isatty(STDIN) and is_string($stdin = rtrim(fread(STDIN, 1<<24), "\n"))
or ($dashes and is_null($stdin = NULL)))
{
// Unpack JSON
if (preg_match("/^ \s* [\[\{] .+ [\]\}] \s* $/smix", $stdin)) {
$stdin = json_decode($stdin, TRUE);
}
// Allot array values to multiple params
if (is_array($stdin) and ($dashes >= 2)) {
while (count($stdin)) {
$args[array_search("-", $args, TRUE)] = array_shift($stdin);
}
}
// Substitute `-` args
elseif ($dashes == 1) {
$args[array_search("-", $args, TRUE)] = $stdin;
}
// Just use as first param
else {
$args = array_merge([$stdin], $args);
}
}
#print_r($args);
#-- Run target function, capture result value
list($fref, $i_result) = reflect_args($func, $args);
#$func =$fref;
$r = $fref->invokeArgs($args);
if (is_int($i_result) && is_scalar($r) && !is_string($r)) {
$r = $args[$i_result];
}
var_dump($func, $args, $r);
#-- Output result
if (in_array($func, str_getcsv("print_r,print,var_dump")) && !is_string($r)) {
// as errno
exit(intval($r));
}
else {
// string or JSON struct
print (is_scalar($r) || is_null($r))
? strval($r)
: json_encode($r, JSON_PRETTY_PRINT);
}
// print PHP errors/warnings to STDERR
function stderr_color($errno, $errstr, $errfile=NULL, $errline=NULL, $errcontext=NULL) {
$errname = array_search($errno, get_defined_constants());
global $func;
fwrite(STDERR, "\x1b[31m$errname \x1b[0m(\x1b[32m$func\x1b[0m): \x1b[33m$errstr\x1b[0m\n");
}
// Apply & references, if one of the function parameters expects one, keep that as result parameter index
function reflect_args($func, & $args, $i_result=NULL) {
$fref = new ReflectionFunction($func);
foreach ($fref->getParameters() as $i => $param) {
if ($i < count($args)) {
$args[$i] = & $args[$i];
if ($param->isPassedByReference()) {
$i_result = $i;
}
}
}
return [$fref, $i_result];
}
?>