Skip to content

Instantly share code, notes, and snippets.

@divinity76
Created October 6, 2024 22:54
Show Gist options
  • Save divinity76/83b004dce67e16c51bb40a0e4f08cf51 to your computer and use it in GitHub Desktop.
Save divinity76/83b004dce67e16c51bb40a0e4f08cf51 to your computer and use it in GitHub Desktop.
PHP bash glue (run php functions in bash)
#!/usr/bin/php
<?php
// how to include these bash functions in a bash script:
// eval "$(/usr/bin/php /path/to/functions.sh.php)";
declare(strict_types=1);
function quote($str)
{
if (str_contains($str, "\x00")) {
throw new \LogicException("null byte found in string");
}
return "'" . str_replace("'", "'\\''", (string)$str) . "'";
}
function echo_stderr(...$args)
{
ob_start();
foreach ($args as $arg) {
echo $arg;
}
$output = ob_get_clean();
fwrite(STDERR, $output);
}
$bash_functions = array(
'test_php_to_bash_function' => function ($arg1, $arg2, ...$variadic_arguments) {
echo "this function just test the bash<->php glue\n";
var_dump(["arguments" => func_get_args(), "variadic_arguments" => $variadic_arguments]);
echo "return value will be 99\n";
return 99;
},
'validate_int' => function ($int, ...$variadic_arguments) {
$max = null;
$min = null;
foreach($variadic_arguments as $argument) {
if(str_starts_with($argument, "max=")) {
$max = (int)substr($argument, strlen("max="));
} elseif(str_starts_with($argument, "min=")) {
$min = (int)substr($argument, strlen("min="));
} else {
echo "validate_int: unknown argument: ";
var_dump($argument);
echo "valid arguments: max=X, min=X\n";
return 1;
}
}
$validated = filter_var($int, FILTER_VALIDATE_INT);
if ($validated === false) {
echo "not a valid integer: ";
var_dump($int);
return 1;
}
if ($max !== null && $validated > $max) {
echo "integer too large: $validated > $max\n";
return 1;
}
if ($min !== null && $validated < $min) {
echo "integer too small: $validated < $min\n";
return 1;
}
return 0;
},
);
// start bash<->php glue...
if (isset($argv[1])) {
// execute the requested function
$function_name = $argv[1];
if (!isset($bash_functions[$function_name])) {
echo_stderr("bash-php function $function_name not found\n");
echo_stderr("available bash-php functions: " . implode(", ", array_keys($bash_functions)) . "\n");
exit(1);
}
$arguments = array_slice($argv, 2, preserve_keys: false);
$return_value = ($bash_functions[$function_name])(...$arguments);
exit($return_value);
}
// no function requested, generate bash<->php functions glue
ob_start();
foreach ($bash_functions as $function_name => $php_callback) {
echo "function $function_name() {\n";
$reflection = new ReflectionFunction($php_callback);
$parameters = $reflection->getParameters();
$is_variadic = $reflection->isVariadic();
$named_arguments = [];
foreach ($parameters as $param) {
$param_name = $param->getName();
if ($param->isVariadic()) {
// not naming this one, variadic arguments are generically passed as "$@"
} else {
$named_arguments[] = $param_name;
}
}
foreach ($named_arguments as $argument_index => $param_name) {
$index1 = $argument_index + 1;
echo "\tlocal $param_name=\"\${$index1}\"\n";
}
if ($is_variadic) {
echo "\tshift " . count($named_arguments) . "\n";
}
echo "\t/usr/bin/php " . quote(__FILE__) . ' ' . quote($function_name);
foreach ($named_arguments as $param_name) {
echo ' ' . "\"\${$param_name}\"";
}
if ($is_variadic) {
echo ' "$@"';
}
echo "\n";
echo "\treturn \$?\n";
echo "}\n";
}
ob_end_flush();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment