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"');