Issuing Commands From Web Pages
If you install a PHP web server on your RPi you can issue commands using the PHP system() function.
Examples:
//Echo some system status:
echo '<pre>';
system('netstat -a');
echo '</pre>';
//Run an executable file:
echo '<pre>';
system("sudo /home/pi/projects/my_project.a"); //system() will echo the output of the executable, use shell_exec() instead if you don't want this
echo '</pre>';
WARNING!! When allowing user-supplied data to be passed use escapeshellarg() or escapeshellcmd() to ensure that users cannot trick the system into executing arbitrary commands.
system()
Also echo's the output of the command to the web page
shell_exec()
Does not echo the output of the command and returns you all of the output
exec()
Does not echo the output of the command but returns only the last line of any output
If it doesn't work
Try adding this to the end of your command: 2>&1
For example: sudo fping -c1 -t750 192.168.1.1 2>&1
This will cause error text to be returned
Issuing commands in the background
You can't just add the '&' character to the end of commands In PHP, because all calls are always waiting for the command to return. There's a good post in the issue here: http://phaq.phunsites.net/2012/01/18/run-command-in-background-from-php/
To fix it you need to direct the console output to a file instead and just adding this to the end of a command will do that: > /dev/null 2>&1 & echo $!
The following example issues a reboot command after a 2 second delay (you need to add the command to sudoeres for it to work – see below) and does it in the background so that the page is loaded before the reboot is actioned:
<?php
//----- DO THE REBOOT -----
//THIS SUDO COMMAND HAS AUTHORISED FOR APACHE TO USE IN THE FILE: sudo nano /etc/sudoers
// # Special for this system - let apache run exes we use in the web interface
// www-data ALL=NOPASSWD: /sbin/reboot
echo '<pre>';
system("(sleep 2 ; sudo /sbin/reboot ) > /dev/null 2>&1 & echo $!");
echo '</pre>';
?>
Issuing sudo commands
Apache will typically run using account www-data and this account is not permitted to use sudo. If you need to use sudo you need to enable this, but you don't want to simply give www-data global sudo access. If a malicious script is uploaded to your web server and gets executed this opens a massive security risk. The more secure approach is to restrict it to only the commands that you actually use in your own scripts.
You can use this command to open the sudoers file:
sudo nano /etc/sudoers
BE VERY CAREFUL TO COPY THIS FILE BEFORE YOU CHANGE IT – IF YOU MAKE AN ERROR YOU CAN STOP YOURSELF BEING ABLE TO OPEN THE FILE USING SUDO (changes to it are instant)!
An example enabling it to run a single executible, add this to the end of the file:
www-data ALL=NOPASSWD: /home/pi/some_executable_name
An example enabling it to run several different executables, add this to the end of the file:
www-data ALL=NOPASSWD: /home/pi/some_executable_name, /home/pi/some_executable_name some_option, /home/pi/some_other_executable_name
Passing $_POST Data To A Running Application
There is a really useful way of using the PHP system function to pass data to a running application on your RPi (e.g. your own application doing something with the IO) if you create a FIFO within it. Then you can use use a web page like this to pass it data from a form or $_POST input:
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My Page</title>
</head>
<body>
<?php
if ($_POST['Command'])
{
$Command = trim($_POST['Command']);
echo "Command received: $Command<br />";
system("sudo sh -c 'echo \"". escapeshellarg($Command) . "\" > /tmp/my_fifo'");
}
?>
<div align="center">
<form id="form1" name="form1" method="post" action="">
<p>
<label for="Command">Command:</label>
<input type="text" name="Command" id="Command" size="80" />
<input type="submit" name="Send" id="Send" value="Send" />
</p>
</form>
</div>
</body>
</html>
Escaping user supplied data – IMPORTANT!
When allowing user-supplied data to be passed to the system() function, ensure you use escapeshellarg() or escapeshellcmd() so that users can't trick the system into executing arbitrary commands.
Confirming which user apache is running as
<?php
echo exec('whoami');
?>
3 years ago
Great work. Thanks. I love raspberries too. I wrote a php class for access a lot of system resources. In raspberry works nice: https://github.com/vivesweb/system-resources
4 years ago
I have made a little deskboard, I can sudo poweroff and reboot, but not the speak program, I have added in sudoer and try many way, espeak not want run from a apache. The trick is running a cron job or a permanent script (with looping) and add file in a folder when apache require an action. The PHP file is running in background and scan the folder, when a file is there, open it, run the require task, and delete it. Is not the best way, make a little more storage usage (r/w and space).
8 years ago
sudo doesn’t work in that context. Setsuid on janhigh.py or find another way to escalate. My favorite way is to have a cron job (runs as root) that checks for a trigger file; your PHP just touch-es the trigger file and the cron job picks it up a few seconds later. Alternatively, write a small program that scans a trigger directory continuously (a while loop perhaps) until the trigger appears, for faster response. This is hard problem otherwise.
4 years ago
#The system command does not seem to work to control the GPIO if I run it in PHP on the localhost server. It does work if I run it from the command line.
The command is ” sudo python janhigh.py” wich is a little program I wrote. But it doesn’ t run within the system function in a php page. Any ideas?
Pingback: Named Pipes / FIFO’s « Raspberry Pi Projects