I'm working on interfacing a microcontroller with a lamp server. I am trying to run the command echo -e -n "data \r" > /dev/ttyUSB0 using shell_exec in php but with no results. It works just fine from the command line. Doing a little experimenting, I discovered that echo -e -n "1 \r" actually echoes -e -n 1. Is there a reason it won't take the -e or -n options?
Here's my code:
<?php
shell_exec('echo -e -n "1 \r" > /dev/ttyUSB0');
?>
Instead of using shell_exec and echo, why not use PHP's filesystem functions?
file_put_contents('/dev/ttyUSB0', "1 \r");
There are some other functions too, try this function maybe you get your answer.
exec(command, $output);
This function takes a command and assigns to $output an array where each element is a line of the generated output.
I ran into similar problem, calling from php
php > echo shell_exec("echo -e aaa\tbbb");
-e aaa bbb
note, that output contains "-e", while I have expected that 'echo' command will interpret -e as flag and would not send it to output.
After doing some investigation I came to following conclusion:
when exec or shell_exec are called from php - new shell interpreter is launched.
php launches "sh".
When I was running on CentOS sh was a symlink to bash, and exec("echo ...") worked as I would have expected.
Now I am running Ubuntu. sh is a symlink to dash, not bash!
And final root cause - builtin echo command in dash does not have/understand '-e' flag, so it just forwards it to output
This is an old question but it goes what worked for me in case someone else comes across with this as well.
Yesterday night I've messing around and struggling with this myself. For this to work, the command you need to use should start by calling the echo bin directly /bin/echo... instead of only echo.
Also don't forget to use single quote /bin/echo... instead of double quote to avoid PHP null byte detection error (this part you did correctly).
I had a similar problem running with -e, I was trying to change the password from a php
running this didnt work
exec("echo -e \"$pass\\n$pass\" | passwd $user");
It said passwords dont match. Checking the echo i saw that -e was includes as a part of the echoing so i changed it to
exec("echo \"$pass\\n$pass\" | passwd $user");
And then it worked.
Related
I'm able to call diff via exec() just fine with files, like so:
exec('diff -N -u '.escapeshellarg($oldfile).' '.escapeshellarg($newfile), $lines);
However, attempting to do this with arbitrary strings fails:
exec('diff -N -u <(echo '.escapeshellarg($oldstring).') <(echo '.escapeshellarg($newstring).')', $lines);
If I copy the command being run into bash, it works just fine. But when run in PHP I get no output. Even 2>&1 doesn't yield anything. Capturing the status code yields 1, which should indicate that diff found differences, but I still get 1 even in the case where $newstring === $oldstring.
So I'm not quite sure what's going on. I can only assume that, for some reason, exec doesn't like process substitutions? Any ideas?
PHP's exec runs the command with /bin/sh, which does not support process substitution (even when sh is provided by bash).
You can instead run your command explicitly with bash -c.
Sadly, PHP has no convenience functions for safe and robust execv style execution, so the easiest way to do that to build your diff command and then escape the whole thing:
exec('bash -c ' . escapeshellarg('diff -N -u <(echo '.escapeshellarg($oldstring).') <(echo '.escapeshellarg($newstring).')'), $lines);
What shell is being used? Make sure diff is in the $PATH, otherwise command will fail.
I wrote a PHP script and I'm trying to read user input from the command line. I started of with
$myVar = exec('read myVar; echo $myVar;');
which worked fine, but when typing the input the arrow keys didn't work the way it should. I learned that this could be solved with the -e switch, so it became:
$myVar = exec('read -e myVar; echo $myVar;');
Now this worked like a charm in my development envionment but unfortunately it seems like in our production environment PHP doesn't use a bash shell and doesn't support the -e switch, and it's probably not easy to change this.
According to the third answer to this question one can force PHP to use bash, so it became:
$myVar = exec('/bin/bash -c "read -e myVar; echo $myVar"');
Now, unfortunately this doesn't work as the variable myVar is not set.
When I run the commands directly from the command line $myVar (the shell variable) is set with whatever my input is, and consequently echo'ed
However when using the -c option, either in a PHP-exec() or directly on the command line like this:
/bin/bash -c "read -e myVar; echo $myVar";
$myVar isn't set at all, and an empty string (or whatever was the previous value of $myVar) is echo'ed
What do I do wrong here?
The issue is that $myVar is being interpreted before being passed to bash. The following will work by escaping the $ before it's passed to the shell:
/bin/bash -c "read -e myVar; echo \$myVar"
Also you can shorten it a little by making use of $REPLY
/bin/bash -c "read -e; echo \$REPLY"
The command you are using is correct.
The solution is to use the correct escape sequence:
$myVar = exec ('/bin/bash -c \'read -e myVar; echo $myVar \'');
I'm trying to execute a command through PHP with shell_exec. The PHP file is hosted by Apache on my Ubuntu server.
When I run this:
echo shell_exec("ps ax | grep nginx");
Then I get to see data. But when I run another command, for example:
echo shell_exec("cat /usr/local/nginx/config/nginx.config");
Then it's not showing anything at all. But when I copy that command and paste it in my terminal, then it executes fine.
My Apache server is running as user www-data. So I edited sudoers and added this line:
www-data ALL=(ALL:ALL) ALL
I know this is a security risk, but I wanted to make sure (for now) that www-data is able to execute all commands. But, for some reason I'm still not able to execute all commands with my PHP script.
Anyone any idea what to do?
have you read http://php.net/manual/en/function.shell-exec.php
There is quite a discussion in comments section. Top comment is:
If you're trying to run a command such as "gunzip -t" in shell_exec and getting an empty result, you might need to add 2>&1 to the end of the command, eg:
Won't always work:
echo shell_exec("gunzip -c -t $path_to_backup_file");
Should work:
echo shell_exec("gunzip -c -t $path_to_backup_file 2>&1");
In the above example, a line break at the beginning of the gunzip output seemed to prevent shell_exec printing anything else. Hope this saves someone else an hour or two.
echo shell_exec("sudo cat /usr/local/nginx/config/nginx.config");
Try that.
It's quite simple, and I'm out of ideas. I'm sure there is a quick workaround.
exec('echo 123 &> /var/log/123.log');
I'm sure it's not about the permissions, because the file 123.log is created, but it's just- empty. I've also tried shell_exec, but it doesn't create the file at all.
Also tried all variants of redirection, i.e. 1> 2> >.
Using PHP to capture the output is not the option, as the output in production is huge, and I don't want to run into memory issues.
Any ideas appreciated.
Btw, I'm using Ubuntu 12.04 LAMP.
Debian and Debian based Linux distributions like Ubuntu are using dash and not bash as /bin/sh by now.
&> is a bash extension, the dash does not know about.
The correct posix-compatible way to write cmd &> file is cmd > file 2>&1
cmd > file 2>&1 works in all posix-compatible shells: dash, bash, ksh, zsh, ash ...
So you need to change your code to:
exec('echo 123 > /var/log/123.log 2>&1');
Try shell_exec without &:
echo shell_exec("echo 123 > /var/log/123.log");
Only thing that did help was to create a shell script with exec permissions, e.g. test.sh:
#!/bin/bash
echo 123 &>> /var/log/123.log
and execute it like this:
shell_exec('[full path to]/test.sh');
So, redirection operator is not important, but everything else is (#! directive, shell_exec).
I have a PHP script that listens on a queue. Theoretically, it's never supposed to die. Is there something to check if it's still running? Something like Ruby's God ( http://god.rubyforge.org/ ) for PHP?
God is language agnostic but it would be nice to have a solution that works on windows as well.
I had the same issue - wanting to check if a script is running. So I came up with this and I run it as a cron job. It grabs the running processes as an array and cycles though each line and checks for the file name. Seems to work fine. Replace #user# with your script user.
exec("ps -U #user# -u #user# u", $output, $result);
foreach ($output AS $line) if(strpos($line, "test.php")) echo "found";
In linux run ps as follows:
ps -C php -f
You could then do in a php script:
$output = shell_exec('ps -C php -f');
if (strpos($output, "php my_script.php")===false) {
shell_exec('php my_script.php > /dev/null 2>&1 &');
}
The above code lists all php processes running in full, then checks to see if "my_script.php" is in the list of running processes, if not it runs the process and does not wait for the process to terminate to carry on doing what it was doing.
Just append a second command after the script. When/if it stops, the second command is invoked. Eg.:
php daemon.php 2>&1 | mail -s "Daemon stopped" you#example.org
Edit:
Technically, this invokes the mailer right away, but only completes the command when the php script ends. Doing this captures the output of the php-script and includes in the mail body, which can be useful for debugging what caused the script to halt.
Simple bash script
#!/bin/bash
while [true]; do
if ! pidof -x script.php;
then
php script.php &
fi
done
Not for windows, but...
I've got a couple of long-running PHP scripts, that have a shell script wrapping it. You can optionally return a value from the script that will be checked in the shell-script to exit, restart immediately, or sleep for a few seconds -and then restart.
Here's a simple one that just keeps running the PHP script till it's manually stopped.
#!/bin/bash
clear
date
php -f cli-SCRIPT.php
echo "wait a little while ..."; sleep 10
exec $0
The "exec $0" restarts the script, without creating a sub-process that will have to unravel later (and take up resources in the meantime). This bash script wraps a mail-sender, so it's not a problem if it exits and pauses for a moment.
Here is what I did to combat a similar issue. This helps in the event anyone else has a parameterized php script that you want cron to execute frequently, but only want one execution to run at any time. Add this to the top of your php script, or create a common method.
$runningScripts = shell_exec('ps -ef |grep '.strtolower($parameter).' |grep '.dirname(__FILE__).' |grep '.basename(__FILE__).' |grep -v grep |wc -l');
if($runningScripts > 1){
die();
}
You can write in your crontab something like this:
0 3 * * * /usr/bin/php -f /home/test/test.php my_special_cron
Your test.php file should look like this:
<?php
php_sapi_name() == 'cli' || exit;
if($argv[1]) {
substr_count(shell_exec('ps -ax'), $argv[1]) < 3 || exit;
}
// your code here
That way you will have only one active instace of the cron job with my-special-cron as process key. So you can add more jobs within the same php file.
test.php system_send_emails sendEmails
test.php system_create_orders orderExport
Inspired from Justin Levene's answer and improved it as ps -C doesn't work in Mac, which I need in my case. So you can use this in a php script (maybe just before you need daemon alive), tested in both Mac OS X 10.11.4 & Ubuntu 14.04:
$daemonPath = "FULL_PATH_TO_DAEMON";
$runningPhpProcessesOfDaemon = (int) shell_exec("ps aux | grep -c '[p]hp ".$daemonPath."'");
if ($runningPhpProcessesOfDaemon === 0) {
shell_exec('php ' . $daemonPath . ' > /dev/null 2>&1 &');
}
Small but useful detail: Why grep -c '[p]hp ...' instead of grep -c 'php ...'?
Because while counting processes grep -c 'php ...' will be counted as a process that fits in our pattern. So using a regex for first letter of php makes our command different from pattern we search.
One possible solution is to have it listen on a port using the socket functions. You can check that the socket is still listening with a simple script. Even a monitoring service like pingdom could monitor its status. If it dies, the socket is no longer listening.
Plenty of solutions.. Good luck.
If you have your hands on the script, you can just ask him to set a time value every X times in db, and then let a cron job check if that value is up to date.
troelskn wrote:
Just append a second command after the script. When/if it stops, the second command is invoked. Eg.:
php daemon.php | mail -s "Daemon stopped" you#example.org
This will call mail each time a line is printed in daemon.php (which should be never, but still.)
Instead, use the double ampersand operator to separate the commands, i.e.
php daemon.php & mail -s "Daemon stopped" you#example.org
If you're having trouble checking for the PHP script directly, you can make a trivial wrapper and check for that. I'm not sufficiently familiar with Windows scripting to put how it's done here, but in Bash, it'd look like...
wrapper_for_test_php.sh
#!/bin/bash
php test.php
Then you'd just check for the wrapper like you'd check for any other bash script: pidof -x wrapper_for_test_php.sh
I have used cmder for windows and based on this script I came up with this one that I managed to deploy on linux later.
#!/bin/bash
clear
date
while true
do
php -f processEmails.php
echo "wait a little while for 5 secobds...";
sleep 5
done