I have just built 3 different versions of PHP from source on an Ubuntu server (alongside NGINX and MySQL 5.7). I am looking for a way to run php --ini for the currently running version. I know I have to add the location to the file PATH in .bashrc so I don't have to add the full path.
I have added this to my .bashrc which allows me to get the currently running PHP version, which then allows me to run the command:
# parallels#ubuntu:~$ ps aux | grep php
# root 6948 0.0 0.2 153724 4620 ? Ss 16:48 0:00 php-fpm: master process (/opt/php-7.0.0/etc/php-fpm.conf)
PHP_VERSION=$(ps aux | grep -o php-[[:digit:]].[[:digit:]].[[:digit:]])
export PATH="/bin:/usr/bin:/opt/$PHP_VERSION/bin:/sbin"
It works, but I am a bash novice and I'm thinking their might be a different way to do it. Would I be correct?
PHP_VERSION=$(php -v | tail -r | tail -n 1 | cut -d " " -f 2 | cut -c 1-3)
cd /usr/local/etc/php/$PHP_VERSION/
# cd /usr/local/etc/php/7.1/
This command works while running in PHP
<?php
echo PHP_VERSION;
You can get it in bash, like
PHP_VERSION=$(php -r "echo PHP_VERSION;")
Here is all of PHP Predefined Constants
I got it to work with the following commands:
# Full version
php -v | head -n 1 | cut -d " " -f 2
# Major.Minor version
php -v | head -n 1 | cut -d " " -f 2 | cut -f1-2 -d"."
should be able to get it done with awk.
php -v | awk 'NR<=1{ print $2 }'
print the second column from the first row of input.
Related
I have the shell script "test.sh":
#!/system/bin/sh
PID=$(ps | grep logcat | grep root |grep -v grep | awk '{print $2}')
echo "Using awk: $PID"
PID=$(ps | grep logcat | grep root |grep -v grep | cut -d " " -f 7 )
echo "Using cut: $PID"
When I run the script from PHP:
exec("su -c sh /path/to/my/script/test.sh");
I got this output:
Using awk:
Using cut: 6512
So "cut" command is work but "awk" command doesn't when I run the script from PHP, but when I run it from terminal:
# sh test.sh
I can get both awk and cut work fine! This how look like the output of "ps":
USER PID PPID VSIZE RSS WCHAN PC NAME
root 6512 5115 3044 1108 poll_sched b6e4bb0c S logcat
Do I missed something?
You should learn how to debug first
You said
So "cut" command is work but "awk" command doesn't when I run the
script from PHP, but when I run it from terminal:
I wonder how ?
actually throws error like below, in CLI
$ php -r 'exec("su -c sh /path/to/my/script/test.sh");'
su: user /path/to/my/script/test.sh does not exist
You first need below syntax while debugging code
// basic : stdin (0) stdout (1) stderr (2)
exec('your_command 2>&1', $output, $return_status);
// to see the response from your command
// su: user /path/to/my/script/test.sh does not exist
print_r($output);
Remember :
su gives you root permissions but it does not change the PATH variable and current working directory.
The operating system assumes that, in the absence of a username, the
user wants to change to a root session, and thus the user is prompted
for the root password
[akshay#localhost Desktop]$ su
Password:
[root#localhost Desktop]# pwd
/home/akshay/Desktop
[root#localhost Desktop]# exit
exit
[akshay#localhost Desktop]$ su -
Password:
[root#localhost ~]# pwd
/root
Solution:
You should allow executing your script without password prompt ( don't use su use sudo )
To allow apache user to execute your script and some commands you may make entry like below in /etc/sudoers
# which awk => give you awk path
# same use in your script also, or else set path variable
www-data ALL=NOPASSWD: /path/to/my/script/test.sh, /bin/cut, /usr/bin/awk
So it becomes :
// assuming your script is executable
exec("sudo /path/to/my/script/test.sh 2>&1", $output);
print_r($output);
I have a php script that runs via a cron job.
I have an exec command in the script like so:
exec("ps -u bob -o user:20,%cpu,cmd | awk 'NR>1' | grep vlc | tr -s ' ' | cut -d ' ' -f 2",$cpu,$return)
This gets me the cpu form a process run by a specific user, if the process exists. When run via the command line I get say 21 or nothing at all depending on if the process is running or not. However, when running vai the PHP script, I get the following:
[0] => bob 0.0 /bin/sh -c php /home/bob/restart.php bob
[1] => bob 0.0 php /home/bob/restartStream.php bob
[2] => bob 0.0 sh -c ps -u bob -o user:20,%cpu,cmd | awk NR
It seems to be returning all the recent commands executed as opposed to the result of the command executed.
I have seen some posts which show the use of 2>&1 which I believe redirects the stdin and stdout or soemthing similar. However I have tried this in my command like so:
ps -u bob -o user:20,%cpu,cmd | awk 'NR>1' | grep vlc | tr -s ' ' | cut -d ' ' -f 2 2>&1
But it does not seem to make a difference. Can any give me any pointers as to why this is occurring and what can possibly be done to resolve this.
You need to clear out $cpu before you call exec. It appends the new output to the end of the array, it doesn't overwrite it.
You can also get rid of grep, tr, and cut and do all the processing of the output in awk
$cpu = array();
exec("ps -u bob -o user:20,%cpu,cmd | awk 'NR>1 && /vlc/ && !/awk/ {print $2}'",$cpu,$return);
The !/awk/ keeps it from matching the awk line, since that contains vlc.
I have setup cron job, it is working properly,when i directly runs the php file(from the path/url) it successfully runs, but from cron its not. i have used simple php mail function and its is running successfully but my task is not completed properly. Kindly suggest me the possible areas to look into it. (I am using Cpanel). here this is the code that i am using in cron.ch
#!/bin/sh
# location of the php binary
if [ ! "$1" = "" ] ; then
CRONSCRIPT=$1
else
CRONSCRIPT=cron.php
fi
PHP_BIN=`which php`
# absolute path to magento installation
INSTALLDIR=`echo $0 | sed 's/cron\.sh//g'`
# prepend the intallation path if not given an absolute path
if [ "$INSTALLDIR" != "" -a "`expr index $CRONSCRIPT /`" != "1" ];then
if ! ps auxwww | grep "$INSTALLDIR""$CRONSCRIPT" | grep -v grep 1>/dev/null 2>/dev/null ; then
$PHP_BIN "$INSTALLDIR""$CRONSCRIPT" &
fi
else
if ! ps auxwww | grep " $CRONSCRIPT" | grep -v grep | grep -v cron.sh 1>/dev/null 2>/dev/null ; then
$PHP_BIN $CRONSCRIPT &
fi
fi
this is how i am setting cron for every 15 minutes from c-panel
*/15 * * * *
From PHP pages of my apache server, I run some commands using a line like :
exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$!");
You can see an explaination of the arguments here.
But I don't understand something : if I restart or stop my apache server, my command dies too.
root#web2:/sx/temp# ps ax | grep 0ff | grep -v grep
15957 ? S 0:38 /usr/bin/php /sx/site_web_php/fr_FR/app/console task:exec /sx/temp/task_inventaire/ 0ff79bf690dcfdf788fff26c259882e2d07426df 10800
root#web2:/sx/temp# /etc/init.d/apache2 restart
Restarting web server: apache2 ... waiting ..
root#web2:/sx/temp# ps ax | grep 0ff | grep -v grep
root#web2:/sx/temp#
After some researches, I read some things about parent pids, but using a & inside my command-line, I thought I was really detaching my child process from his parent.
I am using apache2 with libapache2-mod-php5 and apache2-mpm-prefork.
How can I really detach my children programs from apache?
edit
You can reproduce it on a Linux/Mac this way :
a) create a executed_script.php file that contains :
<?php
sleep(10);
b) create a execute_from_http.php file that contains :
<?php
exec("php executed_script.php > /tmp/test.log 2>&1 & echo -n \$!");
c) run http://localhost/path/execute_from_http.php
d) on a terminal, run the command :
ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
If you run the command during the 10 secs of the execute_from_http.php script, you'll get the output :
php#beast:/var/www/xxx/$ ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
1 5257 5245 5245 ? -1 S 33 0:00 php executed_script.php
* Restarting web server apache2
... waiting ...done.
php#beast:/var/www/xxx/$
As you can see, the ps command outputs only once, this tells you that the executed script died when apache restarted.
The "at" method
I found a working solution but I don't know if that's ok if we speak performance and security. It uses the at command, a kind of cron working only once.
Instead of :
exec("php executed_script.php > /dev/null 2>&1 & echo -n \$!");
Use :
exec("echo 'php executed_script.php > /dev/null 2>&1' | at now -M");
The key is that executed_script.php will be run by an external daemon (atd), so executed_script.php will be a child of atd and not an apache's one.
php#beast:/var/www/xxx$ ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
7032 7033 973 973 ? -1 SN 33 0:00 \_ php executed_script.php
* Restarting web server apache2
... waiting ...done.
7032 7033 973 973 ? -1 SN 33 0:00 \_ php executed_script.php
php#beast:/var/www/xxx$ ps ax | grep 973
973 ? Ss 0:00 atd
Note several things :
you can't access the pid of your ran app, if you get $! like on my previous pieces of code, you'll get the pid of at.
you need to remove www-data which is by default in /etc/at.deny (it is probably there with reasons, so take care)
i have serious doubts about performance : I think that at write on a file read by atd to communicate
The fork / setsid method
As #hek2mgl wrote in its own answer, we can use a pcntl_fork(), but that's not as simple as that. First, you can't run pcntl_fork() behind apache, because if we look at the PHP Manual, Introduction of the Process Control, we can see:
Process Control should not be enabled within a web server environment
and unexpected results may happen if any Process Control functions are
used within a web server environment.
When a fork is made, you get two exact copy of the parent process in memory. And because PHP behind apache is run as a module, at the end of the PHP execution (even after a die()), you come back to the apache's module wrapper, and you can't control what's going on.
So here is the scenario with an intermediate command that will daemonize your execution:
1) From Apache, you run the intermediate command that will create your daemonized command :
$command = escapeshellarg("php executed_script.php");
exec("php run_as_daemon.php {$command} >> /dev/null 2>&1 &");
2) The intermediate command fork and use posix_setsid to really detach your command.
<?php
if (!isset($argv[1]))
{
exit;
}
$command = $argv[1];
$pid = pcntl_fork();
if ($pid < 0) // error
exit;
else if ($pid) // parent
exit;
else // child
{
$sid = posix_setsid(); // creates a daemon
if ($sid < 0)
exit;
exec("{$command} >> /dev/null 2>&1 &");
}
3) Your executed command, of course, doesn't change :
<?php
sleep(10);
Result :
php#beast:/var/www/xxx/$ wget -qO- http://localhost/xxx/execute_from_http.php && sleep 1 && ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
1 19958 19956 19956 ? -1 S 33 0:00 php executed_script.php
* Restarting web server apache2 ......done.
1 19958 19956 19956 ? -1 S 33 0:00 php executed_script.php
First note, that the '&' in your example is just a boolean AND that concats the command and the echo. If you want to start the command in background, meaning that exec will return immediately, use the & at the very end of the command line:
exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$! &");
If you want the process running after apache has finished you'll have to daemonize the process using pcntl_fork()
Here comes an example:
$pid = pcntl_fork();
switch($pid) {
case -1 : die ('Error while forking');
case 0: // daemon code
posix_setsid(); // create new process group
exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$!");
break;
default:
echo 'daemon started';
break;
}
Now there is no code in the starting PHP scripts that handles the return value of exec nor its output. So the current process can finish before exec has finished. The worker process will be owned by init after this.
Also you can have a look at the PEAR package System_Daemon. This can help to daemonize a script.
I know this is simple but I just cant figure it out.
I have a bunch of files output by "svn st" that I want php to do a syntax check on the command line.
This outputs the list of files: svn st | awk '{print $2}'
And this checks a php script: php -l somefile.php
But this, or variants of, doesn't work: svn st | php -l '{print $2}'
Any ideas? Thanks!
Use xargs:
svn st | awk '{print $2}' | xargs -L 1 php -l
The xargs -L 1 command reads items from standard input, one per line, and runs the given command for each item separately. See the xargs(1) man page for more info.