6

I'm having an issue executing a Python script from a PHP script. My client uses Bluehost, so I installed a third party module (numpy) for Python with the easy_install method described here: https://my.bluehost.com/cgi/help/530?step=530

To demonstrate my issue, I've created two python scripts and a PHP script.

hello.py contains:

print "Hello, World!"

hello-numpy.py contains:

import numpy
print "Hello, World!"

The PHP script contains:

Output from exec('python hello.py'): <?php echo exec('python hello.py'); ?><br>
Output from exec('python hello-numpy.py'): <?php echo exec('python hello-numpy.py'); ?><br>
Output from exec('whoami'): <?php echo exec('whoami'); ?>

I then get this output from PHP:

Output from exec('python hello.py'): Hello, World!
Output from exec('python hello-numpy.py'):
Output from exec('whoami'): venicetw

However, running these scripts from the SSH window yields the following results:

# python hello.py
Hello, World!
# python hello-numpy.py
Hello, World!
# whoami
venicetw

It seems PHP doesn't get any output when the Python script imports numpy, but it works fine from SSH. Furthermore, PHP gets a return status of 0 for hello.py but 1 for hello-numpy.py. I thought it might be a permissions issue, but both PHP and SSH are running as the "venicetw" user. What would prevent PHP and Apache from getting the output from the Python script? Is it something I can discuss with Bluehost, or something else I should check? We're using Apache 2.2.21, PHP 5.2.17, Python 2.4.3, and numpy 1.6.0.

Update: SSH prints the following Python paths:

/home8/venicetw/public_html/venicenoise/python
/home8/venicetw/.local/lib/python2.4/site-packages/ogcserver-0.1.0-py2.4.egg
/home8/venicetw/.local/lib/python2.4/site-packages/PIL-1.1.7-py2.4-linux-x86_64.egg
/home8/venicetw/.local/lib/python2.4/site-packages/lxml-2.3.2-py2.4-linux-x86_64.egg
/home8/venicetw/.local/lib/python2.4/site-packages/WebOb-1.2b2-py2.4.egg
/home8/venicetw/.local/lib/python2.4/site-packages/PasteScript-1.7.5-py2.4.egg
/home8/venicetw/.local/lib/python2.4/site-packages/PasteDeploy-1.5.0-py2.4.egg
/home8/venicetw/.local/lib/python2.4/site-packages/Paste-1.7.5.1-py2.4.egg
/home8/venicetw/.local/lib/python2.4/site-packages/numpy-1.6.0-py2.4-linux-x86_64.egg
/home8/venicetw/.local/lib/python2.4/site-packages
/home8/venicetw/.local/lib/python/site-packages
/home8/venicetw/public_html/venicenoise/python
/usr/lib64/python24.zip
/usr/lib64/python2.4
/usr/lib64/python2.4/plat-linux2
/usr/lib64/python2.4/lib-tk
/usr/lib64/python2.4/lib-dynload
/usr/lib64/python2.4/site-packages
/usr/lib64/python2.4/site-packages/Numeric
/usr/lib64/python2.4/site-packages/PIL
/usr/lib64/python2.4/site-packages/gtk-2.0
/usr/lib/python2.4/site-packages

But Apache only prints these Python paths:

/home8/venicetw/public_html/venicenoise/python
/usr/lib64/python24.zip
/usr/lib64/python2.4
/usr/lib64/python2.4/plat-linux2
/usr/lib64/python2.4/lib-tk
/usr/lib64/python2.4/lib-dynload
/usr/lib64/python2.4/site-packages
/usr/lib64/python2.4/site-packages/Numeric
/usr/lib64/python2.4/site-packages/PIL
/usr/lib64/python2.4/site-packages/gtk-2.0
/usr/lib/python2.4/site-packages

Solution: By executing /usr/bin/env from both PHP and SSH, I was able to determine that PHP was missing an environment variable for the Python path where numpy is installed. In this case, by adding

putenv('PYTHONPATH=/home8/venicetw/.local/lib/python2.4/site-packages:/home8/venicetw/.local/lib/python/site-packages:');

to the beginning of the PHP script, everything works as expected.

1 Answers1

5

If PHP gets a return status of 1, that indicates that the process you ran encountered an error. (An nonzero exit status usually indicates an error on Unix style systems. A couple programs are different, e.g., diff.) Try examining the stderr produced by the subprocess to see what error messages are printed there.

You can show stderr this way:

Output from exec('python hello-numpy.py'):
    <?php echo exec('python hello-numpy.py 2>&1'); ?><br>

The 2>&1 instructs the shell to combine stderr and stdout into one stream. You normally don't want to do this, but it can make it easy to see the errors.

Update: Since the error you get is ImportError: No module named numpy we can try looking at Python's paths. It's possible that there are multiple Pythons installed on your system, and it's also possible that Apache's environment (root directory, etc) is different from the environment you get when you run Python over SSH. Try executing this Python script in both environments:

import sys, os
for path in sys.path:
    print path
print
print 'Root:', os.readlink('/proc/self/root') # Linux only

One of those paths should point to where numpy is installed, and perhaps it is missing when you run it in Apache. Or perhaps the Apache process has a different root directory, which would be inherited by the Python process.

Solution: Missing environment variable. See comments.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • Ah, got this: "ImportError: No module named numpy" I wonder if it's just a matter of restarting Apache? –  Jan 02 '12 at 19:26
  • Make sure you are accessing the same python version both times. – Has QUIT--Anony-Mousse Jan 02 '12 at 19:33
  • Just checked - they're both accessing Python 2.4.3. And being in a shared hosting environment, restarting Apache is not an option. –  Jan 02 '12 at 19:43
  • If helps, try using a virtual environment, so you can have the SAME envs a discard environment as a problem. – David Morabito Jan 02 '12 at 20:15
  • @Neil: Restarting Apache (probably) won't help anyway. See edited answer. – Dietrich Epp Jan 02 '12 at 20:49
  • See my update with the results. It seems Apache doesn't include the modules installed in .local. Your Linux-only line produced the error "NameError: name 'os' is not defined". –  Jan 02 '12 at 21:54
  • @Neil: The difference is probably in the environment variables. There should be an environment variable you can set from PHP that causes Python to search the correct path, try comparing environment variables from PHP and SSH by running the `/usr/bin/env` program. – Dietrich Epp Jan 02 '12 at 22:02
  • I was able to find the missing environment variable and set it with putenv() from PHP. Everything works now, thank you! –  Jan 02 '12 at 23:18