Running a Python script from PHP
Asked Answered
F

11

151

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 and python2.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.

Frostbite answered 1/11, 2013 at 20:54 Comment(1)
First Visit this issue #21660137 If not fixed and you get issues like In Case if you are stuck with imports or tty or no askpass not working please check this link for details steps to execute it. https://mcmap.net/q/47135/-php-cannot-connect-to-mysql-through-python Thanks!!!Senskell
G
208

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.

Gwenore answered 1/11, 2013 at 22:34 Comment(3)
Thank you, that did the trick! There was one more problem - the Apache user wasn't able to execute a command in the Python script but I was able to fix that by using sudo and adding a exception for my script to the sudoers file. Thanks again! :)Frostbite
For OSX: echo shell_exec("/usr/local/bin/python3 /Users/cyborg/Dev/magic.py"); or: echo shell_exec("/usr/bin/python /Users/cyborg/Dev/magic.py");Configuration
a bit different, but helped me to diagnose in debian: echo(exec("/usr/bin/python3 magic.py));Cytolysin
H
30

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(); 
Heth answered 1/11, 2013 at 22:38 Comment(0)
L
18

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".

Lamentable answered 18/9, 2015 at 18:19 Comment(0)
T
10

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

Source: http://php.net/manual/en/function.exec.php

Tallinn answered 7/10, 2018 at 15:59 Comment(0)
C
8

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

Cytolysin answered 27/7, 2014 at 22:19 Comment(2)
Doesn't seem effective to add www-data to sudoers, and gives apache more permissions that it needs. Giving www-data permissions on the script you're executing would be sufficient.Geter
Cool idea, but could definitely make your system vulnerable. I agree with @GeterHausa
S
8

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!

Selfassurance answered 2/3, 2018 at 17:43 Comment(0)
S
6

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");
Simplify answered 20/6, 2018 at 11:8 Comment(0)
P
3

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.

Pineal answered 16/8, 2020 at 20:55 Comment(0)
F
3

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.

Fugato answered 30/11, 2020 at 21:52 Comment(1)
Today I would suggest wrapping your script in a flask or fastapi and call it. Use guzzle if you are forced to use PHP.Fugato
C
2

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');
Cacilia answered 29/5, 2018 at 17:37 Comment(0)
D
0

I did find some help from answers above for my scenario. For me the python file was not getting called as i was working on some old version server and i had created virtual environment (with all the required libraries) in which i was working. So i called it like this :

$command="/home/userName/venv/bin/python /var/www/html/foldername1/foldername2/test.py"." ".$arg1." ".$arg2." ".$arg2; \\pass argument if needed in arg1 etc.

chdir("/var/www/html/folder1/folder2/"); //Changed the directory to where my files were

$output=shell_exec($command); //Execute the command in this directory

chdir("to the original working directory");

Hope this helps someone.

P.S.: As we have authorised access to Internet in our lab, so while running these files(python scripts) individually on the server, they were getting stuck in between downloading any modules or giving SSL error etc, so just by giving internet access to the server, it worked. And then i called it from PHP. Thanks

Dramaturgy answered 30/3, 2023 at 12:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.