如何从PHP调用bash函数?

This is my workflow:

ubuntu$ cat test.sh
#!/bin/bash

function getNumber
{
    echo 1
}


ubuntu$ cat test.php
<?php

echo shell_exec("getNumber");



ubuntu$ source test.sh 
ubuntu$ getNumber 
1

ubuntu$ php test.php 
sh: 1: getNumber: not found

Is it possible to change a php script (or may be its call) the way, so it will print "1"? I am looking for a way to call a bash function from php.

I've tried some solutions from here: Is it possible to source a *.sh file using PHP CLI and access exported Env vars in the PHP script?

One of them was: ./test.sh && php -f test.php - but no luck.

Here's a function that does what you want. It loads spawns a bash process that sources the bash script, then runs the function.

It uses proc-open ( http://php.net/manual/en/function.proc-open.php )

<?php


$value = runBashFunction("test.sh", "getNumber");
var_dump($value);



function runBashFunction($bashfile, $bashfunction) {
    $descriptorspec = array(
         0 => array("pipe", "r"),    // stdin is a pipe that the child will read from
         1 => array("pipe", "w"),    // stdout is a pipe that the child will write to
         2 => array("pipe", "w") // stderr is a pipe too
    );

    $cwd = '.';
    $env = array();

    $process = proc_open('bash', $descriptorspec, $pipes, $cwd, $env);

    if (is_resource($process)) {
            fwrite($pipes[0], "source $bashfile
");
            fwrite($pipes[0], "$bashfunction
");
            fclose($pipes[0]);

            $output = stream_get_contents($pipes[1]);
            $error = stream_get_contents($pipes[2]);
            fclose($pipes[1]);
            fclose($pipes[2]);

            // It is important that you close any pipes before calling
            // proc_close in order to avoid a deadlock
            //

            $return_value = proc_close($process);
            //note, $error and $return_value are discarded
            return $output;
    }
    return null;
}
?>

In this particular example, you can combine the source command and the function itself into the same PHP exec call:

var_dump(
    shell_exec('source test.sh && getNumber')
); // string(2) "1
"

Trim the result if you need to to remove the carriage return.

Another approach is to pass the name of the function you would like to execute into the bash script.

test.sh is the bash script with the function you would like to execute:

#!/bin/bash

function getNumber
{
    echo "fnGetNumber"
}

# Test if the first parameter names a function
if [ "$(type -t $1)" = function ]; then
    $1
else
    echo "$1 is an invalid function"
fi;

test.php is the PHP script that will call the function:

#!/usr/bin/php
<?php
echo `./test.sh getNumber`;

Note that this requires you pass the name of the script as well as the function name.

Credit for function test to: https://stackoverflow.com/a/85903/2182349

If you would like to pass a parameter to the function, you may use:

Updated test.sh:

#!/bin/bash

function getNumber
{
    echo "fnGetNumber $1"
}

if [ "$(type -t $1)" = function ]; then
    $1 "$2"
else
    echo "$1 is an invalid function"
fi;

Updated test.php

<?php
$parm = 'toast';
echo `./test.sh getNumber $parm`;

I found an alternative solution. The problem was in Ubuntu and its dash

Running sudo dpkg-reconfigure dash and answering no changed dash to bash, what made source command available from php.

WAS: ls -la /bin/sh => /bin/sh -> dash

NOW: ls -la /bin/sh => /bin/sh -> bash

With enabled source, this worked fine: echo shell_exec('source /full/path/to/file/test.sh && getNumber abc def');

What helped me: https://stackoverflow.com/a/13702876/4621324

One Note: during the change Ubuntu has warned me: Using dash as the system shell will improve the system's overall performance. It does not alter the shell presented to interactive


As I don't really want to change dash to bash on the global level, I decided to go with this solution:

echo shell_exec('/bin/bash -c "source /full/path/to/file/test.sh && getNumber abc def"');