Executing shell script using php - php

I have a shell script deploy.sh that has the following content:-
echo "0 Importing the code"
eval "git pull -u origin master"
echo "1 Backing up existing data in database.."
// -- other code follows here
When I execute the script directly using the terminal, I get the following output:-
0 Importing the code
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From bitbucket.org:user/repo
* branch master -> FETCH_HEAD
Updating db13xxx..6705xxx
1 Backing up existing data in database..
This is correct. However, I wrote a PHP script with which I can invole the deploy.sh script over http. Content of this php page is as follows:-
$output = `./deploy.sh`;
echo '<pre>', $output, '</pre>';
When I invoke this php file through the browser, the shell script is in fact getting invoked and I'm getting the following output:-
0 Importing the code
1 Backing up existing data in database..
The problem is that the eval "git pull -u origin master" command didnt get executed and its output is not shown. Any idea what the problem is?

This works
<?php
$output = shell_exec('sh deploy.sh');
echo "$output";
?>
Before that make sure that file has chmod 777 permission.

One thing you can do with the exec() function is to pass two optional values for more insight.
Here's some code I use to test shell scripts from a web interface.
<?php
require_once(__DIR__.'/../libs/Render.php');
error_reporting(E_ALL);
//Initialize and Run Command, with a little trick to avoid certain issues
$target='cd ../../your/relative/path && ./CustomScript.sh';
$outbuf=exec($target,$stdoutbuf, $returnbuf);
//Structure
$htm= new renderable('html');
$html->children[]= $head= new renderable('head');
$html->children[]= $body= new renderable('body');
$body->children[]= $out= new renderable('div');
$body->children[]= $stdout= new renderable('div');
$body->children[]= $returnout= new renderable('div');
//Value
$out->content= 'OUTPUT: '.$outbuf;
$stdout->content= 'STDOUT: '.var_export($stdoutbuf,true);
$returnout->content= 'RETURN: '.$returnbuf; //127 == Pathing problem
//Output
print_r($html->render());
?>
File is using the renderable class from the project I use this in, but you can put the string output wherever you are using it or echo/print_r() just as well. Also make sure you're not in safe mode by running phpinfo(); lots of folks having that issue.
Additionally, there's no reason you should avoid using shell scripts in PHP. PHP being a scripting language, it is quite thrifty at aggregating many shell scripts to allow higher-level administration.
PHP isn't only for 'web sites'. Even then, exposing administrative scripts to web interfaces is quite useful in and of itself; occasionally this is even a project requirement.

You should try to avoid running shell commands in php.
Having said that, try this:
$output = shell_exec('./deploy.sh');
echo "<pre>".$output."</pre>";
As per: http://www.php.net/manual/en/function.shell-exec.php

This is the correct code
<?php
$cmd = 'ifconfig'; // pass command here
echo "<pre>".shell_exec($cmd)."</pre>";
?>

Related

Open Linux terminal command in PHP

I have a server running on Linux that execute commands to 12 nodes (12 computers with Linux running in them). I recently downloaded PHP on the server to create web pages that can execute commands by opening a specific PHP file.
I used exec(), passthru(), shell_​exec(), and system(). system() is the only one that returns a part of my code. I would like PHP to act like open termainal command in linux and I cannot figure out how to do it!
Here is an example of what is happening now (Linux directly vs PHP):
When using linux open terminal command directly:
user#wizard:/home/hyperwall/Desktop> /usr/local/bin/chbg -mt
I get an output:
The following settings will be used:
option = mtsu COLOR = IMAGE = imagehereyouknow!
NODES = LOCAL
and additional code to send it to 12 nodes.
Now with PHP:
switch($_REQUEST['do'])
{ case 'test':
echo system('/usr/local/bin/chbg -mt');
break;
}
Output:
The following settings will be used:
option = mtsu COLOR = IMAGE = imagehereyouknow!
NODES = LOCAL
And stops! Anyone has an explanation of what is happening? And how to fix it? Only system displays part of the code the other functions display nothing!
My First thought is it can be something about std and output error. Some softwares dump some informations on std out and some in std error. When you are not redirecting std error to std out, most of the system calls only returns the stdout part. It sounds thats why you see the whole output in terminal and can't in the system calls.
So try with
/usr/local/bin/chbg -mt 2>&1
Edit:
Also for a temporary work through, you can try some other things. For example redirect the output to file next to the script and read its contents after executing the command, This way you can use the exec:
exec("usr/local/bin/chbg -mt 2>&1 > chbg_out");
//Then start reading chbg_out and see is it work
Edit2
Also it does not make sense why others not working for you.
For example this piece of code written in c, dumps a string in stderr and there is other in stdout.
#include <stdio.h>
#include<stdlib.h>
int main()
{
fputs("\nerr\nrro\nrrr\n",stderr);
fputs("\nou\nuu\nuttt\n",stdout);
return 0;
}
and this php script, tries to run that via exec:
<?php
exec("/tmp/ctest",&$result);
foreach ( $result as $v )
{
echo $v;
}
#output ouuuuttt
?>
See it still dumps out the stdout. But it did not receive the stderr.
Now consider this:
<?php
exec("/tmp/ctest 2>&1",&$result);
foreach ( $result as $v )
{
echo $v;
}
//output: errrrorrrouuuuttt
?>
See, this time we got the whole outputs.
This time the system:
<?php
echo system("/tmp/ctest 2>&1");
//output: err rro rrr ou uu uttt uttt
?>
and so on ...
Maybe your chbg -mt writes additional code to stderr instead of stdout? Try to execute your script inside php like this:
/usr/local/bin/chbg -mt 2>&1
The other responses are good for generic advice. But in this specific case, it appears you are trying to change your background on your desktop. This requires many special considerations because of 'user context':
First, your web server is probably running as a different user, and therefore would not have permissions to change your desktop.
Second, the program probably requires some environmental variables from your user context. For example, X programs need a DISPLAY variable, ssh-agent needs SSH_AGENT_PID and SSH_AUTH_SOCK, etc. I don't know much about changing backgrounds, but I'm guessing it involves D-Bus, which probably requires things like DBUS_SESSION_BUS_ADDRESS, KONSOLE_DBUS_SERVICE, KONSOLE_DBUS_SESSION, and KONSOLE_DBUS_WINDOW. There may be many others. Note that some of these vars change every time you log in, so you can't hard-code them on the PHP side.
For testing, it might be simpler to start your own webserver right from your user session. (i.e. Don't use the system one, it has to run as you. You will need to run it on an alternate port, like 8080). The web server you start manually will have all the 'context' it needs. I'll mention websocketd because it just came out and looks neat.
For "production", you may need to run a daemon in your user context all the time, and have the web server talk to that daemon to 'get stuff done' inside your user context.
PHP's system only returns the last line of execution:
Return Value: Returns the last line of the command output on success, and FALSE on failure.
You will most likely want to use either exec or passthru. exec has an optional parameter to put the output into an array. You could implode the output and use that to echo it.
switch($_REQUEST['do'])
{ case 'test':
exec('/usr/local/bin/chbg -mt', $output);
echo implode('\n', $output); // Could use <br /> if HTML output is desired
break;
}
I think that the result of execution, can changes between users.
First, try to run your PHP script directly into your terminal php yourScript.php
If it runs as expected, go to your Apache service and update it to run with your own credentials
You are trying to change the backgrounds for currently logged in users... While they are using the desktop. Like while I'm typing this message. I minimize my browser and 'ooh my desktop background is different'. Hopefully this is for something important like it turns red when the reactor or overheating.
Anyway to my answer:
Instead of trying to remotely connect and run items as the individual users. Setup each user to run a bash script (in their own account, in their own shell) on a repeating timer. Say every 10 minutes. Have it select the SAME file.. from a network location
/somenetworkshare/backgrounds/images/current.png
Then you can update ALL nodes (1 to a million) just by changing the image itself in /somenetworkshare/backgrounds/images/current.png
I wrote something a while ago that does just this -- you can run a command interpreter (/bin/sh), send it commands, read back responses, send more commands, etc. It uses proc_open() to open a child process and talk to it.
It's at http://github.com/andrasq/quicklib, Quick/Proc/Process.php
Using it would look something like (easier if you have a flexible autoloader; I wrote one of those too in Quicklib):
include 'lib/Quick/Proc/Exception.php';
include 'lib/Quick/Proc/Exists.php';
include 'lib/Quick/Proc/Process.php';
$proc = new Quick_Proc_Process("/bin/sh");
$proc->putInput("pwd\n");
$lines = $proc->getOutputLines($nlines = 10, $timeoutSec = 0.2);
echo $lines[0];
$proc->putInput("date\n");
$lines = $proc->getOutputLines(1, 0.2);
echo $lines[0];
Outputs
/home/andras/quicklib
Sat Feb 21 01:50:39 EST 2015
The unit of communication between php and the process is newline terminated lines. All commands must be newline terminated, and all responses are retrieved in units of lines. Don't forget the newlines, they're hard to identify afterward.
I am working on a project that uses Terminal A on machine A to output to Terminal B on Machine B, both using linux for now. I didnt see it mentioned, but perhaps you can use redirection, something like this in your webserver:
switch($_REQUEST['do'])
{ case 'test':
#process ID on the target (12345, 12346 etc)
echo system('/usr/local/bin/chbg -mt > /proc/<processID>/fd/1');
#OR
#device file on the target (pts/0,tty0, etc)
echo system('/usr/local/bin/chbg -mt > /dev/<TTY-TYPE>/<TTYNUM>');
break;
}
Definitely the permissions need to be set correctly for this to work. The command "mesg y" in a terminal may also assist...Hope that helps.

Live output of shell script using `watch` in browser?

I've seen PHP reading shell_exec live output and PHP: Outputting the system / Shell_exec command output in web browser, but can't get the following working.
NB: originally, my shell script was running some python, but I have simplified it.
live.sh
uname -a
date
watch --no-title date
live.php
<?php
$cmd = "sh live.sh";
while (# ob_end_flush()); // end all output buffers if any
$proc = popen($cmd, 'r');
echo '<pre>';
while (!feof($proc))
{
echo fread($proc, 4096);
# flush();
}
echo '</pre>';
?>
The uname and date outputs appear in the browser okay, but the watch output does not.
Am I in fact attempting the impossible?
I would advise against the approach of using watch, and you are probably in for more trouble than you expect.
Firstly, long running command might be affected by the (default) PHP timeout, so you may have to tweak that.
Then, watch probably uses terminal sequences to clear the screen, and I am not sure how this translates to the output code.
I would rather suggest setting up a client side mechanism to periodically repeat a call to the sever side live.php.
This post on SO will help you get started.
jQuery, simple polling example
the page above uses the jquery library, but you could use native Javascript equivalent if you want to.
The simplest example (from that page) would be :
function poll(){
$("live.php", function(data){
$("#output_container").html(data);
});
}
setInterval(function(){ poll(); }, 5000);
In your page, set up a container for your results
<div id="output_container"></div>
In your example, you remove the watch from your script and replace it with the command you intended watching.
You probably want this only for some special thing. So, for those you can try ajaxterm.
Really easy to use, (4.line installation)
wget http://antony.lesuisse.org/software/ajaxterm/files/Ajaxterm-0.10.tar.gz
tar zxvf Ajaxterm-0.10.tar.gz
cd Ajaxterm-0.10
./ajaxterm.py
and you will get full bash running interactively in the browser. (after the login/password). Written in python, so easily adaptible for you. Also, see here.

How to run a linux command to compile a c program, from php script

I am trying to make an online judge for c programming. When user enters the c code and submits it, my form redirects to judge.php which is the action file for the form.
Here is what I have written in judge.php
<?php
$text=$_POST['code'];
//echo $text;
$var_str = var_export($text, true);
file_put_contents('code.c', $text);
$ans=exec('pwd');
$ans= exec('gcc code.c');
echo $ans;
?>
I have captured user input in $text and wrote it to a c file(code.c). Till now, it is fine.
But exec(gcc code.c) is not working and not giving any output. I tried other linux commnads like pwd, date, etc. They are working fine. What may be the reason for this and how to fix it?
It is not a directory issue i tried exec(pwd) and it gave the output as the same directory in which code is present.
I tried to run same code.c file from terminal and it is running fine. So, it is also not a 'permission' problem.
One more thing, how to echo the error message generated if any exec() command is not working properly?
After getting suggestion from the answer below, i tried
$cmd="gcc -std=c99 code.c -g -Wall mysql_config --libs --cflags -o db_obj.o --pedantic";
exec($cmd,$out,$status);
But it is also not working. The status returned is 1
Most probably it is permission issue. "whoami" says nobody. Please tell how to change the owner from nobody to root or how to assign the permission to execute gcc from nobody
Three main aspects to my answer
improper use of the exec function.
Look at the man pages. First, the exec function's signature is:
string exec ( string $command [, array &$output [, int &$return_var ]] )
So exec can take up to 3 arguments. It returns the last line of the command's output, like the docs state quite clearly:
The last line from the result of the command. If you need to execute a command and have all the data from the command passed directly back without any interference, use the passthru() function.
To get the output of the executed command, be sure to set and use the output parameter.
So in your case:
$lastLine = exec($command, $fullOutput, $status);
Is what you're looking for. If $status is anything else than 0, your command was unsuccessful. That's what you should check to react accordingly.
The full output of any command can be found in $fullOutput as a line-per-line array.
Output like:
all went well
except for this
Will look like this in the $fullOutput array:
array('all went well', 'except for this');
permissions can be an issue, still.
You say permissions aren't likely to be the cause of the problem, because you can run gcc from the command-line. All fine and dandy, but what user is running the PHP script on the server?
In the case of web-servers, that user is often called nobody, apache or something, and that user is very likely not permitted to run gcc. It's PHP that runs a new instance of whatever default shell it has set up (bash, probably), and it's PHP's user that logs in to that shell, and it's that user that is calling gcc...
Know who you are, and what groups you belong to. Try adding this to your script:
echo 'Script is running under user: ', exec('whoami'), '<br>', PHP_EOL;
echo 'member of the following groups: ', exec('groups'), '<br>', PHP_EOL;
And before you ask: yes, those are comma's... no need to concatenate, you can pass multiple variables/values to echo, separated by a comma. It's actually faster (think of it as C++'s std::cout << some_var << another_var;)
general issues + security
This all said and done: compiling C code from a php script isn't as simple as you seem to think it is. Suppose I were to write this:
#include <stdio.h>
#include <time.h>
int main ( void )
{
time_t t = time(NULL);
if (t%2)
{
float val = (float) t/2.0;
//do stuff with float...
}
else
{
unsigned long long val = t/2;
//do stuff with unsigned long long...
}
}
Your gcc test.c command would fail, because you failed to pass the argument -std=c99, for example.
If I wanted a script to compile a given file, I'd also expect that script to allow me to choose which arguments I compiled my code with, too -g, -Wall and, not to mention: cflags and libs (the output of pkg-config or mysql_config --cflags --libs, to name a specific example I recently used).
Basically, your script simply cannot deal with my wanting to compile something with a commind like
gcc -std=c99 code.c -g -Wall `mysql_config --libs --cflags` -o db_obj.o --pedantic
Which still is a simplified version of what many compilation commands look like, especially when debugging code under development. For stable releases, you'd probably drop -g and --pedantic, but you get my point...
Just think of what it means, allowing the user to pass a set of cli arguments, along with the code. They might pass an argument like -DSOME_MACRO or -O0, which means they might also pass -O0 && rm -Rf *. That means you'll have to call escapeshellcmd or escapeshellarg. Both of which will prohibit me from passing a valid argument, being:
`mysql_config --libs --cflags`
Which contains back-ticks, and thus will be escaped.
To be frank, I struggle to see the point of this exercise... and I'm leaving a lot out, still: the dangers of compiling (let alone running) user-provided code on your machine, for example, are not to be overlooked. You can't just compile code, and run it on your server: memory leaks, segfaults... heck, pure evil code is all getting compiled on your server unchecked if this is the code you have. Really, save yourself a lot of tears, and include an iframe that loads codepad or some similar service...
Recap:
always check the man for a function, see if you're getting all information it returns
check the permissions and runtime for the user that is actually executing the commands
Never trust the network, don't blindly assume people will submit valid, harmless code for you to compile.
Don't reinvent the wheel: compilation services exist, just forward those (but ask for permission first)
Try this code to execute c program from PHP file
<?php
// used to compile the c file using exec() in php
exec('gcc helloworld.c -o helloworld', $out, $status);
if (0 === $status) {
var_dump($out);
// used to execute the c file using exec() in php
exec('./helloworld', $out, $status);
if (0 === $status) {
var_dump($out);
} else {
echo "Command failed with status: $status";
}
} else {
echo "Command failed with status: $status";
}
?>

retrieve R output in PHP

Here's the issue:
I am using R to run some statistical analysis. The results of which will eventually be sent to a an embedded swf on the user's client machine.
To do this, I have PHP execute a shell script to run the R program, and I want to retrieve the results of that program so I can parse them in PHP and respond with the appropriate data.
So, it's simply:
$output = shell_exec("R CMD BATCH /home/bitnami/r_script.R");
echo $output;
But, I receive nothing of course, because R CMD BATCH writes to a file. I've tried redirecting the output in a manner similar to this question which changes my script to
$output = shell_exec('R CMD BATCH /home/bitnami/raschPL.R /dev/tty');
echo $output;
But what I get on the console is a huge spillout of the source code, and nothing is echoed.
I've also tried this question's solution in my R script.
tl;dr; I need to retrieve the results of an R script in PHP.
Cheers!
If it writes to file perhaps you could use file_get_contents to read it?
http://php.net/manual/en/function.file-get-contents.php
Found it, the answer is through Rscript. Rscript should be included in the latest install of R.
Using my code as an example, I would enter this at the very top of r_script.R
#!/usr/bin/Rscript --options-you-need
This should be the path to your Rscript executable. This can be found easily by typing
which Rscript
in the terminal. Where I have --options-you-need, place the options you would normally have when doing the CMD BATCH, such as --slave to remove extraneous output.
You should now be able to run your script like so:
./r_script.R arg1 arg2
Important! If you get the error
Error in `contrasts<-`(`*tmp*`, value = "contr.treatment") :
could not find function "is"
You need to include the "methods" package, like so:
require("methods");
Perhaps,a much simpler workaround, would be:
$output = shell_exec('R CMD BATCH /home/bitnami/raschPL.R > /dev/tty 2>&1');
echo $output;
Redirects both STDOUT and STDERR, since R outputs to STDERR, by default.

issuing things to shell and forgetting about it in php

how do you issue commands to the shell and then forget it's output and such? for example:
<?php
echo `sleep 2;echo hi`;
echo "foo";
?>
the result for this is hifoo. i would want a result that gives me foohi. why? i want the command issued to the shell simply issued and forgotten, i am confused about why PHP will wait for the result. is such a result possible?
(the idea behind this is setting up the correct number of selenium grid RC instances programatically. currently, it will stop after the first process is opened)
From php.net exec()
If a program is started with this
function, in order for it to continue
running in the background, the output
of the program must be redirected to a
file or another output stream. Failing
to do so will cause PHP to hang until
the execution of the program ends.
The same applies for all shell commands.
It's like anything you do at the command prompt, unless you take measures to put the new command in the background, the shell (and PHP ) will block until the command exits. Try this:
<?php
echo `(sleep 2; echo hi) &`;
echo 'foo';
?>
Note the brackets around your command, without that, the & woulud apply only to the echo , and you'd still have the 2 second pause.

Categories