Python modules are not imported when running python script from PHP - php

I have a Python script, which works fine when I run it in Terminal. Here it is:
import bs4, requests, json, sys
from sys import argv
def getFsmonData(link):
res = requests.get(link)
res.raise_for_status()
soup = bs4.BeautifulSoup(res.text)
# Get table data
tds = soup.select('td')
new_td_list = []
for i in range(len(tds)):
inner_td_list = []
for y in range(len(tds)):
inner_td_list.append(tds[y].getText())
new_td_list.append(inner_td_list)
print(inner_td_list)
td_list_json = json.dumps(inner_td_list)
tdf = open("/path/to/file/data/td_data.txt", "w")
tdf.write(td_list_json)
tdf.close()
getFsmonData(sys.argv[1])
But now I am trying to run it from PHP and I get the following error:
Traceback (most recent call last): File
"/path/to/file/example.py", line 1, in import bs4, requests,
json, sys ModuleNotFoundError: No module named 'bs4'
I guess PHP thinks I do not have this module installed, but I am not sure of course. Here is my PHP code:
<?php
$link = $_POST['dn-link'];
if (isset($_POST['submit'])) {
system('/usr/bin/python3 /path/to/file/example.py ' . escapeshellarg($link) . ' 2>&1', $retval);
}
?>
Who can help solving this issue?

Most likely, when your PHP script executes your Python script, its executing it as a different user (possibly super user). What you can do is check if the packages are installed under the super user by doing
sudo pip list
or if you're using python3
sudo pip3 list
see if the packages you we're wanting to use are listed from this command.
If they aren't listed, you can easily install them via the command:
sudo pip install <pkg name>
or
sudo pip3 install <pkg name>
What you're doing here is installing the packages under the super user rather than you the local user.

I think your misunderstanding the permission issue. It's not that you need to add it PHP. It's that your OS keeps track of permissions, and the permission you have assigned to your PHP interpreter and your Python interpreter are misaligned. There are two permissions that usually people mix up here - USER which is login level access and SYSTEM which is system wide access. If your on your own dev machine then add both to SYSTEM.
We need to know your OS to be able to fully answer, i'm going to guess Mac OS in which case would be this (I think, can't test it right now).
sudo nano "pathOfYourInterpreter"
The other thing could be happening is that the libraries you're tryng to import are somewhere where the current sys path you have setup can't reach them. For example if you have your sys variable for Python set to the directory where the interpretor is but the scripts you're importing are in a different folder. In that case you have several options for accessing those scripts.
Set the current working directory to the folder where they're located before importing with:
os.chdir("locationOfScript/")
import script.py
Add a sys Path at runtime:
sys.path.append("locationOfScript/)
There are more methods of attack, but I think this should get you started.

Related

Error execution Python script from php in Apache2

I'm creating a web application managed with apache2, the problem I'm trying to solve is running a python script using php, I'm attaching my code:
PHP CODE:
<?php
$command = escapeshellcmd("/usr/bin/python3.6 /var/www/html/yoloface-master/showInWeb.py");
$output = shell_exec($command);
echo $output;
?>
PYTHON CODE
#!/usr/bin/python3.6
import hashlib, os, sys, cv2, PIL, subprocess, glob, numpy, django, random
from PIL import Image
import shutil
def showInWeb():
pathYolo = 'yoloface-master/'
os.chdir(pathYolo)
photo = random.choice(os.listdir("../Database/ARCHIVIOIMAGO"))
path = '../Database/ARCHIVIOIMAGO/'
print(photo)
shutil.rmtree('outputs/')
processPhoto = path + photo
command_line = ('python3.6', 'yoloface.py', '--image', processPhoto, '--output-dir', 'outputs/')
print(subprocess.run(command_line))
showInWeb();
As IDE I'm using pyCharm, and if I run the same command line in the pyCharm terminal (I'm not in a virtual environment) the program works without problems, however if I run it through the php script I get an error like "No Module Named cv2 ", this makes me guess that php is using a different version.
I read on the internet that a possible solution was to place "sudo" on the command line like:
sudo /usr/bin/python3.6 /var/www/html/yoloface-master/showInWeb.py
But I get this error:
sudo: no tty present and no askpass program specified
How can I do?

Executing bash file via php on apache server

So I have hosted a webpage on my apache server and I'm trying to run some python and bash scripts when the user presses a button via PHP and AJAX.
Now my php file executes at python script (located in /var/www/html) which in turn executes a bash file (located in root/files).
On doing this manually in terminal, everything works perfectly fine.
But when I try to this via the webpage, the bash script isn't executed.
(I can't place the bash script in /var/www/html because it has the command to clone a git repository to the server and it gives private key shouldn't be public error when placed there)
I already tried suggestions in this answer by adding www-data to sudoers but it is still not working as expected.
Any help on this would be appreciated.
Thanks
PHP file :
if(isset($_POST['timestamp']))
{
$uid = $_POST['timestamp'];
echo "Please wait while the app is being generated".$uid;
exec("python /var/www/html/appgenserver.py $uid");
appgenserver.py
#! /usr/bin/env python
import os
import json,sys
from firebase import firebase
import requests
import subprocess
arg = sys.argv[1]
# Path to be created
path = "/root/files/"+str(arg)
print path
if not os.path.exists(path):
os.makedirs(path) #Gets executed
subprocess.call(['/root/Final/clone.sh', path) #Not getting executed
Most likeley because a bash script in its self won't be executable, it's just a plain textfile.
Your bash (and perhaps even appgenserver.py?) might be located under /root and apache probably runs as a non-priviliged user such as www-data, that user won't be able to access either your python script and in turn not the bash that the python would run.
Consider instead calling bash with the script as a parameter.
#! /usr/bin/env python
import os
import json,sys
from firebase import firebase
import requests
import subprocess
arg = sys.argv[1]
path = "/root/files/"+str(arg)
print path
if not os.path.exists(path):
os.makedirs(path)
subprocess.call(['/bin/bash', '/root/Final/clone.sh', path)
Now, this is NOT the most pretty of solutions.
But what you got before was probably a generic "Permission denied" error in the background (check your /var/log/apache/error.log).
What this does is start /bin/bash as a subprocess with the first parameter being the script you want to execute.
But you have zero error handling here and you can't interract with the process very much.
Consider doing something like this instead:
import subprocess
handle = subprocess.Popen(['/bin/bash', '/root/Final/clone.sh', 'parameter'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
while handle.poll() is None:
print(handle.stdout.read()) # There's some optimizations here to be done as well so it's not a blocking call etc.
handle.stdout.close()
handle.stdin.close()
And one last tip is not to place stuff in /root/ at all if you're integrating it into a web front-end/backend type of thing.
You're asking for trouble : )
Another way is to make use of sudo
If you modify your exec() in PHP to run exec("sudo ...") and enable your web-user to run the scripts without a password prompt it could work.
Bare in mind, it's not recommended to give www-data sudo access, rather do something like this:
# useradd -m -G www-data -s /bin/bash wwwexec
# echo "myuser ALL=NOPASSWD: /usr/bin/python" >> /etc/sudoers
and change your PHP script to have the following:
exec("sudo -u wwwexec python /var/www/html/appgenserver.py $uid");
That way at least your entire web service isn't given root access via the default username.
The way to do it
Would be to place your appgenserver.py under /var/www/cgi-bin/ instead, and create a CGI hook for .py in your apache configuration and hand over the user to the URL prividing you access to the CGI script.
That way everything should be according to best practices even tho, in theory, you could get your original solution to work.
For instance, this guide should get you started.

Image Processing (OpenCV with PHP) - Issue with the exec command

I have setup OpenCV 3.0 with python3.4 binding on ubuntu 14.04. I run OpenCV using virtualenv. So, everytime I have to run the workon cv command.
Now I want to run a python script that uses OpenCV library from PHP using the exec command.
exec("workon cv");
exec("python3 hough_circles.py")
This is the error :
sh: 1: workon: not found
Traceback (most recent call last):
File "hough_circles.py", line 1, in <module>
import cv2
ImportError: No module named 'cv2'
Two issues...
1. PATH to workon
The error message is telling you it doesn't know where workon is, so you better tell it the full path to where it is so exec() can find it, e.g.:
exec("/usr/local/bin/workon cv");
The /usr/local/bin above is just an example, if you want to know where it is on your system, run:
which workon
and use the output.
2. Subprocesses are independent
Even when you have got that set correctly, the process that executes workon then exits and you start a fresh, shiny new one - in which you have not run workon. So, you better do both things in the same process like this:
exec("/usr/local/bin/workon cv && /path/to/python3 hough_circles.py");

PHP command not executed system(), exec() or passthru()

I am trying to run a command line file conversion using open office.
openoffice pdf filename.doc 2>&1
when i execute in command line as root it works fine and the file is converted. However when i pass the above command in a PHP file as apache user, it does not execute.
I tried all three PHP command line execution:
$command_output=system($command_line,$rtnval);
$command_output=exec($command_line,$rtnval);
$command_output=passthru($command_line,$rtnval);
Also,
echo print_r($rtnval);
echo print_r($command_output);
$rtnval returns 1 and $command_output 1. I am confused unable to know what is the linux (centos) response to above command passed. It is very frustration because unable to know what the system response when i try to execute the command.
I also included /etc/suders permission for apache to run the open office command.
apache ALL: (ALL) NOPASSWD: /path/to/openoffice
still the command is not execute in PHP as apache user.
What am i missing for PHP as apache user not to execute this command?
It could be that openoffice is not in PATH. Try to execute it with the full path.
To run your command as if you were the apache user, just try this in a shell:
# switch to superuser
sudo su -
# then switch to the apache user
su - www-data
You will find yourself in a quite restricted shell, from which it is usually not possible to start openoffice. Indeed, it requires a lot of environment, that would be unsafe to completely set up for apache anyway.
AFAIK, better create a dedicated user that is allowed to run your command (eg a regular "www-runner" user), then "su" to it from PHP. Other security measures include chroot'ing the dedidacted user, or using apparmor to limit what and where it is allowed to run. In any case, never let www-data run something as root by adding www-data to the sudoers: this is way too dangerous!
You can also have a look at libapache2-mod-suphp (a suid apache module to run php scripts with the owner permissions).It is easier to use than the dedicated suEXEC apache beast (http://httpd.apache.org/docs/2.0/suexec.html). The latter really is not for a quick fix ;)
It is possible that your php in apache runs in safe mode or what's it called, in which system() function and alike are disabled.
This answer, actually, assumes that what you call "running as apache user" is in fact running in apache environment, whatever it is.

What is the difference between running a script from the command line and from exec() with PHP?

I'm trying to run a Python script using exec() from within PHP. My command works fine when I run it directly using a cmd window, but it produces an error when I run it from exec() in PHP.
My Python script uses NTLK to find proper nouns. Example command:
"C:\Python25\python.exe" "C:\wamp\projects\python\trunk\tests\find_proper_nouns.py" "I went to London this morning"
returns [London] when I run it from cmd, but throws an error in the Apache log when I run the same command from exec().The script is defintely getting run OK - if I change the python script to be print "Hello World" that is returned fine.
I know it's a big ask for anyone to know how to fix this NLTK error, but I could really do with any pointers as to why running it from exec is different to cmd. (The command is identical).
I'm running WAMP on Windows 7 with Apache 2.2.11.
Here's the error in the Apache log:
Traceback (most recent call last):
File "C:\wamp\projects\python\trunk\tests\find_proper_nouns_command_line.py", line 6, in <module>
parts = nltk.pos_tag(text)
File "C:\Python25\lib\site-packages\nltk\tag\__init__.py", line 62, in pos_tag
tagger = nltk.data.load(_POS_TAGGER)
File "C:\Python25\lib\site-packages\nltk\data.py", line 590, in load
resource_val = pickle.load(_open(resource_url))
File "C:\Python25\lib\site-packages\nltk\data.py", line 669, in _open
return find(path).open()
File "C:\Python25\lib\site-packages\nltk\data.py", line 451, in find
raise LookupError(resource_not_found)
LookupError:
**********************************************************************
Resource 'taggers/maxent_treebank_pos_tagger/english.pickle' not
found. Please use the NLTK Downloader to obtain the resource:
>>> nltk.download().
Searched in:
- 'C:\\nltk_data'
- 'D:\\nltk_data'
- 'E:\\nltk_data'
- 'C:\\Python25\\nltk_data'
- 'C:\\Python25\\lib\\nltk_data'
- 'C:\\Windows\\system32\\config\\systemprofile\\AppData\\Roaming\\nltk_data'
**********************************************************************
You have to run nltk.download() and choose 'maxent_treebank_pos_tagger'. You must make a python script and in it put:
#!/usr/bin/python
import nltk
nltk.download('maxent_treebank_pos_tagger');
then run it from command line. It will install the data files for the POS tagges, which you don't have installed yet.
After you do this it should work.
Your web server likely runs with other privileges than yourself. Possible problems include:
Path/file permission: can the web server user access the files it needs?
Different environment: are all necessary environment variables (PATH, Python-specific stuff, …) set?
Configuration: are there per-user configurations for Python or the module?
Tip: execute set in both the command prompt and from the PHP process and check the differences.
From the shell/terminal, you can use:
sudo python -m nltk.downloader maxent_treebank_pos_tagger
It will install maxent_treebank_pos_tagger (i.e. the standard treebank POS tagger in NLTK).

Categories