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.

Revisions

  1. divinity76 created this gist Oct 6, 2024.
    108 changes: 108 additions & 0 deletions functions.sh.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,108 @@
    #!/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();