4.2. Writing and Executing Scripts
Bear in mind that the CGI script must be executable in the opinion of your operating system. In order to test it, you can run it from the console with the same login that Apache uses. If you cannot, you have a problem that's signaled by disagreeable messages at the client end, plus equivalent stories in the log files on the server, such as:
You don't have permission to access /cgi-bin/mycgi on this server
You need to do either of the following:
If you have not used ScriptAlias, then Options ExecCGI must be on. It will normally be on by default. See the section Section 4.5, "Debugging Scripts", later in this chapter, for more information on fixing scripts.
To experiment, we have a simple test script, mycgi.cgi, in two locations: .../cgi-bin to test the first method above, and .../site.cgi/htdocs to test the second. When it works, we would write the script properly in C or Perl or whatever.
The script mycgi.cgi looks like this:
#!/bin/sh echo "content-type: text/plain" echo echo "Have a nice day"
Under Win32, providing you want to run your script under COMMAND.COM and call it mycgi.bat, the script can be a little simpler than the Unix version -- it doesn't need the line that specifies the shell:
@echo off echo "content-type: text/plain" echo. echo "Have a nice day"
The @echo off command turns off command-line echoing, which would otherwise completely destroy the output of the batch file. The slightly weird-looking "echo." gives a blank line (a plain echo without a dot prints "ECHO is off").
If you are running a more exotic shell, like bash or perl, you need the `shebang' line at the top of the script to invoke it:
#!shell path ...
A CGI script consists of headers and a body. Everything up to the first blank line (strictly speaking, CRLF CRLF, but Apache will tolerate LF LF) is header, and everything else is body. The lines of the header are separated by LF or CRLF. A list of possible headers is to be found in the draft CGI 1.1 specification, from which this is a quotation:
The CGI header fields have the generic syntax: generic-header = field-name ":" [ field-value ] NL field-name = 1*<any CHAR, excluding CTLs, SP and ":"> field-value = *( field-content | LWSP ) field-content = *( token | tspecial | quoted-string ) The field-name is not case sensitive; a NULL field value is equivalent to the header field not being sent. Content-Type The Internet Media Type  of the entity body, which is to be sent unmodified to the client. Content-Type = "Content-Type" ":" media-type NL This is actually an HTTP-Header rather than a CGI-header field, but it is listed here because of its importance in the CGI dialogue as a member of the "one of these is required" set of header fields. Location This is used to specify to the server that the script is returning a reference to a document rather than an actual document. Location = "Location" ":" ( fragment-URI | rel-URL-abs-path ) NL fragment-URI = URI [ # fragmentid ] URI = scheme ":" *qchar fragmentid = *qchar rel-URL-abs-path = "/" [ hpath ] [ "?" query-string ] hpath = fpsegment *( "/" psegment ) fpsegment = 1*hchar psegment = *hchar hchar = alpha | digit | safe | extra | ":" | "@" | "& | "="
So, the script must send at least one header line: Content-Type. We set it to text/plain to get a nicely formatted output screen. Failure to include it results in an error message on the client, plus equivalent entries in the server log files:
The server encountered an internal error or misconfiguration and was unable to complete your request
Headers must be terminated by a blank line, hence the second echo.
We are going to call our script from one of the Butterthlies forms: form_summer.html. Depending on which location and calling method we use for the script, we need slightly different invocations in the form.
4.2.1. Script in cgi-bin
User webuser Group webgroup ServerName www.butterthlies.com DocumentRoot /usr/www/site.cgi/htdocs ScriptAlias /cgi-bin /usr/www/cgi-bin
We need to edit the form .../site.cgi/htdocs/form_summmer.html so that the relevant line reads:
<!-- UNIX --> <FORM METHOD=POST ACTION="cgi-bin/mycgi.cgi"> <!-- Win32 --> <FORM METHOD=POST ACTION="cgi-bin/mycgi.bat">
Since CGI processing is on by default, this should work. When you submit the Butterthlies order form, and thereby invoke the CGI script named by ACTION, you are sent the message "Have a nice day."
You would probably want to proceed in this way, that is, putting the script in the cgi-bin directory, if you were offering a web site to the outside world and wanted to maximize your security.
4.2.2. Script in DocumentRoot
The other method is to put scripts in amongst the HTML files. You should only do this if you trust the authors of the site to write safe scripts (or not write them at all) since security is much reduced. Generally speaking, it is safer to use a separate directory for scripts, as explained previously. First, it means that people writing HTML can't accidentally or deliberately cause security breaches by including executable code in the web tree. Second, it makes life harder for the Bad Guys: often it is necessary to allow fairly wide access to the nonexecutable part of the tree, but more careful control can be exercised on the CGI directories.
But regardless of these good intentions, we put mycgi.cgi in .../site.cgi/htdocs. The Config file is now:
<!-- UNIX --> <FORM METHOD=POST ACTION="mycgi.cgi"> <!-- WIN32 --> <FORM METHOD=POST ACTION="mycgi.bat">
Copyright © 2001 O'Reilly & Associates. All rights reserved.