php shell_exec triggers a job twice - php

There is an issue I couldn't find the exact problem, or is it a problem anyway I don't know.
I execute below command through shell_exec in php. I'm user I called just once.
curl -o ./server.log --request POST 'crawlserver.xxx.local/workerCallback.php' --user-agent 'xxx' --data 'workerid=worker1&jobid=25&offercount=72&file='/path/to/xxx-2014-02-07-serialized.txt'
this command working like 30 seconds.
while when I ask to bash as ps aux | grep workerCallback
I see 2 different commands triggered, and different process ids. But when look to server.log file it is looking a single request, also I check db and other stuff, the request worked single. But why it is looking twice in commandline by different pids, and commands has little differences. What is the "sh -c" before the command.
1000 27384 0.0 0.0 4404 612 ? S 14:00 0:00 sh -c curl -o ./server.log --request POST 'crawlserver.xxx.local/workerCallback.php' --user-agent 'xxx' --data 'workerid=worker1&jobid=25&offercount=72&file=path/to/xxx-2014-02-07-serialized.txt'
1000 27385 0.0 0.0 88056 3756 ? S 14:00 0:00 curl -o ./server.log --request POST crawlserver.xxx.local/workerCallback.php --user-agent xxx --data workerid=worker1&jobid=25&offercount=72&file=/path/to/xxx-2014-02-07-serialized.txt

Its not the same command twice, the first command is the shell (sh) running your curl command.
The second one is the command itself.
So your code is working fine :)

Related

Incorrect Webpage Output for PHP exec running bash script for audtool (part of Audacious)

On a local linux server (Rapsberry Pi debian stretch with desktop), I am working on sending "audtool" commands to a running Audacious media player using php, exec and bash scripts. Audacious is autostarted when the server starts up with user "pi". I have apache2 and php set up and working on the server, and I can ssh to the server and run all the commands from the cli. I believe I have resolved the issues with running audtool (dbus and setting the right environment variables) and running the php on the command line works successfully. However when running the php on a webpage I get back a long string of information about apache2
I have spent several hours (getting on for a whole day) researching this on the web in order to get to this stage, so close I can almost touch it, but stuck on this last element. The example is to display the current song from a running instance of Audacious. Audtool requires a running dbus (looks for a display). Using exec or shell_exec I have no problems running bash commands such as whoami or ls.
The php page (cursong.php):
<?php
echo exec('/var/www/html/cursong.sh');
?>
The bash script (cursong.sh):
#!/bin/bash
##call current song
pid=`pidof audacious`
user=`ps -p $pid -o user=`
export `strings /proc/$pid/environ | grep DBUS_SESSION_BUS_ADDRESS`
sudo -E -su $user /usr/bin/audtool --current-song
(from here: https://redmine.audacious-media-player.org/boards/1/topics/1058?r=1059)
Output from command line:
php -f cursong.php
Artist - Song Title (for example - so this works)
Output on webpage:
declare -x APACHE_LOCK_DIR="/var/lock/apache2" declare -x
APACHE_LOG_DIR="/var/log/apache2" declare -x
APACHE_PID_FILE="/var/run/apache2/apache2.pid" declare -x
APACHE_RUN_DIR="/var/run/apache2" declare -x APACHE_RUN_GROUP="www-
data" declare -x APACHE_RUN_USER="www-data" declare -x
INVOCATION_ID="4ce76136ca8842bd9108d6b1b9a5b9ed" declare -x
JOURNAL_STREAM="8:23896" declare -x LANG="C" declare -x OLDPWD
declare -x
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/var/www/html" declare -x SHLVL="1"
I have set www-data, the apache2 user with the following in
/etc/sudoers:
www-data ALL=NOPASSWD: ALL
and /var/www/html is rwx for anyone
Obviously, I am expecting to see "Artist - Song Title" on the webpage, but instead I get back all the apache2 info. What am i missing, or where have I gone wrong?
I hate answering my own question, makes it look like I wasn't trying hard enough! After a further five hours or so of searching around and attempting fixes, I happened upon this post on SO:
Running command-line application from PHP as specific user
which suggested putting a "sudo -u user" in the exec of the php file. I tried this with the "pi" user and it still didn't work, then I simply tried it with "sudo" and hey presto!!
The php file now looks like this:
<?php
echo shell_exec('sudo /var/www/html/cursong.sh 2>&1');
?>
Now to do some testing on how it works with the other audtool commands that don't ask for a response but require action from audacious, and to see how I can reduce scripting php files by passing a parameter to the bash script!
Just for completeness, the php and bash scripts for both a request and an action, using a parameter fed to the php url and then on to the bash script:
PHP File with Parameter
<?php
$request = $_GET["request"];
echo shell_exec("sudo /var/www/html/cursong.sh \"${request}\" 2>&1");
?>
url example:
http://192.168.1.92/cursong.php?request="--playlist-shuffle-status"
Bash Script with parameter
#!/bin/bash
##call request
pid=`pidof audacious`
user=`ps -p $pid -o user=`
export `strings /proc/$pid/environ | grep DBUS_SESSION_BUS_ADDRESS`
sudo -E -su $user /usr/bin/audtool $1
PHP file for an action
<?php
$action = $_GET["action"];
shell_exec('sudo /var/www/html/playsong.sh \"${request}\" ');
?>
url example:
http://192.168.1.92/cursong.php?action="--playback-play"
Bash script for an action
#!/bin/bash
##call action
pid=`pidof audacious`
user=`ps -p $pid -o user=`
export `strings /proc/$pid/environ | grep DBUS_SESSION_BUS_ADDRESS`
sudo -E -su $user /usr/bin/audtool $1

Running two linux commands via PHP, don't wait for first to end before executing second

This is pretty weird, and I searched and tried everything, but I think I'm just making a dumb syntax error here.
I'm trying to run a stress test on the CPU , then immediately limit it's cpu usage to 30% , all this via PHP. The test is also run under another user and with a specified name so it can be limited. The stress test starts fine, but I can see the PHP file still loading, and it ends the second the stress test ends.
Here's some of the ways I tried doing it
$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30"');
$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s > /dev/null & cpulimit -e MyUniqueProcessName -l 30"');
The whole purpose of this is because I am writing a script for a game hosting website, and I want to limit the resource consumption of each server to improve quality and not let someone hog all the resources.
Basically, instead of the stress test, a game server will run.
edit::
here's what I have now:
I need to run the stress under "test" , but the cpulimit under either sudo apache or root, because it requires special permissions. The stress still starts fine but it eats 99.9%
passthru('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s &" & sudo cpulimit -e MyUniqueProcessName -l 30 -i -z');
I can't see the cpulimit in the process list after doing this http://i.imgur.com/iK2nL43.png
Unfortunately, the && does more or less the opposite of what you want. :-) When you do A && B in Bash, that means, "Run command A and wait until it's done; if it succeeded, then run command B."
By contrast, A & B means, "Run command A and then immediately run command B."
So you're close to right in your command, but just getting tripped up by using two bash commands (should only need one) and the &&.
Also, did you try running each command separately, outside PHP, in two terminals? I just downloaded and built both stress and cpulimit (I assume these are the ones you're using?), ran the commands separately, and spotted a problem: cpulimit still isn't limiting the percentage.
Looking at the docs for stress, I see it works by forking child processes, so the one you're trying to CPU-limit is the parent, but that's not the one using the CPU. cpulimit --help reveals there's option -i, which includes child processes in what is limited.
This gets me to the point of being able to enter this in one terminal (first line shows input at the prompt; subsequent show output):
$> exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i
[1] 20229
MyUniqueProcessName: info: [20229] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
Process 20229 found
Then, in another terminal running top, I see:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20237 stackov+ 20 0 7164 100 0 R 30.2 0.0 0:04.38 stress
Much better. (Notice that outside the Bash shell where you aliased it with exec -a, you will see the process name as stress.) Unfortunately, I also see another issue, which is cpulimit remaining "listening" for more processes with that name. Back to cpulimit --help, which reveals the -z option.
Just to reduce the complexity a bit, you could leave the alias off and use the PID of the stress process, via the special Bash variable $!, which refers to the PID of the last process launched. Running the following in a terminal seems to do everything you want:
stress -c 1 -t 60s & cpulimit -p $! -l 30 -i -z
So now, just change the PHP script with what we've learned:
exec('bash -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i -z"');
...or, simpler version:
exec('bash -c "stress -c 1 -t 60s & cpulimit -p \$! -l 30 -i -z"');
(Notice the $ in the $! had to be escaped with a backslash, \$!, because of the way it's quoted when passed to bash -c.)
Final Answer:
Based on the last example you amended to your question, you'll want something like this:
passthru('bash -c "sudo -u test stress -c 1 -t 60s & sudo -u root cpulimit -p \$! -l 30 -i -z"');
When I run this with php stackoverflow-question.php, it outputs the following:
stress: info: [3374] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
stress: info: [3374] successful run completed in 60s
Process 3371 found
(The second two lines only appear after the PHP script finishes, so don't be mislead. Use top to check.)
Running top in another terminal during the 60 seconds the PHP script is running, I see:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3472 test 20 0 7160 92 0 R 29.5 0.0 0:07.50 stress
3470 root 9 -11 4236 712 580 S 9.0 0.0 0:02.28 cpulimit
This is exactly what you've described wanting: stress is running under the user test, and cpulimit is running under the user root (both of which you can change in the command, if desired). stress is limited to around 30%.
I'm not familiar with runuser and don't see the applicability, since sudo is the standard way to run a process as another user. To get this to work, you may have to adjust your settings in /etc/sudoers (which will require root access, but you obviously already have that). That's entirely outside the scope of this discussion, but as an example, I added the following rules:
my-user ALL=(test) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/stress
my-user ALL=(root) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/cpulimit

shell_exec not returning the same result as sudoed command line

I'm developping a PHP-FPM driven module in which in upload videos, then transcode them into several HTML5 formats in the background with ffmpeg. This PHP-FPM script runs under a specific, non-root UID, called tv25.
There is a variant in which I record a webcam stream through a Streaming Server (Wowza), which runs under the root UID, and launches the conversion through Java-written module.
In order to know the status of the processes I make a GET request to a script which runs the following function :
function is_conversion_running($base_file_name) {
$command = "sudo ps aux | grep {$base_file_name} | grep -v grep | wc -l";
$lignes = shell_exec($command);
return (bool) $lignes;
}
When I call this function through AJAX, it works for the PHP-FPM variant (the UID is the same, returns true while the conversion is running), but not with the Wowza variant (return false everytime).
The strange thing is that if I run the command in a shell, with the non-root UID, it works like a charm, since the ps command as been allowed to be run by this UID.
The problem seems similar to the one in shell_exec returns empty string, but the solution listed there doesn't work for me.
My /etc/sudoers line is like this :
tv25 ALL = (root) NOPASSWD: /bin/ps
Really can't figure out what is the deal...
What does the command return: 0 or NULL? In the second case the command probably failed alltogether. You can check with the exec function whether you get a non-zero exit code. Make sure to prefix your command with /bin/sh -c in that case.
PS: Do you really need the sudo for running ps? Normally you get all processes even without sudo.
Well I found another way to sikve my problem : since I want to know if the process is still running, I delegated the command in a shell script :
#!/bin/bash
BASE_NAME=`basename $0`
LIGNES=$(/usr/bin/sudo /bin/ps aux | grep "$1" | grep -v grep | grep -v $BASE_NAME | wc -l)
[ $LIGNES -eq "0" ] && exit 1
exit 0
And then I call it with passthru. Its return value parameter is then converted to boolean, negated, and returned by the function.
~

How can I force a PHP script to continue on with a script after calling exec()?

I'm using the exec function in PHP to run a command. The command I'm running can often take quite a bit of time and I don't have any need to read it's output. Is there a simple way of telling PHP not to wait for the exec command to finish before moving on with the rest of the script?
// nohup_test.php:
// a very long running process
$command = 'tail -f /dev/null';
exec("nohup $command >/dev/null 2>/dev/null &"); // here we go
printf('run command: %s'.PHP_EOL, $command);
echo 'Continuing to execute the rest of this script instructions'.PHP_EOL;
for ($x=1000000;$x-->0;) {
for ($y=1000000;$y-->0;) {
//this is so long, so I can do ps auwx | grep php while it's running and see whether $command run in separate process
}
}
run nohup_test.php:
$ php nohup_test.php
run command: tail -f /dev/null
Continuing to execute the rest of this script instructions
Let's find out pids of our processes:
$ ps auwx | grep tail
nemoden 3397 0.0 0.0 3252 636 pts/8 S+ 18:41 0:00 tail -f /dev/null
$ ps auwx | grep php
nemoden 3394 82.0 0.2 31208 6804 pts/8 R+ 18:41 0:04 php nohup_test.php
as you can see, pid is different and my script is running without waiting for tail -f /dev/null.
Here is what I use (you can use exec or system instead of paasthru):
passthru("/path/to/program args >> /path/to/logfile 2>&1 &");
What you are looking for is called an Asynchronous call, like answered here:
Asynchronous shell exec in PHP
php execute a background process
PHP exec() as Background Process (Windows Wampserver Environment)

shell script to check status of another script and restart it

I would like to have a shell scipt that runs infinitely and keeps checking status of a php script (say my.php) and restarts it if the script has terminated somehow. I have the idea to go for -
ps -aux | grep "my.php"
and then use the result of this to check the status and do accordingly. Thanks in advance.
You can simply say:
ps -aux | grep -q "my.php" || php -f my.php
The way it works is that grep -q will not output anything but will return an "OK" exit code if it found something. when it returns a "NOT OK" exit code, the part after the || ("or") gets executed (because of boolean short-circuit evaluation - look it up).
You also need to make sure that:
you run the new script in the background and detach it from your console so that your script can keep monitoring
when you run ps | grep sometimes ps also lists your grep and then the grep "greps itself", so you have to filter that out.
It should look something like this:
while true
ps -aux | grep -v grep | grep -q "my.php" || ( nohup php -f "my.php" & )
sleep 1
done
or some-such..
Another approach is, start your php-program in a loop:
for ((;;))
do
my.php
done
With Linux ps, you could use
ps -C "my.php"
instead of grep, to identify my.php. Grep commands often find themselves. Maybe your ps has a similar switch?
If you DO really feel the need to grep the output of ps, beware of your grep finding itself.
[ghoti#pc ~]$ sleep 60 &
[1] 66677
[ghoti#pc ~]$ ps aux | grep sleep
ghoti 66677 0.0 0.0 3928 784 11 S 4:11PM 0:00.00 sleep 60
ghoti 66681 0.0 0.0 16440 1348 11 S+ 4:12PM 0:00.00 grep sleep
[ghoti#pc ~]$
There's an easy way to avoid this. Just make part of your grep into a more complex regular expression.
[ghoti#pc ~]$ sleep 60 &
[2] 66717
[ghoti#pc ~]$ ps aux | grep '[s]leep'
ghoti 66677 0.0 0.0 3928 784 11 S 4:11PM 0:00.00 sleep 60
ghoti 66717 0.0 0.0 3928 784 11 S 4:13PM 0:00.00 sleep 60
[ghoti#pc ~]$
On the other hand, if you just want to make sure that your PHP script always runs, you can wrap it in something that re-runs it when it dies:
while true; do
php /path/to/my.php
done
If you want this to run at startup, you can edit your crontab on the server, and use a #reboot tag, assuming you're using "Vixie" cron (common on Linux and BSD):
#reboot /path/to/wrapperscript
You can man crontab and man 5 crontab for more details on how to use cron and the #reboot tag.

Categories