PHP shell_exec() unable to run part of shell script - php

I have encountered a strange problem. I have created a gitlab custom webhook. The webhook service is written in php (gitlab.php). The php script, when called with proper payload, should start an automated deployment. The deployment script is basically a shell script (deploy.sh)
Code of gitlab.php
<?php
$json = file_get_contents('php://input');
// Converts it into a PHP object
$data = json_decode($json, true);
$secret = "";
foreach (getallheaders() as $name => $value) {
if($name=='X-Gitlab-Token') {
$secret = $value;
}
}
if($secret=="mysecretcode" && $data['object_kind']=="push") {
file_put_contents("/opt/lampp/htdocs/autodeploy/autodeploy.log", "Webhook auto deployment started at ". date("Y-m-d H:i:s") . "\n". shell_exec("sh /opt/lampp/htdocs/autodeploy/deploy.sh")."\n**********************************************\n\n", FILE_APPEND);
die("Deployment success");
}
else {
die("Auth token invalid or no triggerable event found");
}
?>
Code of deploy.sh
#!/bin/bash
cd "/opt/lampp/htdocs/nodejs/myapp"
echo "Stopping application..."
forever stop index.js
cd ..
sudo rm -rf myapp
echo "Pulling latest code from gitlab..."
git clone -b "master" https://myusername%40domain.com:MyEncodedPass123#gitlab.com/myusername/myapp.git
cd myapp
echo "Installing dependencies..."
npm install
echo "Starting application..."
forever start index.js
echo "Application started on port 3000."
When I push code to gitlab, it triggers the webhook and initiates the deployment process and I see my webhook file gitlab.php returned success response to Gitlab and has written following output in autodeploy.log file
Webhook auto deployment started at 2021-10-03 13:32:07
Stopping application...
Pulling latest code from gitlab...
Installing dependencies...
Starting application...
Application started on port 3000.
**********************************************
But, the deployment actually never happens. It just runs the echo statements (and may be cd, rm etc as well) and rest of the shell commands are kind of ignored or not executed. It for sure doesn't run the git clone command, because I do not see latest code getting refreshed on my server from gitlab. Not sure though what happens to the npm and forever commands.
By the way, this is a Ubuntu VPS server with latest ApacheFriends XAMPP server installed, php v8. All the three files mentioned above reside at the same path i.e. /opt/lampp/htdocs/autodeploy and my deploy.sh script tries to deploy a separate nodejs application in /opt/lampp/htdocs/nodejs/myapp folder. Strangely enough, when I run deploy.sh directly from terminal it deploys the latest code successfully. Which means, all the statements in the script gets executed as expected. It only fails when executed from the php script using shell_exec() function.
Any clue what could be the reason?

The documentation for shell_exec doesn't state it clearly, but chances are you only get the stdout of your command, not its stderr -- the first comment certainly seems to indicate that, it would also match the "it's the same thing as backtick" decription.
If such is the case, you simply don't have the error messages in your output.
Try running :
shell_exec("sh .../deploy.sh 2>&1")
I also second #phd's suggestion (in the comments to your question) : turn set -e on, at least your script will halt when you get an error.
Chances are your current script would fail at the first line : cd "/opt/lampp/htdocs/nodejs/myapp".
I also strongly advise to drop the sudo in sudo rm -rf ....

Related

Use PHP over HTTP to run background bash with trap on exit

I'm trying to use PHP to trigger a bash script that should never stop running. It's not just that the command needs to run and I don't need to wait for output, it needs to continue running after PHP is finished. This has worked other times (and the question has been asked already), the difference seems to be my bash script has a trap for when it's closed.
Here is my bash script:
#!/bin/bash
set -e
WAIT=5
FILE_LOCK="$1"
echo "Daemon started (PID $$)..."
echo "$$" > "$FILE_LOCK"
trap cleanup 0 1 2 3 6 15
cleanup()
{
echo "Caught signal..."
rm -rf "$FILE_LOCK"
exit 1
}
while true; do
# do things
sleep "$WAIT"
done
And here is my PHP:
$command = '/path/to/script.sh /tmp/script.lock >> /tmp/script.log 2>&1 &';
$lastLine = exec($command, $output, $returnVal);
I see the script run, the lock file get created, then it exits, and the trap removes the lock file. In my /tmp/script.log I see:
Daemon started (PID 55963)...
Caught signal...
What's odd is that this only happens when running the PHP via Apache. From command line it keeps running as expected.
The signal on the trap that's being caught is 0.
I've tried wrapping my command in a bash environment, like $command = '/bin/bash -c "' . addslashes($command) . '"';, also tried adding nohup to the beginning. Nothing seems to be working. Is this possible to do for a never ending script?
Found the problem thanks to #lxg.
My # do things command was giving errors, which was causing the script to exit. For some reason they were suppressed.
When removing set -e from the beginning of my bash script I started seeing the errors output to my log file. Not sure why they didn't show up before.
The issue was in my bash loop it was running PHP commands. Even though my bash user and Apache user are the same, for some reason they had different $PATHs. This meant that when running on command line I was using a PHP7 binary, but when Apache trigged bash commands it was using a PHP5 binary (even though Apache itself is configured to use PHP7). So the application errored out and that is what caused the script to die.
The solution was to explicitly set the PHP binary path in my bash loop.
I was doing this with
BIN_PHP=$(which php)
But on true command line it would return one value (/path/to/php7/bin/php) vs command line initiated by Apache (/path/to/php5/bin/php). Despite Apache being the same as a my command line user, it didn't load the ~/.bashrc which specified my correct PHP path.

Run docker in shell using PHP

Well, I need to run a Docker using a PHP function. I have a web page where pushing a link I execute a shell order using shell_exec or exec. This works for me if the execution is like an ls or something that expects a result. The problem is that if the command is to run the Docker (or for example a ping) it doesn't work.
What I want is when the user clicks the link, the shell will execute a command to run Docker in the browser, and the page will be redirected there.
For exemple, if I use shell_exec('firefox'); this should open a new firefox browser, but it doesn't work. It seems that the browser is opened but few seconds later is closed.
This is the Docker execution that doesn't work.
public function executeDocker() {
$result = shell_exec('docker run --rm -p 3838:3838 shiny/gsva_interactive /usr/bin/shiny-server.sh');
echo "<br><br>Execution: ".$result;
}
shell_exec will only return the output of a, in this case Docker, command only when the command has exited completely. In the case of ping (it will just keep pinging) and probably in the case of your Docker image, the process will never exit by itself, so it will never give a response.
Using passthru instead of shell_exec should give you the commandline output of your Docker script right back as a response.
If the Docker container is not meant to exit you should probably start it in detached mode with $containerId = shell_exec('docker run -d --rm -p 3838:3838 shiny/gsva_interactive /usr/bin/shiny-server.sh'), so the docker run command will exit. This will return the container id, which you can use with $result = shell_exec("docker ps -f \"id=$containerId\"") to check if the container is running correctly and redirect the user if it is.
i was having the same issue running docker exec via shell_exec.
shell_exec('docker exec -it containerid /usr/bin/cmd);
Getting rid of the -i option worked for me.
Finally I solved it. The problem was in the user group and permissions. In the system that I was using, CentOS, apache server uses a user called apache. This user needs to be in the docker group and reboot the services.
Now it works. Thanks to everyone who helped me.

php shell_exec and hg pull

I have written simple php script to help me update site contents when the commit is sent to bitbucket. I have following problem with it.
<?php
$repo_dir = '/var/www/vhosts/my_full_path';
$output = shell_exec('cd '.$repo_dir.' && hg --config auth.rc.prefix=https://bitbucket.org/XXXXX --config auth.rc.username=my_username --config auth.rc.password=my_pass pull -u https://bitbucket.org/XXXXXXX &');
echo $output;
?>
When I type it to web browser it doesn't work. The output of script is:
pulling from https://bitbucket.org/XXXXXXXXXXXXXX
but when I try to execute it under console on the server it works like a charm:
php myscript.php
generates following output:
pulling from https://bitbucket.org/XXXX
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 1 files
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
See the oupt is full and correct! in concole I'm using root user in web browser data-www? Is there any difference in this case?
I have found the solution. I hope it helps someone.
There were two problems:
Permissions to my repo dir
Authentication for user www-data for this repo
The problem occured because web browser doesn't flush warnings and abort messages while executing command shell_exec. If you want to test your script, you have to lgoin to console by SSH (as root for example) then execute script / command as apache user:
sudo -u www-data php /path-to-your-script/script.php
In console you will see all problems which following user generates.

PHP calls to git command via system(), fails with exit code 128

CentOS 5.9, PHP 5.4.21, Tomcat 7.0.42, Safe mode is off.
I need to commit some code to repository from php. but failed with exit code 128.
Codes are below, and command_exec is 'cd /data/project && git add .'
ob_start();
$this->system_call_detail = system($this->command_exec, $this->output);
$logger->debug('ExecuteCMD system call result : '.$this->system_call_detail);
ob_end_clean();
I can run git command as the apache user account from cmd, but programs run from PHP fail with exit code 128.
I guessed this cause from PHP. So, I tried this git command, "php -r 'system("cd /data/project && git add .", $test); echo $test;'" from cmd as apache user account and it success.
I solved this problem..
First, I couldn't get contents when run command, because of some php bug(?).
http://kr1.php.net/manual/en/function.system.php#108713
I fixed the command belows:
$this->system_call_detail = system($this->command_exec.' 2>&1', $this->output);
and then, I could get error msgs belows:
fatal: unable to access '/home/{username}/.config/git/config': Permission denied
But, there were no such files or directory.
So, I googled with the error msgs. and found some blog.
http://www.jethrocarr.com/2013/08/25/the-apache-that-wanted-to-be-root/
And I edited '/etc/sysconfig/httpd' file with the blogs posted.
And Solved. :)
Thank for helping me.
deceze and ojrask

How to push git from php using exec()

Here is my push.bat file
echo "Hello world!"
cd abhishek3/
call git add .
call git commit -m "sadf"
call heroku accounts:set abhishek84
call git push heroku master
I am able to push to my repository by running push.bat file in cmd
I want to push to my repo from php, tried following snippets but none of them worked for me.
exec("psexec -d push.bat");
Result: PHP page loads indefinitely
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C abhishek3.bat, 0, false);
Result: Page stops loading after a while and nothing works
exec("cmd.exe /c abhishek3.bat")
Result: Page stops loading after a while and nothing works
EDIT:
Tried the following snippet but nothing worked.
exec("hstart.exe /NOCONSOLE \"cmd.exe /c \"abhishek3.bat\"\"");
The above snippet runs successfully when run from cmd but when run from php through exec() didn't worked. Download hstart (Hidden Start Binary)
check the permissions for the web users are correct (It can access the files and execute git)
check the path for git and any environment variables it may need. You may have to set those environment variables in your script and use absolute paths)
check IIS or apache (whichever you are using) is allowed to execute programs in general and bat files (for example if it is apache, you may have to configure httpd.conf or htaccess depending on your configuration)

Categories