Running a Python script from PHP
PhpPythonLinuxExecArchlinuxPhp Problem Overview
I'm trying to run a Python script from PHP using the following command:
exec('/usr/bin/python2.7 /srv/http/assets/py/switch.py arg1 arg2');
However, PHP simply doesn't produce any output. Error reporting is set to E_ALL and display_errors is on.
Here's what I've tried:
- I used
python2
,/usr/bin/python2
andpython2.7
instead of/usr/bin/python2.7
- I also used a relative path instead of an absolute path which didn't change anything either.
- I tried using the commands
exec
,shell_exec
,system
.
However, if I run
if (exec('echo TEST') == 'TEST')
{
echo 'exec works!';
}
it works perfectly fine while shutdown now
doesn't do anything.
PHP has the permissions to access and execute the file.
EDIT: Thanks to Alejandro, I was able to fix the problem. If you have the same problem, don't forget that your webserver probably/hopefully doesn't run as root. Try logging in as your webserver's user or a user with similar permissions and try to run the commands yourself.
Php Solutions
Solution 1 - Php
Tested on Ubuntu Server 10.04. I hope it helps you also on Arch Linux.
In PHP use shell_exec function:
> Execute command via shell and return the complete output as a string. > > It returns the output from the executed command or NULL if an error > occurred or the command produces no output.
<?php
$command = escapeshellcmd('/usr/custom/test.py');
$output = shell_exec($command);
echo $output;
?>
Into Python file test.py
, verify this text in first line: (see shebang explain):
#!/usr/bin/env python
> If you have several versions of Python installed, /usr/bin/env will > ensure the interpreter used is the first one on your environment's > $PATH. The alternative would be to hardcode something like > #!/usr/bin/python; that's ok, but less flexible. > > In Unix, an executable file that's meant to be interpreted can indicate > what interpreter to use by having a #! at the start of the first line, > followed by the interpreter (and any flags it may need). > > If you're talking about other platforms, of course, this rule does not > apply (but that "shebang line" does no harm, and will help if you ever > copy that script to a platform with a Unix base, such as Linux, > Mac, etc).
> This applies when you run it in Unix by making it executable > (chmod +x myscript.py) and then running it directly: ./myscript.py, > rather than just python myscript.py
To make executable a file on unix-type platforms:
chmod +x myscript.py
Also Python file must have correct privileges (execution for user www-data / apache if PHP script runs in browser or curl)
and/or must be "executable". Also all commands into .py
file must have correct privileges.
Taken from php manual:
> Just a quick reminder for those trying to use shell_exec on a > unix-type platform and can't seem to get it to work. PHP executes as > the web user on the system (generally www for Apache), so you need to > make sure that the web user has rights to whatever files or > directories that you are trying to use in the shell_exec command. > Other wise, it won't appear to be doing anything.
Solution 2 - Php
I recommend using passthru
and handling the output buffer directly:
ob_start();
passthru('/usr/bin/python2.7 /srv/http/assets/py/switch.py arg1 arg2');
$output = ob_get_clean();
Solution 3 - Php
If you want to know the return status of the command and get the entire stdout
output you can actually use exec
:
$command = 'ls';
exec($command, $out, $status);
$out
is an array of all lines. $status
is the return status. Very useful for debugging.
If you also want to see the stderr
output you can either play with proc_open or simply add 2>&1
to your $command
. The latter is often sufficient to get things working and way faster to "implement".
Solution 4 - Php
To clarify which command to use based on the situation
exec()
- Execute an external program
system()
- Execute an external program and display the output
passthru()
- Execute an external program and display raw output
Solution 5 - Php
Alejandro nailed it, adding clarification to the exception (Ubuntu or Debian) - I don't have the rep to add to the answer itself:
sudoers file:
sudo visudo
exception added:
www-data ALL=(ALL) NOPASSWD: ALL
Solution 6 - Php
In my case I needed to create a new folder in the www
directory called scripts
. Within scripts
I added a new file called test.py
.
I then used sudo chown www-data:root scripts
and sudo chown www-data:root test.py
.
Then I went to the new scripts
directory and used sudo chmod +x test.py
.
My test.py file it looks like this. Note the different Python version:
#!/usr/bin/env python3.5
print("Hello World!")
From php I now do this:
$message = exec("/var/www/scripts/test.py 2>&1");
print_r($message);
And you should see: Hello World!
Solution 7 - Php
The above methods seem to be complex. Use my method as a reference.
I have these two files:
-
run.php
-
mkdir.py
Here, I've created an HTML page which contains a GO button. Whenever you press this button a new folder will be created in directory whose path you have mentioned.
run.php
<html>
<body>
<head>
<title>
run
</title>
</head>
<form method="post">
<input type="submit" value="GO" name="GO">
</form>
</body>
</html>
<?php
if(isset($_POST['GO']))
{
shell_exec("python /var/www/html/lab/mkdir.py");
echo"success";
}
?>
mkdir.py
#!/usr/bin/env python
import os
os.makedirs("thisfolder");
Solution 8 - Php
This is so trivial, but just wanted to help anyone who already followed along Alejandro's suggestion but encountered this error:
> sh: blabla.py: command not found
If anyone encountered that error, then a little change needs to be made to the php file by Alejandro:
$command = escapeshellcmd('python blabla.py');
Solution 9 - Php
Inspired by Alejandro Quiroz:
<?php
$command = escapeshellcmd('python test.py');
$output = shell_exec($command);
echo $output;
?>
Need to add Python, and don't need the path.
Solution 10 - Php
All the options above create new system process. Which is a performance nightmare. For this purpose I stitched together PHP module with "transparent" calls to Python.
https://github.com/kirmorozov/runpy
It may be tricky to compile, but will save system processes and will let you keep Python runtime between PHP calls.