GRASS and PHP
Running Grass modules through an Webserver
For some reasons, you may want to call Grass modules within a html page instead of using the command line or a GUI. One way - among others - is to execute them out of a php script.
In the following, a few notes how to procceed for writing your own code:
Check your php installation
Save this code snipped in your server directory under the filename "doihavephp.php" and call it with a web browser:
<?php phpinfo(); ?>
There you will see detailed informations upon your server's php installation. If you see nothing, please check http://www.php.net for details how to get and install php on your machine.
Define the environment settings
By default, there are only a few variables set in the server environment. Save the following snippet under "env.php" and see what is set as default values for your server.
<?php //enable all error messages error_reporting(E_ALL); //print a line of text as a header for the following output echo "<hr>env:<br>"; //execute the env command and redirect the output $handle = popen('"env" 2>&1', 'r'); //wait a while for the results. this is not clean, but works for the first attempt sleep("1"); //collect the response $read = fread($handle, 4096); //print the response - if response is incomplete, increment the sleep delay echo $read; //don't forget to close the handle pclose($handle); echo "<br>done.<hr>"; ?>
Note: Please be careful when modifying environment variables permanent in files like /etc/bashrc. You may cause by accident security leaks. Please check with your IT manager how to grant security when your machine is visible to the internet.
The environment variables are set by using the *<verbatim>putenv("VARIABLE")</verbatim>* command. They are only valid during the runtime of the actual script, so you have to send the full set for each request.
<?php error_reporting(E_ALL); putenv("GRASS_WIDTH=900"); echo "<hr>env:<br>"; $handle = popen('"env" 2>&1', 'r'); sleep("1"); $read = fread($handle, 4096); echo $read; pclose($handle); echo "<br>done.<hr>"; ?>
The list shows some environment variables used by GRASS modules. Please note, that the content has to be adapted to meet your system's specific setup and that it may be incomplete or partially false in some combinations.
|GISBASE||/usr/local/grass-6.1.cvs||"...where the happy little creatures hide..." (Bob Ross)|
|LD_LIBRARY_PATH||/usr/lib:/usr/local/grass-6.1.cvs/lib:/usr..||path to ALL required libraries|
|GISRC||/gd/.grassrc6_php||Grass resource file -please see related paragraph below|
Glynn clarified regarding GRASS_LD_LIBRARY_PATH:
You need to set LD_LIBRARY_PATH. GRASS_LD_LIBRARY_PATH is merely a saved copy so that the value can be restored if LD_LIBRARY_PATH is reset due to running a setuid/setgid executable (e.g. xterm). LD_LIBRARY_PATH is what the Linux loader actually uses to locate shared libraries.
Redirecting STDOUT and STDERR
When calling a function, you may either collect the output in a handle as shown in the example before or redirect it in a text file. The syntax for redirection is:
system("g.version > version.txt 2> version_err.txt");
Another option is to use PHP function proc_open() which gives you means to use stdin, stdout and stderr in a flexible fashion. It is especially handy if you want to feed data to a GRASS module.
Deleting prior output files
Remove output files immediately after use or before rewriting them to ensure that you will not work with old stuff in case of troubles.
system("rm -f version.txt");
system("rm -f version_err.txt");
The GRASS Resource File
You may copy your .grassrc6 file to your script directory and e.g. name it .grassrc6_php. It contains the follwing lines and has to be adapted to fit into your setup:
GISDBASE: /gd GRASS_GUI: text MAPSET: etopo5 LOCATION_NAME: smallworld MONITOR: PNG
I can't get outside a shell access to a mapset even when calling in advance g.access with grant for both user and group. When chowning the entire location directory to user www-data, it works, but then there is no longer access from the grass shell.
Glynn wrote: You can't select a mapset as the current mapset unless you actually own it. Having write permission isn't sufficient.
This check is implemented in G__mapset_permissions() and G__mapset_permissions2() in lib/gis/mapset_msc.c. You will have to modify those functions to disable the check if you want to be able to modify mapsets which you don't own.
If your web application only reads the data, you can create a single mapset directory owned by the account under which the PHP script runs, then either use g.mapsets or explicit map@mapset references to access maps in other mapsets.
One working solution
Thist works at least on Debian with Apache. Contrary to the common settings where Apache is running as user 'nobody', in Debian, the Apache user is 'www-data' and it belongs to the group 'www-data':
Make sure the permissions of your location directory include the group write permission, and your username also belongs to the group www-data.
As www-data (In principle: '
su www-data' as root; in practice, also '
sudo su www-data' if your username has the necessary rights.) run
grass. In the location window, give the location of your data (/home/johndoe/grass or whatever). Now all the mapsets you create will have the necessary rights properly set up both in the filesystem as in GRASS.
In the same way, you can also set up the database access rights.
This approach has the nice feature, that you don't have to worry about the .grassrc6 or .grasslogin6 files; the right data will go to the right place automatically, most probably in /var/www, depending where the $HOME setting of Apache points to.
--Harri 18:44, 4 November 2006 (CET)
Resources and examples
Earthquake epicenters dynamically inserted (see source code link there at page bottom): http://grass.itc.it/spearfish/php_grass_earthquakes.php
A simple GRASS Map on the fly: http://grass.itc.it/spearfish/php_grassmap.php
related e-mails: http://grass.itc.it/pipermail/grass5/2004-August/015106.html
Many thanks to Glynn Clements, Markus Neteler and Sharyn Namnath for code and help!
Simplified Method (for GRASS >= 6.4.x)
VERY IMPORTANT Firstly you must control if SHELL enviroment for your web server is set. You can done a script like this
<?php system ('export -p'); ?>
and in your answer you must found SHELL=/bin/bash or something similar. If your SHELL enviroment isn't set you must editing the apache enviroments file (in debian and ubuntu is in /etc/apache2/envvars) and add a line with export SHELL=/bin/bash
With putenv you set the variable GRASS_BATCH_JOB=/path/to/your/bash/script and after you execute GRASS with the path to the gisbase/location/mapset as parameter in a system call. Remember gisbase, location and mapset must be accessible for the apache user (in debian and ubuntu www-data, use e.g., "ps -aef | grep httpd" to figure out the user name). At the end of your php code you must deactivate the batch job mode. That's all.
<?php putenv ('GRASS_BATCH_JOB=/path/to/your/bash/script'); system ('grass64 /path/to/your/grassdata/location/mapset'); system ('unset GRASS_BATCH_JOB); ?>