Writing CGI scripts
CGI scripts are a simple way of providing dynamic content to users. For example, you could write a program to allow users to run calculations over the network, or you could provide access to a centralized database. However, CGI scripts require a lot of processing. On a busy server, it would be more efficient to write a module for Apache.
- Find out which httpd.conf your system is
using. Each installation puts this file in a different location.
This command prints the location of the httpd binary that is actually used:
Run `strings' on the binary to find out where it looks for httpd.conf:cat /etc/rc.d/apache | grep httpd | grep bin
In this example, we will assume httpd.conf was in /etc/httpd.strings /usr/local/apache/bin/httpd | grep httpd.conf
- Edit /etc/httpd/httpd.conf and uncomment the
following lines:
You could also enable `includes' by commenting out any lines containingAddType text/html .shtml AddHandler server-parsed .shtml AddType text/x-server-parsed-html .shtml Options ExecCGI
and addingIncludesNOEXEC
If any point in the path to the CGI files is a symlink, this must be changed toOptions Includes
or you will get "Access Forbidden". (This has to be done in several places.) Another possible cause of "Access Forbidden" are incorrectly set permissions. One way to distinguish between these two possibilities is to su to wwwrun (or whatever user Apache is running as) and try to run the CGI script manually. If it can be run manually, the problem is in the httpd configuration file; if not, the problem is probably with file permissions.Options Includes FollowSymLinks
The AddType option makes the server parse all files with the extension .shtml. It is possible to make the server parse ordinary .html files, but this is not a good idea, as it will degrade your system performance. Don't enable `includes' unless you absolutely have to. - Restart the server.
- Before creating a CGI file, make sure the server is handling
CGI correctly by typing
in a browser. If test-cgi is in cgi-bin, it should print something likehttp://localhost/cgi-bin/test-cgi
Click here for a copy of the test-cgi script.CGI/1.0 test script report: argc is 0. argv is . SERVER_SOFTWARE = Apache/1.3.26 (Unix) PHP/4.2.3 SERVER_NAME = carbon.my_hostname.com GATEWAY_INTERFACE = CGI/1.1 SERVER_PROTOCOL = HTTP/1.0 SERVER_PORT = 80 REQUEST_METHOD = GET HTTP_ACCEPT = image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* PATH_INFO = PATH_TRANSLATED = SCRIPT_NAME = /cgi-bin/test-cgi QUERY_STRING = REMOTE_HOST = REMOTE_ADDR = 192.168.100.1 REMOTE_USER = AUTH_TYPE = CONTENT_TYPE = CONTENT_LENGTH =
- Create an executable file in /usr/local/apache/cgi-bin. This can be a
perl script, a shell script, or a binary, for example:
Set its permissions to:#!/bin/sh set -f echo Content-type: text/plain echo echo Logging asdf logger asdf
On some servers, the script won't run if the permissions are not set to 700 or if it is not in the cgi-bin directory. Compiled binaries are much safer than shell scripts from a security standpoint. In some configurations, the script must have the extension .cgi or .pl. The script will be run with the permissions of its owner. The script must write the line "Content-type: text/plain" followed by a blank line to stdout before anything else.-rwx------ 1 wwwrun nogroup 82 Oct 23 22:42 myscript
- In your shtml file, add the line:
or create a form with an "action" (see below). Note: the shtml file must be in /usr/local/apache/htdocs or it will not be executed.<!--#EXEC CGI="/cgi-bin/myscript"-->
- Note that there are severe limitations on what you can do.
You can't, for example, execute an X-Window type application
or an interactive program.
The CGI interface can only handle text I/O. Graphics must be
done with HTML. The script can, however, output HTML and create
image files that are then loaded by the remote user's browser.
Alternatively, to send a GIF file, first send
followed by a blank line, then send the binary GIF file to stdout.Content-type: image/gif
- Any commands in the script must be executable by wwwrun (or whatever user is running httpd). This may mean using sudo or making the binary suid (by typing "chmod a+s < program>"). This has obvious security implications. Be sure to restrict access to the file in /etc/httpd/httpd.conf.
Error messages
Internal Server Error The server encountered an internal
error or misconfiguration and was unable to complete your
request.
This can be caused by a line in your script that could not
be executed. For example, if you had the line
#!/usr/local/bin/csh |
There should also be no spaces between <! and --#, and none at the end ..program-->.
Check to make sure the script is executable by "su"-ing to wwwrun and running the script manually.
When testing the script, you must exit and restart Netscape each time you make a change. Hitting 'refresh' doesn't always work.
Premature end of script headers: myprogram
This message in the error_log file means the server was unable to
execute your script. Check to make sure that the AddType, AddHandler,
and Options are set correctly in the httpd.conf file. Also check to
make sure it is using the correct httpd.conf file. Apache may be
using the httpd.conf file in /usr/local/apache/conf or the httpd.conf
in /etc/httpd. Finally, check to make sure the script is executable
by the server (usually wwwrun or nobody).
Symbolic link not allowed: /usr/local/apache2/cgi-bin/some-symlink
This error usually means one of two things: either your permissions are wrong, or your httpd.conf is missing an Option FollowSymLinks statement.
- The user that owns httpd (usually wwwrun) must have execute permission in all subdirectories leading to the cgi script. The cgi script itself must be executable by wwwrun.
- Sometimes, the cgi script calls some other program that is located somewhere else or has its permissions set wrong. Check the cgi script.
- In your httpd.conf file, you need to change three places to get
cgi scripts to run:
1. In your ScriptAlias line:
2. In the cgi-bin options section. If this one is not set, cgi programs in the cgi-bin directory will work but programs elsewhere will not. Also, make sure allow from all is set, or cgi programs won't run.ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
3. In the main options section. If ExecCGI is not set here, your cgi programs won't run. If FollowSymLinks isn't set here, html files under a symlink won't be found.# this path must match the path in ScriptAlias <Directory "/usr/local/apache2/cgi-bin"> AllowOverride All Options FollowSymLinks Order allow,deny Allow from all </Directory>
4. Check for stupid errors, like editing the wrong copy of httpd.conf:Options Indexes FollowSymLinks ExecCGI Includes SymLinksifOwnerMatch
ps -aux | grep httpd strings /usr/local/apache2/bin/httpd | grep httpd.conf
Example shtml file
The shtml file below will display a Submit button and a selection box with 3 items visible. When the Submit button is clicked, the file 'printer.sh' is executed.
<HTML> <HEAD> <TITLE> Printers</TITLE> </HEAD> <BODY> <FORM ACTION="/cgi-bin/printer.sh" METHOD="GET"> <SELECT NAME="hpbw" SIZE=3> <OPTION SELECTED> Check status <OPTION> Check queue <OPTION> Print test page <OPTION> Break Printer <OPTION> Remove job from queue </SELECT> <INPUT TYPE="submit" VALUE="Submit"> Submit request </FORM> </BODY> </HTML> |
#!/bin/sh echo "Content-type: text/plain" echo "" echo case "$QUERY_STRING" in hpbw=Check+status) echo Printer status lpc stat hpbw ;; hpbw=Check+queue) echo Print queue lpq -Phpbw ;; hpbw=Print+test+page) echo Printing test page ... lpr -Phpbw testpage.ps ;; hpbw=Break+Printer) echo Segmentation fault echo Printer is now broken. echo Way to go. ;; *) echo Unrecognized command esac echo Press Back to continue ... |
Alternatively, you could use
<!--#exec cmd=/usr/local/apache/cgi-bin/mycommand--> or <!--#exec cgi=/cgi-bin/mycommand--> |
Example using Radio Buttons
Here is an example that uses radio buttons to select what to send:
<FORM METHOD="GET" ACTION="http://search.somewhere.com/cgi-bin/QResults"> <B>Find</B> <INPUT TYPE="text" VALUE="" NAME="keyword" SIZE="25" MAXLENGTH="150"> in <INPUT TYPE="radio" NAME="mediaType" VALUE="Book"CHECKED>Books <INPUT TYPE="radio" NAME="mediaType" VALUE="Music">Music <INPUT TYPE="radio" NAME="mediaType" VALUE="Video">Videos <INPUT TYPE="submit" NAME="submit" VALUE="Find!"> </FORM> |
This script will execute the file "/cgi-bin/QResults" on search.somewhere.com and send its data through QUERY_STRING. For example, if the first radio button was clicked, it would send the string
keyword=&mediaType=Book&submit=Find%21 |
keyword=abcde&mediaType=Book&submit=Find%21 |
Example shtml file using POST
Here is one that uses POST. POST is typically used when there is no data to send, or when there is a large amount of data to send.
<FORM METHOD="POST" ACTION="http://www.somewhere.com/cgi-bin/Logoff"> <INPUT NAME="url" TYPE="hidden" VALUE="http://www.somewhere.com/"> <INPUT TYPE="SUBMIT" VALUE="Finished Shopping"> </FORM> |
Example shtml file using POST to send data
This example will execute the Logoff script and will send data from a single-line text box and a multi-line text box. If TYPE="hidden" is present, the single-line text box will be invisible, but the text would still be sent. The ACTION tag can be a URL on a different server, or you can omit the address if the script is on the same server as the Web page.
<FORM METHOD="POST" ACTION="/cgi-bin/Logoff"> <INPUT NAME="url" VALUE="http://www.somewhere.com/"><BR> <TEXTAREA NAME="address" ROWS=6 COLS=60> The user can enter multiline text in this area. </TEXTAREA> <INPUT TYPE="SUBMIT" VALUE="Finished Shopping"> </FORM> |
An extra line would have to be added to the CGI script to acquire the data from stdin.
#!/bin/sh echo Content-type: text/plain echo echo QUERY_STRING = "$QUERY_STRING" echo REMOTE_ADDR = $REMOTE_ADDR echo CONTENT_LENGTH = $CONTENT_LENGTH echo Reading stuff from stdin read STUFF echo $STUFF echo Done reading stuff from stdin |
QUERY_STRING = REMOTE_ADDR = 192.168.100.1 CONTENT_LENGTH = 110 Reading stuff from stdin url=http%3A%2F%2Fwww.somewhere.com%2F&address=The+user+ca n+enter+%0D%0Amultiline+text%0D%0Ain+this+area.%0D%0A Done reading stuff from stdin |
WARNING: For a real CGI script, you must sanitize any data sent by the user to prevent your program or the shell from interpreting it as a command. Not doing so can be a major security risk. By using specially formatted text, a user might be able to open a command shell or xterm, mail themselves your password file, or change system files and gain remote root access to your computer. The following characters (and their hexadecimal equivalents) should always be removed before passing a user string to a shell: & ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r
Summary of input tags
- TEXT
- CHECKBOX
- RADIO
- SUBMIT
- RESET
- HIDDEN
- IMAGE
Back