PHP: cannot run nested shell scripts - php

I hope you can help me.
I am dealing with a problem that I cannot solve. This is my issue. I am trying to exec a bash script through PHP. I tried with the method
exec()
with 3 arguments, arg1, arg2, and arg3.
php code
<?php exec("./randomScript.sh arg1 arg2 arg3"); ?>
randomScript.sh
.... # random code which exploits the three arguments -> executed normally..
.... # random code which exploits the three arguments -> executed normally..
./secondScript.sh $arg1 $arg2 $arg3 #<- this is the script that is not running (is not even started).
I have tried to change the permission (I've got full permission), change the way I call the randomScript.sh (through absolute path), but nothing occurred. Besides, I tried with:
shell_exec()
method, but nothing changed. Of course, if I run the secondScript.sh via terminal everything works fine.
I cannot understand which is the problem. Could you please help me?
Thanks in advance.

In the inner shell, the arguments are not called like that (because it is invoked by the shell, not by PHP).
./secondScript.sh "$1" "$2" "$3"
or just
./secondScript.sh $*
At this stage, just remember that spaces, quotes, and dollar signs in the arguments you pass must be avoided at all costs (the solution is escaping them, but how to do it exactly is tricky).
You also might want to do instead:
$ret = shell_exec("./randomScript.sh 'arg1' 'arg2' 'arg3' 2>&1");
so that in $ret you might find error messages and output from the inner shell.

You should escape your string command before passing it in exec function, i think it may help you
Escapeshellcmd()
...
$escaped_command = escapeshellcmd("./randomScript.sh arg1 arg2 arg3");
exec($escaped_command);
...
Escapeshellarg()
For system command, i recommand using system
...
$escaped_command = escapeshellarg("./randomScript.sh arg1 arg2 arg3");
system($escaped_command);
...

You also need to make sure that your PHP code does not change working dir, and both shell scripts have execute permissions, and filesystems allows to exec files on it.
I would avoid exec("./script $arg ...");, I would rather specify the interpreter to use and full path to the script like exec("sh /home/user/project/script.sh $arg ...");

Related

How can you use the "*" path wildcard via PHP exec() as part of a `cp` or `ls` command?

I just cannot fathom how to get the PHP exec() or shell_exec() functions to treat a '*' character as a wildcard. Is there some way to properly encode / escape this character so it makes it through to the shell?
This is on windows (via CLI shell script if that matters, Terminal or a git-bash yields the same results).
Take the following scenario:
C:\temp\ contains a bunch of png images.
echo exec('ls C:\temp\*');
// output: ls: cannot access 'C:\temp\*': No such file or directory
Permissions is not the problem:
echo exec('ls C:\temp\exmaple.png');
// output: C:\temp\example.png
Therefore the * character is the problem and is being treated as a literal filename rather than a wildcard. The file named * does not exist, so from that point of view, it's not wrong...
It also does not matter if I use double quotes to encase the command:
echo exec("ls C:\temp\*");
// output: ls: cannot access 'C:\temp\*': No such file or directory
I have also tried other things like:
exec(escapeshellcmd('ls C:\temp\*'));
exec('ls C:\temp\\\*');
exec('ls "C:\temp\*"');
exec('ls "C:\temp\"*');
And nothing works...
I'm pretty confused that I cannot find any other posts discussing this but maybe I'm just missing it. At this point I have already worked around the issue by manually programming a glob loop and using the internal copy() function on each file individually, but it's really bugging me that I do not understand how to make the wildcard work via shell command.
EDIT:
Thanks to #0stone0 - The answer provided did not particularly answer my initial question but I had not tried using forward slashes in the path and when I do:
exec('ls C:/temp/*')
It works correctly, and as 0stone0 said, it only returns the last line of the output, which is fine since this was just for proof of concept as I was not actually attempting to parse the output.
Also, on a side note, since posting this question my system had been updated to Win11 22H2 and now for some reason the original test code (with the backslashes) no longer returns the "Cannot access / no file" error message. Instead it just returns an empty string and has no output set to the &$output parameter either. That being said, I'm not sure if the forward slashes would have worked on my system prior to the 22H2 update.
exec() only returns the last output line by default.
The wildcard probably works, but the output is just truncated.
Pass an variable by ref to exec() and log that:
<?php
$output = [];
exec('ls -lta /tmp/*', $output);
var_dump($output);
Without any additional changes, this returns the same as when I run ls -lta /tmp/* in my Bash terminal
That said, glob() is still the preferred way of getting data like this especcially since
You shouldn't parse the output of ls

How to pass the string from php to tcl and execute the script

I want to pass the string from my php like
<?php
str1="string to pass"
#not sure about passthru
?>
And my tcl script
set new [exec $str1]#str1 from php
puts $new
Is this Possible? Please let me know I'm stuck with this
The simplest mechanism is to run the Tcl script as a subprocess that runs a receiving script (that you'd probably put in the same directory as your PHP code, or put in some other location) which decodes the arguments it is passed and which does what you require with them.
So, on the PHP side you might do (note the important use of escapeshellarg here! I advise using strings with spaces in as test cases for whether your code is quoting things right):
<?php
$str1 = "Stack Overflow!!!";
$cmd = "tclsh mycode.tcl " . escapeshellarg($str1);
$output = shell_exec($cmd);
echo $output;
echo $output;
?>
On the Tcl side, arguments (after the script name) are put in a list in the global argv variable. The script can pull them out with any number of list operations. Here's one way, with lindex:
set msg [lindex $argv 0]
# do something with the value from the argument
puts "Hello to '$msg' from a Tcl script running inside PHP."
Another way would be to use lassign:
lassign $argv msg
puts "Hello to '$msg' from a Tcl script running inside PHP."
Note however (if you're using Tcl's exec to call subprograms) that Tcl effectively automatically quotes arguments for you. (Indeed it does that literally on Windows for technical reasons.) Tcl doesn't need anything like escapeshellarg because it takes arguments as a sequence of strings, not a single string, and so knows more about what is going on.
The other options for passing values across are by environment variables, by pipeline, by file contents, and by socket. (Or by something more exotic.) The general topic of inter-process communication can get very complex in both languages and there are a great many trade-offs involved; you need to be very sure about what you're trying to do overall to pick an option wisely.
It is possible.
test.php
<?php
$str1="Stackoverflow!!!";
$cmd = "tclsh mycode.tcl $str1";
$output = shell_exec($cmd);
echo $output;
?>
mycode.tcl
set command_line_arg [lindex $argv 0]
puts $command_line_arg

PHP exec command not having an $output but $return is 0

This is my code for executing a command from PHP:
$execQuery = sprintf("/usr/local/bin/binary -mode M \"%s\" %u %s -pathJson \"/home/ec2/fashion/jsonS/\" -pathJson2 \"/home/ec2/fashion/jsonS2/\"", $path, $pieces, $type);
exec($execQuery, $output, $return);
the $return value is always 0 but $output is empty. The $output should be a JSON.
If I execute the same but removing one letter to binary (for example /usr/local/bin/binar ) I get (correctly) a $return = 127.
If I write other parameters (like -mode R which doesn't exit) I got errors from the console (which are correct as well).
If I run the exact $execQuery (which I printf before to be sure about quotation marks) on the console, it executes correctly. It's only the PHP side where I've got the error.
What can be wrong?
Thank you in advance.
Well, a couple of things might be happening...
This binary you're running write to something else that STDOUT (for instance, STDERR)
The env vars available to the PHP user differ from the env vars available to the user running console (and those vars are required)
PHP User does not have permission to access some files involved.
In order to debug, it might be better to use proc_open instead of exec, and check the STDOUT and STDERR. This might give you additional information regarding what's happening.
Suggestion (and shameless advertising)
I wrote a small utility library for PHP that executes external programs in a safer way and provides aditional debug information. It might help you to, at least pinpoint the issue.

How to pass PHP or JavaScript variables to Windows cmd.exe

I have a VBScript (.vbs) file on my Windows 7 machine. To run that *.vbs file , I have to execute it from cmd by passing arguments. Ex( *.vbs arg1 arg2 arg3).
I want to run this *.vbs file from PHP or JavaScript. But arguments should be through variables. Ex ($a=arg1; $b=arg2; $c=arg3;) and then use this variable to pass to that .vbs. Ex(.vbs $a $b $c). How to do it, from JavaScript or PHP.
You have a couple of options with PHP. You could use exec() or system(). I would also recommend using escapeshellarg() prior to passing in any user inputted values.
Links:
http://php.net/manual/en/function.exec.php
http://php.net/manual/en/function.system.php
http://php.net/manual/en/function.escapeshellarg.php
I don't know if you're aware of this already, but on some Windows servers (read: all windows servers), unless you run the Apache service as an actual executable, it will not be allowed to directly interact with your desktop.
That being said, use exec(), or simply put your query in backticks, like this:
$query = `cmd.exe`;
You can use :
exec() function and write the command in it.
Or enclose the cmd command you want to execute inside `` (back tick) operator.
Example:
$cmd=`xyz.vb $a $b $c`
The $cms variable will have the output of the script.
<?php
$fname="C:/sendemail.vbs";
$id="vkvk1993#gmail.com";
$h="hi";
$s="hhhhhhhhhha";
$q="$fname $id $h $s";
if(exec($q));
echo "Done";
?>

How to run Java program and get output in PHP?

I'd like to run something like (in myProgram.sh):
java -cp whatever.jar com.my.program $1
within PHP and read the output.
So far I have something like:
$processOrderCommand = 'bash -c "exec nohup setsid /myProgram.sh ' . $arg1 . ' > /dev/null 2>&1 &"';
exec($processOrderCommand);
But what I'd really like is to be able to get the output of the java program within the PHP script and not just execute it as another thread.
How can this be done?
You can do this :
exec($processOrderCommand, $output);
From the documentation :
If the output argument is present, then the specified array will be filled with every line of output from the command. Trailing whitespace, such as \n, is not included in this array. Note that if the array already contains some elements, exec() will append to the end of the array. If you do not want the function to append elements, call unset() on the array before passing it to exec().
For a better control on your execution you can take a look at proc_open()
Resources :
php.net - exec()
php.net - proc_open()
The key is that the classpaths need to be absolute within the shell_exec
PHP script.
Or at least that's the only way I could get it to correctly work. Basically it's almost impossible to tell from environment to environment what the relative directory is that the php script is running the JVM.
As well, it helped to put the absolute path location for java, such as usr/.../bin/java

Categories