I'd like to run a Python script from PHP (LAMP). The script imports astropy, and for some reason I am not able to successfully do that. I can reproduce the basic problem with the example files copied below. I don't think it is a permission or Python path problem. I can import numpy, scipy, etc., for example. I can also create a Python script to read and write files on that same directory (/www/var). I have the standard Python on /usr/bin/python and also the Anaconda version. Both have astropy and I get the same problem regardless of which one I use.
I suspect it is something about running the code as myself (which works fine) or as www-data (from the web browser). However, when I do this from the Linux terminal: sudo -u www-data php test.php, the code works as expected.
This is test.php:
<?php
echo "<p>begin test.php</p>";
system("python test.py");
echo "<p>end test.php</p>";
?>
And test.py:
print("this is test.py ...")
import sys, numpy, scipy, matplotlib
print("passed the import sys, numpy, scipy, matplotlib ...")
import astropy
print("passed the import astropy ...")
What I get when I open test.php is this:
begin test.php
this is test.py ... passed the import sys, numpy, scipy, matplotlib ... ERROR: TypeError: coercing to Unicode: need string or buffer, NoneType found [genericpath]
end test.php
What version of Astropy are you running? Incidentally I'm pretty sure this is a known and fixed issue: https://github.com/astropy/astropy/pull/952
Also, current versions of Astropy require you to specify a configuration directory that the library can write to. It doesn't necessarily know that /var/www is the correct "home" directory to use for the webserver, so you need to set the environment variable XDG_CONFIG_HOME=/var/www (make sure the /var/www/astropy directory exists too).
I think there are plans to simply this so that the library is at least importable without this additional setup.
Related
Hi I've got the following written in a python script pythonscript1.py in linux debian in the directory /home/user/a/:
import subprocess
subprocess.call(["python" /home/user/b/phpcall.py"])
where the phpcall.py script contains:
import subprocess
subprocess.call(["php", "/home/user/b/phpscript1.php"])
individually called from console all scripts function perfectly, but when I use the first script whilst the 2nd script calls/looks for a file in directory b, rather than a, It yields the following error:
"PHP warning: include_once(something.php): failed to open stream: no such file in /home/user/b/phpschript1.php on line 25
Now it is quite clear to me the problem is that it cannot reach out of it's original directory. But I don't know what command I should add to the first script to allow the 2nd script to look in folder b.
So far google results have suggested something with "include_path='include'" but I don't know how/where to incorporate the statement succesfully.
Any suggestions on the correct syntax would be appreciated!
you can try this program:
import subprocess
import sys
proc = subprocess.Popen(
[sys.executable, '/home/user/b/phpcall.py'],stdin=subprocess.PIPE)
proc.communicate()
i think it's work. if not let know.
If the php script works only if you start it from the directory with the python script then you could use cwd parameter to change the working directory for the subprocess:
#!/usr/bin/env python
from subprocess import check_call
check_call(["php", "/home/user/b/phpscript1.php"], cwd="/home/user/b")
I've added the shebang #!/usr/bin/env python so that you could run the script directly as /path/to/phpcall.py assuming it is executable (chmod +x phpcall.py).
Note: if you want to run the python script as user user then you could specify the path using ~:
#!/usr/bin/env python
import os
from subprocess import check_call
script_dir = os.path.expanduser("~/b")
check_call(["php", os.path.join(script_dir, "phpscript1.php")], cwd=script_dir)
To avoid hardcoding the script directory, you could find it dynamically:
#!/usr/bin/env python
import os
from subprocess import check_call
script_dir = get_script_dir()
check_call(["php", os.path.join(script_dir, "phpscript1.php")], cwd=script_dir)
where get_script_dir().
For future reference the code that directly called the php script from python within was:
import os
os.chdir("/home/user/b")
os.system("php /home/user/b/phpscript1.php")
.Thanks Marc B
& I love the dynamic approach Sebastian, thank you :)
Im trying to call a python file containing a sentence/word tokenizer from my php file like this:
$output = shell_exec('python tokenizer.py $sentence')
I've tried single exec, full paths to python and tokenizer.py, wrapping $sentence in double quotes. But logically, It should not be the problem because calling print(1) at the beginning of python the python code before actually using any nltk packages makes $output equal to '1'. So I came to conclusion that the problem here is the nltk itself, like the path to the modules is not correct or something...
But, calling python from the shell using the same command as above gives me fully tokenized output! To conclude: looks like when calling python from php magically 'turns off' nltk, while it fully works when executed from the shell.
Here's the part of the python code I am using:
import sys
import nltk
from nltk.tokenize import sent_tokenize
sample_text2 = sys.argv[1]
gust = sent_tokenize(sample_text2)
#print(1) here doesn't work, but everywhere above (before calling sent_tokenize) it does.
The server's running on CentOS (Linux), I am accessing it via SSH.
Obvious question: What am I doing wrong here with PHP? Or generally? Any alternatives?
EDIT
As visible in dvhh's answer and its comments, the situation happened because there were two versions installed on the server (2.6 and 2.7), while the www user had access to 2.6 and through console, the default version was 2.7. The solution was to change the default python to 2.7 for both cases and to put the nltk modules to one of the dependency folders. (Or append the dependency directory using sys.path.append)
Your php script is executed by the www user.
You could check if the python script interpreter is correctly called, it is usually in one of the directory in the PATH environment variable (like /usr/bin/python), but the www user don't have a PATH environment variable set.
Solution specify the whole path to your python interpreter in your shell_exec call ( also specify the full path to your script when you're at it )
What about the path the nltk library is installed, you could check if the python interpreter would correctly look for it by looking at the sys.path while running python with the www user.
Diagnostic : use the shell_exec call to run a python script to print the sys.path values
Solution : append the library path to the sys.path in your python script before the import nltk
These would be the most obvious solutions considering the information provided in the question.
Update :
As there is 2 version version of python installed (on that haven't got the library installed ), it is recommended to specify the path to the desired interpreter. The first solution help correct the issue.
In unix like system I would recommend using which python command to determine the path of your default python interpreter.
Option 1
Setup a simple python httpserver listening on localhost. This old answer might help but there are plenty of howtos out there. The advantage is that you don't have the overhead of starting the python interpreter each time the ntlk stuff needs to be executed and you don't have to worry about shell script executions, permissions etc. Disadvantage is a little of extra work and a little overhead.
Option 2
Using a task queue. Whatever said and done it's not safe to execute commands from your web facing PHP scripts. If you are already using RabbitMQ or something similar you can use that here. Or else if you are using redis you can use the lpush, rpop methods to make redis behave like a queue. Disadvantage: the result is not immidiately available.
Option 3
Anbother strategy for your php script to enter the data into a table and setup your python script to run as a cron job to check the table once a minute. Disadvantage: the result is not immidiately available.
Option 4
Your current choice but please make sure that you have escaped the data properly by #lafor if this option is chosen #dvhh 's answer ought to work.
In my case it wasn't problem of python version but problem (as I soon found) of the nltk_data folder. First I thought it was as permission problem, so I changed the permissions to 777, but that didn't work.
I had to copy the folder.
First you have to find where was the nltk folder installed. You will find it by running python3 command from your bash and then put following lines:
import nltk
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
It will say something like:
[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data] Package punkt is already up-to-date!
Now you know you have it installed eg in /root folder (i had it there).
Then put in your python script which is called by php this:
import nltk
print(nltk.data.path)
It will output something like: (note the folders are another if you run it from php script or if you call it from command line)
['/var/www/nltk_data', '/usr/nltk_data', '/usr/share/nltk_data', '/usr/lib/nltk_data', '/usr/share/nltk_data', '/usr/local/share/nltk_data', '/usr/lib/nltk_data', '/usr/local/lib/nltk_data']
Now just copy your original folder to any of the above folders. I did:
cp /root/nltk_data /var/www/nltk_data -r
Voila. It works now.
I am running Ubuntu 14.04 with a locally hosted webpage running on Apache2. I can access index.php fine through my browser, but I want that page to display a graph that is prepared in a python script called graph.py. graph.py will execute fully when the I execute index.php from the terminal, and it will PARTIALLY execute when I access it from the browser. commands from pyplot, used within the graph.py file will not execute when called from the browser.
I have simplified the contents of the files for this question.
Contents of index.php:
<?php
echo exec('whoami');
echo "</br>";
$r = `python graph.py`;
echo($r);
?>
Contents of graph.py:
#!/usr/bin/python2.7
import cgi
import matplotlib.pyplot as plt
print("Initial file parsing successful")
plt.plot([1,2,3,4])
print("File completed operation using pyplot")
The output of index.php from the terminal has what I would expect:
MYUSERNAME</br>Initial file parsing successful
File completed operation using pyplot
The browser never completed the PyPlot operation as shown by its output:
www-data
Initial file parsing successful
After scouring the internet for answers, this post appears to be the most similar to my issue:
Why cannot PHP execute a command from web browser?
As suggested in the responses, it makes sense that I may be dealing with a permissions issue. I used "updatedb" and "locate pyplot" to find every instance the pyplot module appears. On my machine, there are three files in two directories:
/usr/lib/pymodules/python2.7/matplotlib/pyplot.py
/usr/lib/pymodules/python2.7/matplotlib/pyplot.pyc
/usr/share/pyshared/matplotlib/pyplot.py
Since pyplot has other dependencies in the matplotlib directory, I set permissions for every file in both of these directories with "chmod 777." I know I will have to restore these for security reasons once I find where I can scale permissions back, but even allowing that level of access, the php file will not execute when accessed from the browser. Does anyone have any ideas what could be catching this?
AFAIK, when you execute python from the browser the user is www-data. Thus you should change the python script's permissions to a+x. You don't need cgi unless you run PHP in cgi that is unusual. Just put 'graph.py' into the same folder where you keep your index.php. Save your plot into am image and open it in your browser via PHP. That's it.
Python script
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.savefig('img.png')
PHP code
<?php
$r = '/usr/bin/python ./graph.py';
exec($r);
$im = imagecreatefrompng("img.png");
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>
Output:
I was able to make a plot with Python in cgi. No problems. http://wiki.scipy.org/Cookbook/Matplotlib/Using_MatPlotLib_in_a_CGI_script
PHP
<?php
header('Location: cgi-bin/graph.py');
?>
PYTHON
#!/usr/bin/python
import os,sys
import cgi
import cgitb; cgitb.enable()
os.environ[ 'HOME' ] = '/tmp/'
import matplotlib
matplotlib.use( 'Agg' )
import pylab
form = cgi.FieldStorage()
pylab.plot([1,2,3])
print "Content-Type: image/png\n"
pylab.savefig( sys.stdout, format='png')
And here's without cgi. Since PHP is pretty much executable, we don't actually need cgi. I moved the graph.py from cgi-bin to html folder and deleted all the cgi modules from it and even os.environ[ 'HOME' ] = '/tmp/'.
PHP
<?php
$r = '/usr/bin/python ./graph.py';
exec($r);
$im = imagecreatefrompng("img.png");
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>
PYTHON
#!/usr/bin/python
import matplotlib
matplotlib.use( 'Agg' )
import pylab
pylab.plot([1,2,3])
pylab.savefig('img.png')
AS you see the difference is
matplotlib.use( 'Agg' )
I have no idea what it means. Something important, maybe. Without this opting the script doesn't run.
As per my understanding you will need to configure your webserver to work with python compiler. Any of the web server will by default will not be able to use any compiler installed on your system. Your webserver should understand for a particular file extension which program should be used to run it.
Below is the link where you can find information for it here:
[How do you set up Python scripts to work in Apache 2.0?
But in your case you may need just to run python scripts from php. You can find information about it here : Running a Python script from PHP
I'm using this command to execute a Python script from who.php:
virtual('../cgi-bin/sigphon/who.py');
on an Apache server, but when I go to the webpage from which command is called (who.php), raw code from the Python file is displayed, like this:
\#!/usr/bin/python print '3' scriptpath = "/compsci/webdocs/morphon/web_docs/cgi-bin/sigphon" import sys, cgi, string, sha, time import cgitb sys.path.insert(0, scriptpath) import easyhtml, member, readdb, common cgitb.enable() # FieldStorage object to hold the form data formdata = cgi.FieldStorage() thisscript = "%s/who.py" % (common.cgibase) def update_text(): return """
etc. ...
I'm able to execute the who.py script from the command line on the same server, from the same directory as who.php, with no issues, and I've tried setting the permissions for all files involved to 777.
I've also tried
echo exec('../cgi-bin/sigphon/who.py');
but to no avail. What's going on here?
You would have to configure Apache to parse .py files using python. There is a mod_python for Apache or you can set it up to run under CGI.
Most likely you can just use one of the PHP Program Execution Functions.
passthru('/path/to/python ../cgi-bin/sigphon/who.py');
hey yall. Im running python on a webserver from dreamhost. I am using their install of python and am using a lastfm module that can be found here: http://code.google.com/p/python-lastfm/
to get it to import properly i do this
import sys
sys.path.append("/home/myusername/build/Python-2.5/Lib/site-packages/")
import lastfm
since the lastfm module is installed there.
When I use putty to ssh into my server, i can simply run python test.py and it works perfectly. But when i run it from a php script with
exec("python test.py");
it suppossedly does not work and the script doesnt run. it runs perfectly fine when i do
import lastfm
and then have other things after,
but when i actually try to do something with the module like:
import lastfm
api=lastfm.Api(api_key)
it does not run. once again i can run the script using the same python install in a shell and it executes fine. So something must be happening that goes wrong when i run it from the php script. I figured it would be running the exact same python and everything. I checked other posts and they say it may be something with file permissions, but ive put every file to 777 and it still doesnt work. idk what the problem could be. thanks in advance everyone.
Try using the full path to the python executable. For example:
exec("/usr/bin/python test.py")
You can find the full path from the command line using the which command:
$ which python
/usr/bin/python
Whatever error python is raising would be going to the child's stderr. Try either telling php to read from stderr, or (in python) do this:
import sys
sys.stderr = sys.stdout
For Windows users:
$output = null;
exec('C:\\Python27\\python.exe C:\\sud.py', $output);
echo var_export($output, TRUE);
The code i was searching whole day ^^
That's why - hope it'll help somebody.
For Windows User -
Thanks to Karlisup my PHP file could read python.
I'm using BITNAMI WAMP in EC2 Amazon, my python file (leadatos.py) and php file are on htdocs folder.
My calling was
<?php
passthru('C:\\Python27\\python.exe leadatos.py');
?>
The last line of my Python file was print "message".
Hope it words!