cgic 2.02: an ANSI C library for CGI Programming
The LATEST
documentation is available here. Check often
for new releases.
IMPORTANT NOTICES:
If you have CGIC 1.05 or earlier, you should upgrade
to CGIC 1.07,
or to CGIC 2.02 or better, in order to obtain important security fixes.
If you have CGIC 2.0 or CGIC 2.01 and you use the
cgiCookie routines, you should upgrade to CGIC 2.02 or better, in order
to obtain
important security fixes.
Table of Contents
cgic can be used free of charge, provided that a
credit notice is provided online. Alternatively,
a nonexclusive Commercial License can be purchased, which
grants the right to use cgic without a public credit notice.
Please see the file license.txt
for the details of the Basic License and Commercial License,
including ordering information for the Commercial License.
Thanks are due to Robert Gustavsson, Ken Holervich, Bob
Nestor, Jon Ribbens, Thomas Strangert, Wu Yongwei, and other CGIC users
who have corresponded over the years. Although the implementation
of multipart/form-data file upload support in CGIC 2.x is my own, I
particularly wish to thank those who submitted their own
implementations of this feature.
STOP! READ THIS FIRST! REALLY!
Are you getting a "server error," indicating that your web server
"cannot allow POST to this URL," or a similar message? YOU
MUST CONFIGURE YOUR WEB SERVER TO ALLOW CGI PROGRAMS, AND YOU MUST
INSTALL CGI PROGRAMS IN THE LOCATION (OR WITH THE EXTENSION) THAT YOUR
WEB SERVER EXPECTS TO SEE. Please don't send me email about
this, unless you wish me to configure your web server for you; I can
certainly do that for $50/hr, but you can probably straighten this out
yourself or have your web server administrator do it.
Free Support
Anyone can send questions
about the gd and cgic libraries
via my support page.
However, I receive a very large volume of email on many subjects, and
while I do my best to respond to all queries this can take some time.
Sometimes the response must take the form of an eventual new release or
an addition to a FAQ or other document, as opposed to an detailed
individual response.
Hourly Support
Those requiring support in detail may arrange for direct support
from the author, Thomas Boutell, at the rate of $50/hr, billed
directly by credit card. Purchase orders are also accepted from
Fortune 500 corporations and institutions in good standing.
To make arrangements, contact
us via our
regular contact page,
or use our secure
message page. To avoid delay, be sure to specifically mention that
you wish to purchase CGIC support at the hourly rate above.
- In CGIC 2.0 and 2.01, if the HTTP_COOKIE environment
variable
was exactly equal to the name of a cookie requested with
cgiCookieString,
with no value or equal sign or other characters present, a buffer
overrun could take place. This was not normal behavior and it is
unknown whether any actual web server would allow it to occur, however
we have of course released a patch to correct it. Thanks to Nicolas
Tomadakis.
- cgiCookieString returned cgiFormTruncated when
cgiFormSuccess would
be appropriate. Fixed; thanks to Mathieu Villeneuve-Belair.
- Cookies are now set using a simpler Set-Cookie:
header, and with
one header line per cookie, based on data collected by Chunfu Lai.
- Memory leaks in cgiReadEnvironment fixed by Merezko
Oleg. These
memory leaks were not experienced in a normal CGI situation,
only
when reading a saved CGI environment.
- Makefile supports "make install"
- Compiles without warnings under both C and C++ with
strict
warnings and strict ANSI compliance enabled
- Builds out of the box on Windows (#include
<fcntl.h> was needed)
- Rare problem in cgiReadEnvironment corrected; no
impact on
normal CGI operations
- cgiCookieString now sets the result to an empty
string
when returning cgiFormNotFound
- Minor code cleanups
1. CGIC 2.0 provides support for file upload fields. User-uploaded
files are kept in temporary files, to avoid the use of
excessive swap space (Solaris users may wish to change the cgicTempDir
macro in cgic.c before compiling).
The cgiFormFileName, cgiFormFileContentType, cgiFormFileSize, cgiFormFileOpen, cgiFormFileRead, and cgiFormFileClose
functions
provide a complete interface to this new functionality. Remember,
the enctype attribute of the form tag
must be set to multipart/form-data when <input
type="file"> tags are used.
2. CGIC 2.0 provides support for setting and examining
cookies
(persistent data storage on the browser side).
The cgiCookieString,
and cgiCookieInteger
and cgiCookies
functions retrieve cookies. The cgiHeaderCookieSetString
and cgiHeaderCookieSetInteger
functions set cookies.
3. CGIC 2.0 offers a convenient way to retrieve a list
of all form fields.
The new cgiFormEntries
function performs this operation.
4. CGIC 2.0 provides convenience functions to correctly
escape
text before outputting it as part of HTML, or as part of the value of a
tag attribute, such as the HREF or VALUE
attribute. See cgiHtmlEscape,
cgiHtmlEscapeData,
cgiValueEscape
and cgiValueEscapeData.
5. Users have often asked the correct way to determine
which submit
button was clicked. This could always be accomplished in previous
versions,
but CGIC 2.0 also provides cgiFormSubmitClicked,
a convenient alternate label for the cgiFormCheckboxSingle
function.
A problem with the cgiFormString and related functions has been
corrected. These functions were previously incorrectly returning
cgiFormTruncated
in cases where the returned string fit the buffer exactly.
1. A potentially significant buffer overflow problem has been
corrected. Jon Ribbens correctly pointed out to me (and to the
Internet's bugtraq mailing list) that the cgiFormEntryString
function, which is used directly or indirectly by almost all
CGIC programs, can potentially write past the buffer passed
to it by the programmer. This bug has been corrected.
Upgrading to version 1.06 is strongly recommended.
2. The function cgiSaferSystem() has been
removed entirely. This function escaped only a few metacharacters,
while most shells have many, and there was no way to account for
the many different operating system shells that might be in use
on different operating systems. Since this led to a false sense
of security, the function has been removed. It is our recommendation
that user input should never be passed directly on the command line
unless it has been carefully shown to contain only characters
regarded as safe and appropriate by the programmer. Even then, it is
better to design your utilities to accept their input from standard
input rather than the command line.
Non-exclusive commercial license fee reduced to $200.
For consistency with other packages, the standard Makefile
now produces a true library for cgic (libcgic.a).
Version 1.03 sends line feeds only (ascii 10) to end Content-type:,
Status:, and other HTTP protocol output lines,
instead of CR/LF sequences. The standard specifies CR/LF.
Unfortunately, too many servers reject CR/LF to make
implementation of that standard practical. No server
tested ever rejects LF alone in this context.
Version 1.02 corrects bugs in previous versions:
- cgiFormDoubleBounded
specified
its arguments in the wrong order, with surprising results.
This bug has been corrected.
- Many small changes have been made to increase
compatibility.
cgic now compiles with no warnings under the compilers
available at boutell.com.
Version 1.01 adds no major functionality but corrects significant bugs
and incompatibilities:
- cgiFormInteger, cgiFormIntegerBounded, cgiFormDouble and cgiFormDoubleBounded
now
accept negative numbers properly. They also accept positive
numbers with an explicit + sign.
- Hex values containing the digit
9 are
now properly decoded.
- cgiFormString now
represents each newline as a single line feed (ascii 10 decimal)
as described in the documentation, not a carriage return
(ascii 13 decimal) as in version 1.0. The latter approach
pleased no one.
- cgiFormString and cgiFormStringNoNewlines
no longer erroneously return cgiFormEmpty in place of
cgiFormSuccess.
- The main() function of cgic now flushes standard
output
and sleeps for one second before exiting in order to inhibit
problems with the completion of I/O on some platforms. This was
not a cgic bug per se, but has been reported as a common problem
with CGI when used with the CERN server. This change should
improve compatibility.
- The single selection example in the testform.html
example now works properly. This was an error in the
form itself, not cgic.
- cgiRemoteUser and cgiRemoteIdent are now
documented accurately. They were reversed earlier.
cgic is an ANSI C-language library for the creation of CGI-based
World Wide Web applications. For basic information about
the CGI standard, see the
CGI documentation at NCSA.
cgic performs the following tasks:
- Parses form data, correcting for defective and/or
inconsistent browsers
- Transparently accepts both GET and POST form data
- Accepts uploaded files as well as regular form fields
- Provides functions to set and retrieve "cookies"
(browser-side persistent information)
- Handles line breaks in form fields in a consistent
manner
- Provides string, integer, floating-point, and single-
and
multiple-choice functions to retrieve form data
- Provides bounds checking for numeric fields
- Loads CGI environment variables into C strings which
are always non-null
- Provides a way to capture CGI situations for replay
in a debugging
environment, including file uploads and cookies
cgic is compatible with any CGI-compliant server
environment, and
compiles without modification in Posix/Unix/Linux and Windows
environments.
cgic is distributed via the web in two forms: as a Windows-compatible
.ZIP file, and as a gzipped tar file. Most users of Windows and
related operating systems have access to 'unzip' or 'pkunzip'. All
modern Unix systems come with 'gunzip' and 'tar' as standard equipment,
and gzip/gunzip
is not difficult to find if yours does not. Versions
of these programs for other operating systems are widely
available if you do not already have them.
Important: to use cgic, you will need
an ANSI-standard
C compiler. Under Unix, just obtain and use gcc. Most Unix systems have
standardiszed on gcc. Users of Windows operating systems should not
have
ANSI C-related problems as all of the popular compilers follow the ANSI
standard.
Note for Windows Programmers: you must
use a modern
32-bit compiler. Visual C++ 2.0 or higher, Borland C++ and the
mingw32 gcc compiler are all appropriate, as is cygwin. Do NOT
use an ancient 16-bit DOS executable compiler, please.
What Operating System Does Your WEB SERVER Run?
Remember, the computer on your desk is usually NOT your web server.
Compiling a Windows console executable will not give you a CGI program
that
can be installed on a Linux-based server.
Your web browser should inquire whether to save the file to disk
when you select one of the links below. Under Unix and compatible
operating systems, save it, then issue the following
commands to unpack it:
gunzip cgic202.tar.gz tar -xf cgic202.tar
This should produce the subdirectory 'cgic202', which will contain
the complete cgic distribution for version 2.02, including a copy of
this documentation in the file cgic.html.
Under Windows and compatible operating systems, save it,
open a console ("DOS") window, and issue the following commands to
unpack it:
unzip /d cgic202.zip
Or use the unzip utility of your choice.
This command also produces the subdirectory 'cgic201',
which will contain
the complete cgic distribution for version 2.0, including a copy of
this documentation in the file cgic.html.
cgic is available via the web from www.boutell.com:
The sample application 'cgictest.c' is provided as part of the
cgic distribution. This CGI program accepts input submitted
by the form cgictest.html.
On a Unix system, you can build cgictest simply by
typing
'make cgictest.cgi'. cgic.c and cgictest.c will be compiled and linked
together to produce the cgictest application. Under non-Unix
operating systems, you will need to create and compile an appropriate
project containing the files cgic.c and cgictest.c.
IMPORTANT: after compiling
cgictest.cgi, you will
need to place it in a location on your server system which is
designated by your server administrator as an appropriate location
for CGI scripts. Some servers are configured to recognize any
file ending in .cgi as a CGI program when it is found in any
subdirectory of the server's web space, but this is not always
the case! The right locations for CGI
programs vary greatly from one server to another. Resolving
this issue is between you, your web server administrator,
and your web server documentation. Before submitting a bug
report for cgic, make certain that the CGI example programs
which came with your server do work for you. Otherwise
it is very likely that you have a server configuration problem.
Once you have moved cgictest.cgi (or cgictest.exe, under
Windows)
to an appropriate cgi directory,
use the web browser of your choice to access the URL at which
you have installed it (for instance, www.mysite.com/cgi-bin/cgictest.cgi).
Fill out the various fields in any manner you wish, then
select the SUBMIT button.
If all goes well, cgictest.cgi will respond with a page
which
indicates the various settings you submitted. If not,
please reread the section above regarding the correct location in
which to install your CGI program on your web server.
- Are you using Visual C++ or Borland C++? Did
you forget to add
cgic.c to your project?
- Make sure you are using an ANSI C or C++
compiler.
(All of the Windows compilers are ANSI C compliant.)
If none of the above proves effective, please see the
section regarding support.
Note: All cgic applications must be linked to
the cgic.c module
itself. How to do this depends on your operating system; under Unix,
just use the provided Makefile as an example.
Since all CGI applications must perform certain initial
tasks, such as parsing form data and examining
environment variables, the cgic library provides its
own main() function. When you write applications that
use cgic, you will begin your own programs by writing
a cgiMain() function, which cgic will invoke when
the initial cgi work has been successfully completed. Your
program must also be sure to #include the file cgic.h.
Important: if you write your own main()
function, your program will not link properly. Your own
code should begin with cgiMain(). The library
provides main() for you. (Those who prefer different behavior
can easily modify cgic.c.)
Consider the cgiMain function of cgictest.c:
int cgiMain() { #ifdef DEBUG LoadEnvironment(); #endif /* DEBUG */ /* Load a previously saved CGI scenario if that button has been pressed. */ if (cgiFormSubmitClicked("loadenvironment") == cgiFormSuccess) { LoadEnvironment(); } /* Set any new cookie requested. Must be done *before* outputting the content type. */ CookieSet(); /* Send the content type, letting the browser know this is HTML */ cgiHeaderContentType("text/html"); /* Top of the page */ fprintf(cgiOut, "<HTML><HEAD>\n"); fprintf(cgiOut, "<TITLE>cgic test</TITLE></HEAD>\n"); fprintf(cgiOut, "<BODY><H1>cgic test</H1>\n"); /* If a submit button has already been clicked, act on the submission of the form. */ if ((cgiFormSubmitClicked("testcgic") == cgiFormSuccess) || cgiFormSubmitClicked("saveenvironment") == cgiFormSuccess) { HandleSubmit(); fprintf(cgiOut, "<hr>\n"); } /* Now show the form */ ShowForm(); /* Finish up the page */ fprintf(cgiOut, "</BODY></HTML>\n"); return 0; }
Note the DEBUG #ifdef. If DEBUG is defined at compile time, either by
inserting the line "#define DEBUG 1" into the program or by setting
it in the Makefile or other development environment, then the
LoadEnvironment function is invoked. This function calls cgiReadEnvironment() to restore a
captured CGI environment for debugging purposes. See
also the discussion of the capture program, which
is
provided for use in CGI debugging. Because this is a test program,
the cgiFormSubmitClicked function
is
also called to check for the use of a button that requests the
reloading
of a saved CGI environment. A completed CGI program typically would
never allow the end user to make that decision.
Setting Cookies
Next, one of the cgiHeader functions should be called.
This particular program demonstrates many features, including
the setting of cookies. If the programmer wishes to set a cookie,
the cookie-setting function must be called
first, before other headers are output. This is done by the
CookieSet() function of cgictest.c:
void CookieSet() { char cname[1024]; char cvalue[1024]; /* Must set cookies BEFORE calling cgiHeaderContentType */ cgiFormString("cname", cname, sizeof(cname)); cgiFormString("cvalue", cvalue, sizeof(cvalue)); if (strlen(cname)) { /* Cookie lives for one day (or until browser chooses to get rid of it, which may be immediately), and applies only to this script on this site. */ cgiHeaderCookieSetString(cname, cvalue, 86400, cgiScriptName, cgiServerName); } }
Since this is a test program, the cgiFormString
function is used to fetch the name and value from the form previously
filled
in by the user. Normally, cookie names and values are chosen to meet
the
needs of the programmer and provide a means of identifying the same
user again later.
The cgiHeaderCookieSetString
function sets the cookie by requesting that the web browser store it. There
is never any guarantee that this will happen!
Many browsers reject cookies completely; others do not necessarily keep
them as long as requested or return them with their values intact.
Always code defensively when using cookies.
The cname and cvalue parameters are of course the namd
and value for
the cookie. The third argument is the time, in seconds, that the
cookie should "live" on the browser side before it expires; in this
case it has been set to 86,400 seconds, which is exactly one day. The
browser may or may not respect this setting, as with everything
else about cookies.
The fourth argument identifies the "path" within the web
site for which
the cookie is considered valid. A cookie that should be sent back
for every access to the site should be set with a path of /.
In this case the cookie is relevant only to the CGI program itself, so cgiScriptName
(the URL of the CGI program, not including the
domain name) is sent. Similarly, a cookie can be considered relevant
to a single web site or to an entire domain, such as www.boutell.com
or the entire .boutell.com
domain. In this case, the current site on which the program is running
is the only relevant site, so cgiServerName
is used
as the domain.
Outputting the Content Type Header
Next, cgiHeaderContentType() is
called to indicate the MIME type of the document being output, in this
case "text/html" (a normal HTML document). A few other common MIME
types are
"image/gif", "image/jpeg" and "audio/wav".
Note that cgiHeaderStatus()
or cgiHeaderLocation() could have
been invoked instead to output an error code or redirect the
request to a different URL. Only one of the cgiHeader functions
should be called in a single execution of the program.
Important: one of the cgiHeader
functions,
usually cgiHeaderContentType(), must
be invoked before outputting any other
response to the user. Otherwise, the result will not be a valid
document and the browser's behavior will be unpredictable.
You may, of course, output your own ContentType and other
header information to cgiOut if you prefer. The
cgiHeader functions
are provided as a convenience.
Handling Form Submissions
Like many CGI programs, cgictest makes decisions about the way it
should behave based on whether various submit buttons have been
clicked.
When either the testcgic or saveenvironment button is present, cgictest
invokes the HandleSubmit function, which invokes additional functions
to
handle various parts of the form:
void HandleSubmit() { Name(); Address(); Hungry(); Temperature(); Frogs(); Color(); Flavors(); NonExButtons(); RadioButtons(); File(); Entries(); Cookies(); /* The saveenvironment button, in addition to submitting the form, also saves the resulting CGI scenario to disk for later replay with the 'load saved environment' button. */ if (cgiFormSubmitClicked("saveenvironment") == cgiFormSuccess) { SaveEnvironment(); } }
Handling Text Input
The Name() function of cgictest is shown below, in its simplest
possible form:
void Name() { char name[81]; cgiFormStringNoNewlines("name", name, 81); fprintf(cgiOut, "Name: "); cgicHtmlEscape(name); fprintf(cgiOut, " \n"); }
The purpose of this function is to retrieve and display the name that
was
input by the user. Since the programmer has decided that names should
be permitted to have up to 80 characters, a buffer of 81 characters
has been declared (allowing for the final null character). The cgiFormStringNoNewlines()
function is then invoked to retrieve the name and ensure that
carriage returns are not present in the name (despite the
incorrect behavior of some web browsers). The first argument
is the name of the input field in the form, the second argument
is the buffer to which the data should be copied, and the third
argument is the size of the buffer. cgic will never write beyond
the size of the buffer, and will always provide a null-terminated
string in response; if the buffer is too small, the string will
be shortened. If this is not acceptable, the cgiFormStringSpaceNeeded()
function can be used to check the amount of space needed; the
return value of cgiFormStringNoNewlines() can also be checked
to determine whether truncation occurred. See
the full description of
cgiFormStringNoNewlines().
Handling Output
Note that Name() writes its HTML output to cgiOut,
not
to stdout.
The actual name submitted by the user may or may not
contain
characters that have special meaning in HTML, specifically the
the <, >, and &
characters.
The cgiHtmlEscape function is used to
output
the user-entered name with any occurrences of these characters
correctly escaped as <, >,
and &.
Important: cgiOut
is normally equivalent
to stdout, and there is no performance penalty for using it.
It is recommended that you write output to cgiOut
to ensure compatibility
with modified versions of the cgic library for special
environments that do not provide stdin and stdout for
each cgi connection.
Note that, for text input areas in which carriage
returns are
desired, the function cgiFormString
should be used instead. cgiFormString ensures that line breaks
are always represented by a single carriage return (ascii decimal 13),
making life easier for the programmer. See the source code to
the Address() function of cgictest.c for an example.
Handling Single Checkboxes
Consider the Hungry() function, which determines whether
the user has selected the "hungry" checkbox:
void Hungry() { if (cgiFormCheckboxSingle("hungry") == cgiFormSuccess) { fprintf(cgiOut, "I'm Hungry!<BR>\n"); } else { fprintf(cgiOut, "I'm Not Hungry!<BR>\n"); } }
This function takes advantage of the cgiFormCheckboxSingle()
function, which
determines whether a single checkbox has been selected.
cgiFormCheckboxSingle() accepts the name attribute of the checkbox
as its sole argument and returns
cgiFormSuccess if the checkbox is selected, or cgiFormNotFound if it is not.
If multiple checkboxes with the same name are in use,
consider the
cgiFormCheckboxMultiple() and cgiFormStringMultiple()
functions.
Handling Numeric Input
Now consider the Temperature() function, which retrieves
a temperature in degrees (a floating-point value) and ensures
that it lies within particular bounds:
void Temperature() { double temperature; cgiFormDoubleBounded("temperature", &temperature, 80.0, 120.0, 98.6); fprintf(cgiOut, "My temperature is %f.<BR>\n", temperature); }
The temperature is retrieved by the function cgiFormDoubleBounded(). The first
argument is the name of the temperature input field in the form;
the second argument points to the address of the variable that will
contain the result. The next two arguments are the lower and upper
bounds, respectively. The final argument is the default value to
be returned if the user did not submit a value.
This function always retrieves a reasonable value within
the
specified bounds; values above or below bounds are constrained
to fit the bounds. However, the return value of
cgiFormDoubleBounded can be checked to make sure the
actual user entry was in bounds, not blank, and so forth;
see the description of
cgiFormDoubleBounded() for more details. If bounds checking
is not desired, consider using
cgiFormDouble() instead.
Note that, for integer input, the functions cgiFormInteger and cgiFormIntegerBounded
are available. The behavior of these functions is similar to
that of their floating-point counterparts above.
Handling Single-Choice Input
The <SELECT> tag of HTML is used to provide the user with
several choices. Radio buttons and checkboxes can also be used
when the number of choices is relatively small. Consider
the Color() function of cgictest.c:
char *colors[] = { "Red", "Green", "Blue" };
void Color() { int colorChoice; cgiFormSelectSingle("colors", colors, 3, &colorChoice, 0); fprintf(cgiOut, "I am: %s<BR>\n", colors[colorChoice]); }
This function determines which of several colors the user chose
from a <SELECT> list in the form. An array of colors is
declared; the cgiFormSelectSingle()
function is then invoked to determine which, if any, of those choices
was selected. The first argument indicates the name of the input
field in the form. The second argument points to the list of
acceptable colors. The third argument indicates the number of
entries in the color array. The fourth argument points to the
variable which will accept the chosen color, and the last argument
indicates the index of the default value to be set if no
selection was submitted by the browser.
cgiFormSelectSingle()
will
always indicate a reasonable selection value. However, if
the programmer wishes to know for certain that a value was
actually submitted, that the value submitted was a legal
response, and so on, the return value of cgiFormSelectSingle()
can be consulted. See the full description of cgiFormSelectSingle()
for
more information.
Note that radio button groups and <SELECT> lists
can both
be handled by this function. If you are processing radio
button groups, you may prefer to invoke cgiFormRadio(),
which functions
identically.
"What if I won't know the acceptable choices at
runtime?"
If the acceptable choices aren't known until
runtime,
one can simply load the choices from disk. But if the acceptable
choices aren't fixed at all (consider a list of country names;
new names may be added to the form at any time and it is
inconvenient to also update program code or a separate list
of countries), simply invoke cgiFormStringNoNewlines()
instead to retrieve the string directly. Keep in mind that, if
you do so, validating the response to make sure it is
safe and legitimate becomes a problem for your own
program to solve. The advantage of cgiFormSelectSingle() is that
invalid responses are never returned.
To handle multiple-selection <SELECT> lists and
groups of checkboxes with the same name, see the
discussion of the NonExButtons() function of cgictest.c, immediately
below.
Handling Multiple-Choice Input
Consider the first half of the NonExButtons() function of cgictest.c:
char *votes[] = { "A", "B", "C", "D" };
void NonExButtons() { int voteChoices[4]; int i; int result; int invalid;
char **responses;
/* Method #1: check for valid votes. This is a good idea, since votes for nonexistent candidates should probably be discounted... */ fprintf(cgiOut, "Votes (method 1):<BR>\n"); result = cgiFormCheckboxMultiple("vote", votes, 4, voteChoices, &invalid); if (result == cgiFormNotFound) { fprintf(cgiOut, "I hate them all!<p>\n"); } else { fprintf(cgiOut, "My preferred candidates are:\n"); fprintf(cgiOut, "<ul>\n"); for (i=0; (i < 4); i++) { if (voteChoices[i]) { fprintf(cgiOut, "<li>%s\n", votes[i]); } } fprintf(cgiOut, "</ul>\n"); }
This function takes advantage of cgiFormCheckboxMultiple(),
which is used to identify one or more selected checkboxes with the same
name. This function performs identically to cgiFormSelectMultiple().
That is, <SELECT> tags with the MULTIPLE attribute are handled
just like a group of several checkboxes with the same name.
The first argument to
cgiFormCheckboxMultiple() is the name given to all
checkbox input fields in the group. The second argument
points to an array of legitimate values; these should
correspond to the VALUE attributes of the checkboxes
(or OPTION tags in a <SELECT> list). The third argument
indicates the number of entries in the array of
legitimate values. The fourth argument points to
an array of integers with the same number of entries
as the array of legitimate values; each entry
will be set true if that checkbox or option was selected,
false otherwise.
The last argument points to an integer which will be set
to the number of invalid responses (responses not in the array of
valid responses) that were submitted. If this value is not
of interest, the last argument may be a null pointer (0).
Note that the return value of cgiFormCheckboxMultiple is
inspected to determine whether any choices at all were
set. See the full description of cgiFormCheckboxMultiple
for other possible return values.
"What if I won't know the acceptable choices at
runtime?"
If the acceptable choices aren't known until
runtime,
one can simply load the choices from disk. But if the acceptable
choices aren't fixed at all (consider a list of ice cream flavors;
new names may be added to the form at any time and it is
inconvenient to also update program code or a separate list
of countries), a more dynamic approach is needed. Consider
the second half of the NonExButtons() function of cgictest.c:
/* Method #2: get all the names voted for and trust them. This is good if the form will change more often than the code and invented responses are not a danger or can be checked in some other way. */ fprintf(cgiOut, "Votes (method 2):<BR>\n"); result = cgiFormStringMultiple("vote", &responses); if (result == cgiFormNotFound) { fprintf(cgiOut, "I hate them all!<p>\n"); } else { int i = 0; fprintf(cgiOut, "My preferred candidates are:\n"); fprintf(cgiOut, "<ul>\n"); while (responses[i]) { fprintf(cgiOut, "<li>%s\n", responses[i]); i++; } fprintf(cgiOut, "</ul>\n"); } /* We must be sure to free the string array or a memory leak will occur. Simply calling free() would free the array but not the individual strings. The function cgiStringArrayFree() does the job completely. */ cgiStringArrayFree(responses); }
This code excerpt demonstrates an alternate means of retrieving
a list of choices. The function cgiFormStringMultiple()
is used
to retrieve an array consisting of all the strings submitted
for with a particular input field name. This works both for
<SELECT> tags with the MULTIPLE attribute and for groups of
checkboxes with the same name.
The first argument to
cgiFormStringMultiple() is the name of the input field or
group of input fields in question. The second argument should
be the address of a pointer to a pointer to a string, which
isn't as bad as it sounds. Consider the following simple call
of the function:
/* An array of strings; each C string is an array of characters */ char **responses;
cgiFormStringMultiple("vote", &responses);
"How do I know how many responses there are?"
After the call, the last entry in the string array will
be
a null pointer. Thus the simple loop:
int i = 0; while (responses[i]) { /* Do something with the string responses[i] */ i++; }
can be used to walk through the array until the last
entry is encountered.
Important: the cgiFormStringMultiple function
returns a pointer to allocated memory. Your code
should not modify the strings in the responses array or the responses
array itself; if modification is needed, the strings should be
copied. When your code is done examining the responses array,
you MUST call
cgiStringArrayFree() with the array as an argument to free the
memory associated with the array. Otherwise, the memory will not be
available again until the program exists. Don't just
call the free() function; if you do, the individual strings will not be
freed.
Accessing Uploaded Files
CGIC provides functions to access files that have been uploaded
as part of a form submission. IMPORTANT: you MUST set
the enctype attribute of your form tag
to multipart/form-data for this feature to work! For an
example, see the ShowForm function of
cgictest.c, examined below.
The File function of cgictest.c takes care
of receiving uploaded files:
void File() { cgiFilePtr file; char name[1024]; char contentType[1024]; char buffer[1024]; int size; int got; if (cgiFormFileName("file", name, sizeof(name)) != cgiFormSuccess) { printf("<p>No file was uploaded.<p>\n"); return; } fprintf(cgiOut, "The filename submitted was: "); cgiHtmlEscape(name); fprintf(cgiOut, "<p>\n"); cgiFormFileSize("file", &size); fprintf(cgiOut, "The file size was: %d bytes<p>\n", size); cgiFormFileContentType("file", contentType, sizeof(contentType)); fprintf(cgiOut, "The alleged content type of the file was: "); cgiHtmlEscape(contentType); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Of course, this is only the claim the browser " "made when uploading the file. Much like the filename, " "it cannot be trusted.<p>\n"); fprintf(cgiOut, "The file's contents are shown here:<p>\n"); if (cgiFormFileOpen("file", &file) != cgiFormSuccess) { fprintf(cgiOut, "Could not open the file.<p>\n"); return; } fprintf(cgiOut, "<pre>\n"); while (cgiFormFileRead(file, buffer, sizeof(buffer), &got) == cgiFormSuccess) { cgiHtmlEscapeData(buffer, got); } fprintf(cgiOut, "</pre>\n"); cgiFormFileClose(file); }
First, the File function checks to determine the filename that was
submitted by the user. VERY IMPORTANT: this filename may or
may not bear any relation to the real name of the file on the user's
computer, may be deliberately manipulated with malicious intent,
and should not be used for any purpose unless you
have
determined that its content is safe for your intended use and will not,
at the very least, overwrite another file of importance to you,
especially if
you intend to use it as a file name on the server side. The cgic
library
itself does not use this file name for temporary storage.
If the cgiFormFileName
function does
not succeed, no file was uploaded.
Next, the cgiFormFileSize
function is called
to determine the size of the uploaded file, in bytes.
The File function then proceeds to query the content
type of the uploaded
file. Files uploaded by the user have their own content type
information, which may be useful in determining whether the file is an
image, HTML document,
word processing document, or other type of file. However, as
with the filename and any other claim made by
the browser,
this information should not be blindly trusted. The browser
may upload a file with the name picture.jpg and the
content type image/jpeg, but this does not guarantee that
the
actual file will contain a valid JPEG image suitable for display.
The content type submitted by the browser can be queried
using the cgiFormFileContentType
function.
Of course, CGIC also provides access to the actual
uploded file. First, the programmer calls cgiFormFileOpen,
passing the address of a cgiFilePtr object. If this
function
succeeds, the cgiFilePtr object becomes valid, and can be
used in subsequent calls to cgiFormFileRead.
Notice that the number of bytes read may be less than the number
requested,
in particular on the last successful call before cgiFormFileRead begins
to return cgiFormEOF. When cgiFormFileRead no longer
returns cgiFormSuccess, the programmer calls cgiFormFileClose
to
release the cgiFilePtr object.
The uploaded file data may contain anything, including
binary data,
null characters, and so on. The example program uses the cgiHtmlEscapeData function to output the
data with any special characters that have meaning in HTML escaped.
Most programs will save the uploaded information to a server-side file
or
database.
Fetching All Form Entries
From time to time, the programmer may not know the names of all
form fields in advance. In such situations it is convenient to
use the cgiFormEntries function.
The Entries function of cgictest.c demonstrates the use of
cgiFormEntries:
void Entries() { char **array, **arrayStep; fprintf(cgiOut, "List of All Submitted Form Field Names:<p>\n"); if (cgiFormEntries(&array) != cgiFormSuccess) { return; } arrayStep = array; fprintf(cgiOut, "<ul>\n"); while (*arrayStep) { fprintf(cgiOut, "<li>"); cgiHtmlEscape(*arrayStep); fprintf(cgiOut, "\n"); arrayStep++; } fprintf(cgiOut, "</ul>\n"); cgiStringArrayFree(array); }
The cgiFormEntries function retrieves an array of form field names.
This array consists of pointers to strings, with a final null pointer
to mark the end of the list. The above code illustrates one way of
looping through the returned strings. Note the final call to cgiStringArrayFree, which
is
essential in order to return the memory used to store the strings
and the string array.
Retrieving Cookies
The Cookies function of cgictest.c displays a list of all cookies
submitted by the browser with the current form submission, along
with their values:
void Cookies() { char **array, **arrayStep; char cname[1024], cvalue[1024]; fprintf(cgiOut, "Cookies Submitted On This Call, With Values " "(Many Browsers NEVER Submit Cookies):<p>\n"); if (cgiCookies(&array) != cgiFormSuccess) { return; } arrayStep = array; fprintf(cgiOut, "<table border=1>\n"); fprintf(cgiOut, "<tr><th>Cookie<th>Value</tr>\n"); while (*arrayStep) { char value[1024]; fprintf(cgiOut, "<tr>"); fprintf(cgiOut, "<td>"); cgiHtmlEscape(*arrayStep); fprintf(cgiOut, "<td>"); cgiCookieString(*arrayStep, value, sizeof(value)); cgiHtmlEscape(value); fprintf(cgiOut, "\n"); arrayStep++; } fprintf(cgiOut, "</table>\n"); cgiFormString("cname", cname, sizeof(cname)); cgiFormString("cvalue", cvalue, sizeof(cvalue)); if (strlen(cname)) { fprintf(cgiOut, "New Cookie Set On This Call:<p>\n"); fprintf(cgiOut, "Name: "); cgiHtmlEscape(cname); fprintf(cgiOut, "Value: "); cgiHtmlEscape(cvalue); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "If your browser accepts cookies " "(many do not), this new cookie should appear " "in the above list the next time the form is " "submitted.<p>\n"); } cgiStringArrayFree(array); }
VERY IMPORTANT: YOUR BROWSER MIGHT NOT SUBMIT
COOKIES,
EVER, REGARDLESS OF WHAT VALUES YOU ENTER INTO THE TEST FORM.
Many, many browsers are configured not to accept or send cookies;
others are configured to send them as little as possible to meet the
bare minimum requirements for entry into popular sites. Users will
often
refuse your cookies; make sure your code still works in that situation!
The above code uses the cgiCookies
function
to retrieve a list of all currently set cookies as a null-terminated
array of strings. The cgiCookieString
function is then used to fetch the value associated with each cookie;
this function works much like cgiFormString,
discussed earlier. Note that a cookie set as a part of the current
form submission process does not appear on this list immediately, as
it has not yet been sent back by the browser. It should appear on
future submissions, provided that the browser chooses to accept
and resend the cookie at all.
Displaying a Form That Submits to the Current Program
CGI programmers often need to display HTML pages as part of the output
of CGI programs; these HTML pages often contain forms which should
submit
fields back to the same program they came from. Provided that your
web server is well-configured, this can be done conveniently using
the cgiScriptName environment variable, as shown below. Here is the
source code of the ShowForm function of cgictest.c:
void ShowForm() { fprintf(cgiOut, "<!-- 2.0: multipart/form-data is required "for file uploads. -->"); fprintf(cgiOut, "<form method=\"POST\" " "enctype=\"multipart/form-data\" "); fprintf(cgiOut, " action=\""); cgiValueEscape(cgiScriptName); fprintf(cgiOut, "\">\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Text Field containing Plaintext\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "<input type=\"text\" name=\"name\">Your Name\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Multiple-Line Text Field\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "<textarea NAME=\"address\" ROWS=4 COLS=40>\n"); fprintf(cgiOut, "Default contents go here. \n"); fprintf(cgiOut, "</textarea>\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Checkbox\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "<input type=\"checkbox\" name=\"hungry\" checked>Hungry\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Text Field containing a Numeric Value\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "<input type=\"text\" name=\"temperature\" value=\"98.6\">\n"); fprintf(cgiOut, "Blood Temperature (80.0-120.0)\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Text Field containing an Integer Value\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "<input type=\"text\" name=\"frogs\" value=\"1\">\n"); fprintf(cgiOut, "Frogs Eaten\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "Single-SELECT\n"); fprintf(cgiOut, "<br>\n"); fprintf(cgiOut, "<select name=\"colors\">\n"); fprintf(cgiOut, "<option value=\"Red\">Red\n"); fprintf(cgiOut, "<option value=\"Green\">Green\n"); fprintf(cgiOut, "<option value=\"Blue\">Blue\n"); fprintf(cgiOut, "</select>\n"); fprintf(cgiOut, "<br>\n"); fprintf(cgiOut, "Multiple-SELECT\n"); fprintf(cgiOut, "<br>\n"); fprintf(cgiOut, "<select name=\"flavors\" multiple>\n"); fprintf(cgiOut, "<option value=\"pistachio\">Pistachio\n"); fprintf(cgiOut, "<option value=\"walnut\">Walnut\n"); fprintf(cgiOut, "<option value=\"creme\">Creme\n"); fprintf(cgiOut, "</select>\n"); fprintf(cgiOut, "<p>Exclusive Radio Button Group: Age of " "Truck in Years\n"); fprintf(cgiOut, "<input type=\"radio\" name=\"age\" " "value=\"1\">1\n"); fprintf(cgiOut, "<input type=\"radio\" name=\"age\" " "value=\"2\">2\n"); fprintf(cgiOut, "<input type=\"radio\" name=\"age\" " "value=\"3\" checked>3\n"); fprintf(cgiOut, "<input type=\"radio\" name=\"age\" " "value=\"4\">4\n"); fprintf(cgiOut, "<p>Nonexclusive Checkbox Group: " "Voting for Zero through Four Candidates\n"); fprintf(cgiOut, "<input type=\"checkbox\" name=\"vote\" " "value=\"A\">A\n"); fprintf(cgiOut, "<input type=\"checkbox\" name=\"vote\" " "value=\"B\">B\n"); fprintf(cgiOut, "<input type=\"checkbox\" name=\"vote\" " "value=\"C\">C\n"); fprintf(cgiOut, "<input type=\"checkbox\" name=\"vote\" " "value=\"D\">D\n"); fprintf(cgiOut, "<p>File Upload:\n"); fprintf(cgiOut, "<input type=\"file\" name=\"file\" " "value=\"\"> (Select A Local File)\n"); fprintf(cgiOut, "<p>\n"); fprintf(cgiOut, "<p>Set a Cookie<p>\n"); fprintf(cgiOut, "<input name=\"cname\" " "value=\"\"> Cookie Name\n"); fprintf(cgiOut, "<input name=\"cvalue\" " "value=\"\"> Cookie Value<p>\n"); fprintf(cgiOut, "<input type=\"submit\" " "name=\"testcgic\" value=\"Submit Request\">\n"); fprintf(cgiOut, "<input type=\"reset\" " "value=\"Reset Request\">\n"); fprintf(cgiOut, "<p>Save the CGI Environment<p>\n"); fprintf(cgiOut, "Pressing this button will submit the form, then " "save the CGI environment so that it can be replayed later " "by calling cgiReadEnvironment (in a debugger, for " "instance).<p>\n"); fprintf(cgiOut, "<input type=\"submit\" name=\"saveenvironment\" " "value=\"Save Environment\">\n"); fprintf(cgiOut, "</form>\n"); }
Note the use of enctype="multipart/form-data" in the FORM
tag. This is absolutely required if the
form
will contain file upload fields, as in the above example. Most
browsers will not even attempt file uploads without the
presence of this attribute.
Examining CGI environment variables
The CGI standard specifies a number of environment variables
which are set by the server. However, servers are somewhat
unpredictable as to whether these variables will be null or
point to empty strings when an environment variable is not set.
Also, in order to allow the programmer to restore saved
CGI environments, the cgic library needs have a way of insulating
the programmer from the actual environment variables.
Instead of calling getenv() to determine the value of a
variable such as HTTP_USER_AGENT (the browser software being used),
always use the cgic copies of the environment
variables,
which are always valid C strings (they are never null, although
they may point to an empty string). For instance, the cgic
variable containing the name of the browser software is cgiUserAgent. The referring URL
appears
in the variable cgiReferrer.
cgic can be used in conjunction with the gd graphics library,
which
can produce GIF images on the fly.
The following short sample program hints at the
possibilities:
#include "cgic.h" #include "gd.h"
char *colors[] = { "red", "green", "blue" };
#define colorsTotal 3
int cgiMain() { int colorChosen; gdImagePtr im; int r, g, b; /* Use gd to create an image */ im = gdImageCreate(64, 64); r = gdImageColorAllocate(im, 255, 0, 0); g = gdImageColorAllocate(im, 0, 255, 0); b = gdImageColorAllocate(im, 0, 0, 255); /* Now use cgic to find out what color the user requested */ cgiFormSelectSingle("color", 3, &colorChosen, 0); /* Now fill with the desired color */ switch(colorChosen) { case 0: gdImageFill(im, 32, 32, r); break; case 1: gdImageFill(im, 32, 32, g); break; case 2: gdImageFill(im, 32, 32, b); break; } /* Now output the image. Note the content type! */ cgiHeaderContentType("image/gif"); /* Send the image to cgiOut */ gdImageGif(im, cgiOut); /* Free the gd image */ gdImageDestroy(im); return 0; }
Note that this program would need to be linked with both cgic.o
and libgd.a. Often programs of this type respond to one
cgiPathInfo value or set of form fields by returning an HTML page with
an inline image reference that, in turn, generates a GIF image.
Debugging CGI applications can be a painful task. Since CGI
applications
run in a special environment created by the web server, it is difficult
to execute them in a debugger. However, the cgic library provides a way
of capturing "live" CGI environments to a file, and also provides a way
to reload saved environments.
The provided program 'capture.c' can be used to capture
CGI
environments. Just change the first line of the cgiMain() function
of capture.c to save the CGI environment to a filename appropriate
on your system and type 'make capture'. Then place capture in your
cgi directory and set the form action or other link you want to test
to point to it. When the form submission or other link takes place,
capture will write the CGI environment active at that time to
the filename you specified in the source. The cgiReadEnvironment()
function can then be invoked on the same filename at the beginning of
the cgiMain() function of the application you want to test in order to
restore the captured environment. You can then execute your program in
the debugger of your choice,
and it should perform exactly as it would have performed had
it been launched by the actual web server, including file uploads,
cookies and all other phenomena within the purview of cgic.
Important: Make sure you specify the
full path, as the
current working directory of a CGI script may not be what you
think it is!
Even More Important: If you call
getenv() yourself
in your code, instead of using the provided
cgic copies of the CGI environment variables, you will not
get the values you expect when running with
a saved CGI environment. Always use the cgic variables instead
of calling getenv().
- cgiFormResultType
cgiFormString( char *name, char *result, int max)
- cgiFormString attempts to retrieve the string sent
for the specified input field. The text will be copied into the buffer
specified by result, up to but not exceeding max-1 bytes; a terminating
null is then added to complete the string. Regardless of the newline
format submitted by the browser, cgiFormString always encodes each
newline as a single line feed (ascii decimal 10); as a result the final
string may be slightly shorter than indicated by a call to cgiFormStringSpaceNeeded but
will never be longer. cgiFormString returns cgiFormSuccess
if the string was successfully retrieved, cgiFormTruncated
if the string was retrieved but was truncated to fit the buffer,
cgiFormEmpty if the string was retrieved but was empty, and cgiFormNotFound if no such input field was
submitted. In the last case, an empty string is copied to result.
- cgiFormResultType
cgiFormStringNoNewlines( char *name, char *result, int max)
- cgiFormStringNoNewlines() is exactly equivalent to cgiFormString(), except that any carriage
returns or line feeds that occur in the input will be stripped out. The
use of this function is recommended for single-line text input fields,
as some browsers will submit carriage returns and line feeds when they
should not.
- cgiFormResultType
cgiFormStringSpaceNeeded( char *name, int *length)
- cgiFormStringSpaceNeeded() is used to determine the
length of the input text buffer needed to receive the contents of the
specified input field. This is useful if the programmer wishes to
allocate sufficient memory for input of arbitrary length. The actual
length of the string retrieved by a subsequent call to cgiFormString()
may be slightly shorter but will never be longer than *result. On
success, cgiFormStringSpaceNeeded() sets the value pointed to by length
to the number of bytes of data, including the terminating null, and
returns cgiFormSuccess. If no value was
submitted for the specified field, cgiFormStringSpaceNeeded sets the
value pointed to by length to 1 and returns cgiFormNotFound.
1 is set to ensure space for an empty string (a single null character)
if cgiFormString is called despite the return value.
- cgiFormResultType
cgiFormStringMultiple( char *name, char ***ptrToStringArray)
- cgiFormStringMultiple is useful in the unusual case
in which several input elements in the form have the same name and, for
whatever reason, the programmer does not wish to use the checkbox,
radio button and selection menu functions provided below. This is
occasionally needed if the programmer cannot know in advance what
values might appear in a multiple-selection list or group of checkboxes
on a form. The value pointed to by result will be set to a pointer to
an array of strings; the last entry in the array will be a null
pointer. This array is allocated by the CGI library. Important: when
done working with the array, you must call cgiStringArrayFree() with
the array pointer as the argument. cgiFormStringMultiple() returns cgiFormSuccess if at least one occurrence
of the name is found, cgiFormNotFound
if no occurrences are found, or cgiFormMemory if not enough memory is
available to allocate the array to be returned. In all cases except the
last, ptrToStringArray is set to point to a valid array of strings,
with the last element in the array being a null pointer; in the
out-of-memory case ptrToStringArray is set to a null pointer.
- cgiFormResultType
cgiFormEntries( char *name, char ***ptrToStringArray)
- cgiFormEntries is useful when the programmer cannot
know the names of all relevant form fields in advance. The value
pointed to by result will be set to a pointer to an array of strings;
the last entry in the array will be a null pointer. This array is
allocated by the CGI library. Important: when done working with the
array, you must call cgiStringArrayFree() with the array pointer as the
argument. cgiFormEntries() returns cgiFormSuccess
except in the event of an out of memory error. On success,
ptrToStringArray is set to point to a valid array of strings, with the
last element in the array being a null pointer; in the out-of-memory
case ptrToStringArray is set to a null pointer, and cgiFormOutOfMemory is returned.
- void
cgiStringArrayFree(char **stringArray)
- cgiStringArrayFree() is used to free the memory
associated with a string array created by cgiFormStringMultiple(), cgiFormEntries(), or cgiFormCookies().
- cgiFormResultType
cgiFormInteger( char *name, int *result, int defaultV)
- cgiFormInteger() attempts to retrieve the integer
sent for the specified input field. The value pointed to by result will
be set to the value submitted. cgiFormInteger() returns cgiFormSuccess
if the value was successfully retrieved, cgiFormEmpty if the value
submitted is an empty string, cgiFormBadType if the value submitted is
not an integer, and cgiFormNotFound if
no such input field was submitted. In the last three cases, the value
pointed to by result is set to the specified default.
- cgiFormResultType
cgiFormIntegerBounded( char *name, int *result, int min, int max, int
defaultV)
- cgiFormIntegerBounded() attempts to retrieve the
integer sent for the specified input field, and constrains the result
to be within the specified bounds. The value pointed to by result will
be set to the value submitted. cgiFormIntegerBounded() returns
cgiFormSuccess if the value was successfully retrieved, cgiFormConstrained if the value was out
of bounds and result was adjusted accordingly, cgiFormEmpty
if the value submitted is an empty string, cgiFormBadType
if the value submitted is not an integer, and cgiFormNotFound if no such input field was
submitted. In the last three cases, the value pointed to by result is
set to the specified default.
- cgiFormResultType
cgiFormDouble( char *name, double *result, double defaultV)
- cgiFormDouble attempts to retrieve the floating-point
value sent for the specified input field. The value pointed to by
result will be set to the value submitted. cgiFormDouble returns
cgiFormSuccess if the value was successfully retrieved, cgiFormEmpty if
the value submitted is an empty string, cgiFormBadType if the value
submitted is not a number, and cgiFormNotFound
if no such input field was submitted. In the last three cases, the
value pointed to by result is set to the specified default.
- cgiFormResultType
cgiFormDoubleBounded( char *name, double *result, double min, double
max, double defaultV)
- cgiFormDoubleBounded() attempts to retrieve the
floating-point value sent for the specified input field, and constrains
the result to be within the specified bounds. The value pointed to by
result will be set to the value submitted. cgiFormDoubleBounded()
returns cgiFormSuccess if the value was successfully retrieved, cgiFormConstrained if the value was out
of bounds and result was adjusted accordingly, cgiFormEmpty
if the value submitted is an empty string, cgiFormBadType
if the value submitted is not a number, and cgiFormNotFound
if no such input field was submitted. In the last three cases, the
value pointed to by result is set to the specified default.
- cgiFormResultType
cgiFormSelectSingle( char *name, char **choicesText, int choicesTotal,
int *result, int defaultV)
- cgiFormSelectSingle() retrieves the selection number
associated with a <SELECT> element that does not allow multiple
selections. name should identify the NAME attribute of the
<SELECT> element. choicesText should point to an array of strings
identifying each choice; choicesTotal should indicate the total number
of choices. The value pointed to by result will be set to the position
of the actual choice selected within the choicesText array, if any, or
to the value of default, if no selection was submitted or an invalid
selection was made. cgiFormSelectSingle() returns cgiFormSuccess if the value was
successfully retrieved, cgiFormNotFound
if no selection was submitted, and cgiFormNoSuchChoice
if the selection does not match any of the possibilities in the
choicesText array.
- cgiFormResultType
cgiFormSelectMultiple( char *name, char
**choicesText, int choicesTotal, int *result, int *invalid)
- cgiFormSelectMultiple() retrieves the selection
numbers associated with a <SELECT> element that does allow
multiple selections. name should identify the NAME attribute of the
<SELECT> element. choicesText should point to an array of strings
identifying each choice; choicesTotal should indicate the total number
of choices. result should point to an array of integers with as many
elements as there are strings in the choicesText array. For each choice
in the choicesText array that is selected, the corresponding integer in
the result array will be set to one; other entries in the result array
will be set to zero. cgiFormSelectMultiple() returns cgiFormSuccess if at least one valid
selection was successfully retrieved or cgiFormNotFound if no valid
selections were submitted. The integer pointed to by invalid is set to
the number of invalid selections that were submitted, which should be
zero unless the form and the choicesText array do not agree.
- cgiFormResultType
cgiFormSubmitClicked( char *name)
- It is often desirable to know whether a particular
submit button was clicked, when multiple submit buttons with different
name attributes exist. cgiFormSubmitClicked is an alternative name for
the cgiFormCheckboxSingle
function, which is suitable for testing whether a particular submit
button was used.
- cgiFormResultType
cgiFormCheckboxSingle( char *name)
- cgiFormCheckboxSingle determines whether the checkbox
with the specified name is checked. cgiFormCheckboxSingle returns cgiFormSuccess if the button is checked, cgiFormNotFound if the checkbox is not
checked. cgiFormCheckboxSingle is intended for single checkboxes with a
unique name; see below for functions to deal with multiple checkboxes
with the same name, and with radio buttons.
- cgiFormResultType
cgiFormCheckboxMultiple( char *name, char **valuesText, int
valuesTotal, int *result, int *invalid)
- cgiFormCheckboxMultiple() determines which checkboxes
among a group of checkboxes with the same name are checked. This is
distinct from radio buttons (see cgiFormRadio).
valuesText should point to an array of strings identifying the VALUE
attribute of each checkbox; valuesTotal should indicate the total
number of checkboxes. result should point to an array of integers with
as many elements as there are strings in the valuesText array. For each
choice in the valuesText array that is selected, the corresponding
integer in the result array will be set to one; other entries in the
result array will be set to zero. cgiFormCheckboxMultiple returns
cgiFormSuccess if at least one valid checkbox was checked or
cgiFormNotFound if no valid checkboxes were checked. The integer
pointed to by invalid is set to the number of invalid selections that
were submitted, which should be zero unless the form and the valuesText
array do not agree.
- cgiFormResultType
cgiFormRadio( char *name, char **valuesText, int valuesTotal, int
*result, int defaultV)
- cgiFormRadio() determines which, if any, of a group
of radio boxes with the same name was selected. valuesText should point
to an array of strings identifying the VALUE attribute of each radio
box; valuesTotal should indicate the total number of radio boxes. The
value pointed to by result will be set to the position of the actual
choice selected within the valuesText array, if any, or to the value of
default, if no radio box was checked or an invalid selection was made.
cgiFormRadio() returns cgiFormSuccess if
a checked radio box was found in the group, cgiFormNotFound
if no box was checked, and cgiFormNoSuchChoice
if the radio box submitted does not match any of the possibilities in
the valuesText array.
- cgiFormResultType
cgiFormFileName( char *name, char *fileName, int max)
- cgiFormFileName attempts to retrieve the file name
uploaded by the user for the specified form input field of type
file.
NEVER, EVER TRUST THIS FILENAME TO BE
REASONABLE AND SAFE FOR DIRECT USE ON THE SERVER SIDE. The
text will be copied into the buffer specified by fileName, up to but
not exceeding max-1 bytes; a terminating null is then added to complete
the string. cgiFormFileName returns cgiFormSuccess
if the string was successfully retrieved and was not empty, cgiFormNoFileName if the string was
successfully retrieved but empty indicating that no file was uploaded, cgiFormTruncated if the string was
retrieved but was truncated to fit the buffer, and cgiFormNotFound if no such input field was
submitted. In the last case, an empty string is copied to result.
- cgiFormResultType
cgiFormFileSize( char *name, int *sizeP)
- cgiFormFileSize attempts to retrieve the size, in
bytes, of a file uploaded by the browser in response to the input field
of type
file specified by the name
parameter. On success, the size is stored to *sizeP, and this function
returns cgiFormSuccess. If the form
field does not exist, this function returns cgiFormNotFound.
If the form field exists but no file was uploaded, this function
returns cgiFormNotAFile.
- cgiFormResultType
cgiFormFileContentType( char *name, char *contentType, int max)
- cgiFormString attempts to retrieve the content name
claimed by the user for the specified form input field of type
file.
THERE IS NO GUARANTEE THAT THE CONTENT TYPE
WILL BE ACCURATE. The content type string will be copied into
the buffer specified by contentType, up to but not exceeding max-1
bytes; a terminating null is then added to complete the string.
cgiFormFileContentType returns cgiFormSuccess
if the string was successfully retrieved and was not empty, cgiFormNoContentType if the string
was successfully retrieved but empty indicating that no file was
uploaded or the browser did not know the content type, cgiFormTruncated if the string was
retrieved but was truncated to fit the buffer, and cgiFormNotFound if no such input field was
submitted. In the last case, an empty string is copied to result.
- cgiFormResultType
cgiFormFileOpen( char *name, cgiFilePtr *cfpp)
- cgiFormFileOpen attempts to open the actual uploaded
file data for the specified form field of type
file. Upon
success, this function returns retrieve the content name claimed by the
user for the specified form input field of type file. On
success, this function sets *cfpp to a valid cgiFilePtr object for use
with cgiFormSuccess.
On failure, this function sets
*cfpp to a null pointer, and returns cgiFormNotFound,
cgiFormNotAFile, cgiFormMemory or cgiFormIO
as appropriate.
See also cgiFormFileRead
and cgiFormFileClose.
- cgiFormResultType
cgiFormFileRead( cgiFilePtr cfp, char *buffer, int bufferSize, int
*gotP)
- cgiFormFileRead attempts to read up to
bufferSize
bytes from a cgiFilePtr object previously opened with cgiFormFileOpen. If any data is
successfully read, it is copied to buffer, and the number
of bytes successfully read is stored to *gotP. This
function returns cgiFormSuccess if any
data is successfully read. At end of file, this function returns cgiFormEOF. In the event of an I/O error, this
function returns cgiFormIO. If cfp is a null
pointer, this function returns cgiFormOpenFailed.
See also cgiFormFileOpen
and cgiFormFileClose.
- cgiFormResultType
cgiFormFileClose( cgiFilePtr cfp)
- cgiFormFileClose closes a cgiFilePtr object
previously opened with cgiFormFileOpen,
freeing memory and other system resources. This function returns cgiFormSuccess unless cfp is null, in which
case cgiFormOpenFailed is returned.
See also cgiFormFileOpen
and cgiFormFileRead.
- void
cgiHeaderLocation(char *redirectUrl)
- cgiHeaderLocation() should be called if the
programmer wishes to
redirect the user to a different URL. No futher output
is needed in this case.
If you wish to set cookies, you must make
your calls to cgiHeaderCookieSetString
and cgiHeaderCookieSetInteger
BEFORE invoking cgiHeaderLocation.
- void
cgiHeaderStatus(int status, char *statusMessage)
- cgiHeaderStatus() should be called if the programmer
wishes to
output an HTTP error status code instead of a document. The status
code is the first argument; the second argument is the status
message to be displayed to the user.
If you wish to set cookies, you must make
your calls to cgiHeaderCookieSetString
and cgiHeaderCookieSetInteger
BEFORE invoking cgiHeaderStatus.
- void
cgiHeaderContentType(char *mimeType)
- cgiHeaderContentType() should be called if the
programmer wishes to
output a new document in response to the user's request. This is
the normal case. The single argument is the MIME document type
of the response; typical values are "text/html" for HTML documents,
"text/plain" for plain ASCII without HTML tags, "image/gif" for
a GIF image and "audio/basic" for .au-format audio.
If you wish to set cookies, you must make
your calls to cgiHeaderCookieSetString
and cgiHeaderCookieSetInteger
BEFORE invoking cgiHeaderContentType.
- void
cgiHeaderCookieSetString(char *name, char *value, int secondsToLive,
char *path, char *domain)
- cgiHeaderCookieSetString() should be called when the
programmer wishes
to store a piece of information in the user's browser, so that the
stored information is again presented to the server on subsequent
accesses to the relevant site. The first argument is the name of the
cookie to be stored; for best results in all browsers, use a short
name without spaces or unusual punctuation. The second argument is
the value of the cookie to be stored. Again, for best results, use
a short string; it is recommended that cookies be used to store a
unique identifier which is then used to look up more detailed
information in a database on the server side. Attempts to store
elaborate information on the browser side are much more likely to fail.
The third argument is the number of seconds that the cookie should
be kept by the browser; 86400 is a single full day, 365*86400 is
roughly one year. The fourth argument is the partial URL of the
web site within which the cookie is relevant. If the cookie should
be sent to the server for every access to the entire site, set this
argument to
/. The final argument is the
web site name or entire domain for which this cookie should be
submitted; if you choose to have the cookie sent back for an
entire domain, this argument must begin with a dot, such as .boutell.com.
The cgic variables cgiServerName
are convenient
values for the fourth and fifth arguments.
See also cgiHeaderCookieSetInteger,
cgiCookieString, cgiCookieInteger and cgiCookies.
- void
cgiHeaderCookieSetInteger(char *name, int value, int secondsToLive,
char *path, char *domain)
- cgiHeaderCookieSetInteger() is identical to cgiHeaderCookieSetString,
except that the value to be set is an integer rather than a string.
See cgiHeaderCookieSetString
for complete information.
- cgiFormResultType
cgiCookieString( char *name, char *result, int max)
- cgiFormString attempts to retrieve the string sent
for the specified cookie (browser-side persistent storage). The text
will be copied into the buffer specified by result, up to but not
exceeding max-1 bytes; a terminating null is then added to complete the
string. cgiCookieString returns cgiFormSuccess
if the string was successfully retrieved, cgiFormTruncated
if the string was retrieved but was truncated to fit the buffer,
cgiFormEmpty if the string was retrieved but was empty, and cgiFormNotFound if no such cookie was
submitted. In the last case, an empty string is copied to result.
- cgiFormResultType
cgiCookieInteger( char *name, int *result, int defaultV) See also cgiCookieInteger, cgiCookies,
cgiHeaderCookieSetInteger.
- cgiCookieInteger() attempts to retrieve the integer
sent for the specified cookie (browser-side persistent storage). The
value pointed to by result will be set to the value submitted.
cgiCookieInteger() returns cgiFormSuccess if the value was successfully
retrieved, cgiFormEmpty if the value submitted is an empty string,
cgiFormBadType if the value submitted is not an integer, and cgiFormNotFound if no such input field was
submitted. In the last three cases, the value pointed to by result is
set to the specified default. See also cgiCookieString,
cgiCookies, cgiHeaderCookieSetInteger.
- cgiFormResultType
cgiCookies( char *name, char ***ptrToStringArray)
- cgiCookies is useful when the programmer cannot know
the names of all relevant cookies (browser-side persistent strings) in
advance. The value pointed to by result will be set to a pointer to an
array of strings; the last entry in the array will be a null pointer.
This array is allocated by the CGI library. Important: when done
working with the array, you must call cgiStringArrayFree() with the
array pointer as the argument. cgiCookies() returns cgiFormSuccess except in the event of an
out of memory error. On success, ptrToStringArray is set to point to a
valid array of strings, with the last element in the array being a null
pointer; in the out-of-memory case ptrToStringArray is set to a null
pointer, and cgiFormOutOfMemory is
returned.
- cgiFormResultType
cgiEscapeHtml(char *s)
- cgiEscapeHtml() outputs the specified null-terminated
string to cgiOut,
escaping any <, &, and > characters encountered correctly so
that
they do not interfere with HTML markup. Returns cgiFormSuccess, or cgiFormIO
in the event of an
I/O error.
- cgiFormResultType
cgiEscapeHtmlData(char *data, int len)
- cgiEscapeHtmlData() is identical to cgiEscapeHtml,
except that the data is not null-terminated. This version of the
function
outputs
len bytes. See cgiEscapeHtml
for more information.
- cgiFormResultType
cgiEscapeValue(char *s)
- cgiEscapeValue() outputs the specified
null-terminated string to cgiOut,
escaping any " characters encountered correctly so that
they do not interfere with the quotation marks of HTML attribute
values. This is useful when outputting a string as part of the
value attribute of an input tag, or the href attribute of a link
or form tag. This function returns cgiFormSuccess,
or cgiFormIO in the event of an
I/O error.
- cgiFormResultType
cgiEscapeValueData(char *data, int len)
- cgiEscapeValueData() is identical to cgiEscapeValue,
except that the data is not null-terminated. This version of the
function
outputs
len bytes. See cgiEscapeValue
for more information.
- cgiEnvironmentResultType
cgiWriteEnvironment(char *filename)
- cgiWriteEnvironment() can be used to write the entire
CGI environment, including form data, to the specified output file; cgiReadEnvironment() can then be used
to restore that environment from the specified input file for
debugging. Of course, these will only work as expected if you use the cgic copies of the CGI environment variables and
cgiIn and cgiOut
rather than stdin and stdout (also see above). These functions are
useful in order to capture real CGI situations while the web server is
running, then recreate them in a debugging environment. Both functions
return cgiEnvironmentSuccess on
success, cgiEnvironmentIO on an I/O
error, and cgiEnvironmentMemory on
an out-of-memory error.
- cgiEnvironmentResultType
cgiReadEnvironment(char *filename)
- cgiReadEnvironment() restores a CGI environment saved
to the specified file by cgiWriteEnvironment().
Of course, these will only work as expected if you use the cgic copies of the CGI environment variables and
cgiIn and cgiOut
rather than stdin and stdout (also see above). These functions are
useful in order to capture real CGI situations while the web server is
running, then recreate them in a debugging environment. Both functions
return cgiEnvironmentSuccess on
success, cgiEnvironmentIO on an I/O
error, and cgiEnvironmentMemory on
an out-of-memory error.
- int cgiMain()
- The programmer must write this function,
which performs the unique task of the program and is invoked by the
true main() function, found in the cgic library itself. The return
value from cgiMain will be the return value of the program. It is
expected that the user will make numerous calls to the cgiForm
functions from within this function. See how to write
a cgic application for details.
This section provides a reference guide to the various global
variables provided by cgic for the programmer to utilize.
These variables should always be used in preference to
stdin, stdout, and calls to getenv() in order to ensure
compatibility with the cgic CGI debugging features.
Most of these variables are equivalent to various CGI
environment
variables. The most important difference is that the cgic
environment string variables are never null pointers. They will always
point to valid C strings of zero or more characters.
- char
*cgiServerSoftware
- Points to the name of the server software,
or to an empty string if unknown.
- char *cgiServerName
- Points to the name of the server,
or to an empty string if unknown.
- char
*cgiGatewayInterface
- Points to the name of the gateway interface (usually
CGI/1.1),
or to an empty string if unknown.
- char
*cgiServerProtocol
- Points to the protocol in use (usually HTTP/1.0),
or to an empty string if unknown.
- char *cgiServerPort
- Points to the port number on which the server is
listening
for HTTP connections (usually 80), or an empty string if unknown.
- char
*cgiRequestMethod
- Points to the method used in the request (usually GET
or POST),
or an empty string if unknown (this should not happen).
- char *cgiPathInfo
- Most web servers recognize any additional path
information in the URL of the request beyond the name of the CGI
program itself and
pass that information on to the program. cgiPathInfo points to this
additional path information.
- char
*cgiPathTranslated
- Most web servers recognize any additional path
information in the URL of the request beyond the name of the CGI
program itself and
pass that information on to the program. cgiPathTranslated points
to this additional path information, translated by the server into a
filesystem path on the local server.
- char *cgiScriptName
- Points to the name under which the program was
invoked.
- char *cgiQueryString
- Contains any query information submitted by the user
as a result
of a GET-method form or an <ISINDEX> tag. Note that this
information need not be parsed directly unless an <ISINDEX> tag
was used; normally it is parsed automatically by the cgic library. Use
the cgiForm family of functions to retrieve the values associated
with form input fields. See how to write
a cgic application for more information.
- char *cgiRemoteHost
- Points to the fully resolved hostname of the browser,
if known,
or an empty string if unknown.
- char *cgiRemoteAddr
- Points to the dotted-decimal IP address of the
browser, if known,
or an empty string if unknown.
- char *cgiAuthType
- Points to the type of authorization used for the
request,
if any, or an empty string if none or unknown.
- char *cgiRemoteUser
- Points to the user name under which the user has
authenticated; an empty string if no authentication has
taken place. The certainty of this information depends on
the type of authorization in use; see cgiAuthType.
- char *cgiRemoteIdent
- Points to the user name volunteered by the user via
the user identification protocol; an empty
string if unknown. This information is not secure.
Identification demons can be installed by users on
insecure systems such as Windows machines.
- char *cgiContentType
- Points to the MIME content type of the information
submitted by the user, if any; an empty string if no
information was submitted. If this string is equal to
application/x-www-form-urlencoded
or multipart/form-data, the cgic
library will automatically examine the form data submitted.
If this string has any other non-empty value, a different
type of data has been submitted. This is currently very rare,
as most browsers can only submit forms and file uploads which
cgic parses directly.
- char *cgiCookie
- Points to the raw cookie (browser-side persistent
storage)
data submitted by the web browser. Programmers should use the functions
cgiCookies, cgiCookieString and cgiCookieInteger
instead of
examining this string directly.
- char *cgiAccept
- Points to a space-separated list of MIME content
types
acceptable to the browser (see
cgiHeaderContentType() ), or an empty string. Unfortunately, this
variable
is not supplied in a useful form by most current browsers. Programmers
wishing
to make decisions based on the capabilities of the browser
are advised to check the cgiUserAgent
variable against a list of browsers and capabilities instead.
- char *cgiUserAgent
- Points to the name of the browser in use, or an empty
string if this information is not available.
- char *cgiReferrer
- Points to the URL of the previous page visited by the
user. This is
often the URL of the form that brought the user to your program.
Note that reporting this information is entirely up to the browser,
which may choose not do so, and may choose not to do so truthfully.
However, this variable is typically accurate. The frequently
used misspelling cgiReferer is also supplied as a macro.
- int
cgiContentLength
- The number of bytes of form or query data received.
Note that if the submission is a form or query submission the library
will read and parse all the information directly from cgiIn and/or
cgiQueryString. The programmer should not do so, and indeed the cgiIn
pointer will be at end-of-file in such cases.
- FILE *cgiOut
- Pointer to CGI output. The cgiHeader functions, such
as cgiHeaderContentType, should be
used first to output the mime headers; the output HTML page, GIF image
or other web document should then be written to cgiOut by the
programmer using standard C I/O functions such as fprintf() and
fwrite(). cgiOut is normally equivalent to stdout; however, it is
recommended that cgiOut be used to ensure compatibility with future
versions of cgic for specialized environments.
- FILE *cgiIn
- Pointer to CGI input. In 99.99% of cases, you will
not need this. CGIC 2.0 supports both regular POST form submissions and
multipart/form-data file upload form submissions directly.
In most cases, cgic functions are designed to produce
reasonable
results
even when browsers and users do unreasonable things. However, it is
sometimes
important to know precisely which unreasonable things took place,
especially
when assigning a default value or bounding a value is an inadequate
solution. The following result codes are useful in making this
determination.
- cgiFormSuccess
- Indicates that the function successfully performed at
least one
action (or retrieved at least one value, where applicable).
- cgiFormTruncated
- Indicates that a string value retrieved from the user
was
cut short to avoid overwriting the end of a buffer.
- cgiFormBadType
- Indicates that a "numeric" value submitted by the
user was
in fact not a legal number.
- cgiFormEmpty
- Indicates that a field was retrieved but contained no
data.
- cgiFormNotFound
- Indicates that no value was submitted for a
particular field.
- cgiFormConstrained
- Indicates that a numeric value was beyond the
specified bounds
and was forced to the lower or upper bound as appropriate.
- cgiFormNoSuchChoice
- Indicates that the value submitted for a
single-choice field
(such as a radio-button group) was not one of the acceptable values.
This usually indicates a discrepancy between the form and the program.
- cgiFormEOF
- Returned by cgiFormFileRead
when, at the start of the call, the cgiFilePtr object is already
positioned at the end of the uploaded file data.
- cgiFormIO
- Returned by cgiFormFileRead
when an I/O error occurs while reading uploaded file data.
- cgiFormNotAFile
- Returned in response to an attempt to manipulate a
form field
that is not a file upload field using a file-related function.
- cgiFormNoContentType
- Returned in response to an attempt to fetch the
content type of
a file-upload field when the content type is not specified by the
browser.
- cgiFormNoFileName
- Returned in response to an attempt to fetch the file
name of
a file-upload field when a file name is not specified by the browser.
- cgiFormOpenFailed
- Returned in response to an attempt to read from a
null
cgiFilePtr object, typically when the programmer has failed to
check the result of a call to cgiFormFileOpen.
- cgiEnvironmentMemory
- Indicates that an attempt to read or write the CGI
environment
to or from a capture file failed due to an out-of-memory error.
- cgiEnvironmentSuccess
- Indicates that an attempt to read or write the CGI
environment
to or from a capture file was successful.
- cgiEnvironmentIO
- Indicates that an attempt to read or write the CGI
environment
to or from a capture file failed due to an I/O error.
- cgiEnvironmentWrongVersion
- Indicates that an attempt to read from a saved
debugging CGI environment
produced by a pre-2.0 version of CGIC was made.
cgiAccept | cgiAuthType
| cgiContentLength | cgiContentType | cgiEnvironmentIO | cgiEnvironmentMemory | cgiEnvironmentSuccess
| cgiCookieInteger | cgiCookies | cgiCookieSetInteger
| cgiCookieSetString | cgiCookieString | cgiEscapeHtml
| cgiEscapeHtmlData | cgiEscapeValue | cgiEscapeValueData | cgiFormBadType | cgiFormCheckboxMultiple()
| cgiFormCheckboxSingle()
| cgiFormConstrained | cgiFormDouble() | cgiFormDoubleBounded()
| cgiFormEOF | cgiFormEmpty
| cgiFormEntries | cgiFormFileClose | cgiFormFileContentType
| cgiFormFileName | cgiFormFileOpen | cgiFormFileRead | cgiFormFileSize | cgiFormInteger() | cgiFormIntegerBounded()
| cgiFormNoFileName
| cgiFormNoSuchChoice | cgiFormNotFound
| cgiFormRadio() | cgiFormSelectMultiple()
| cgiFormSelectSingle() | cgiFormString() | cgiFormStringMultiple()
| cgiFormStringNoNewlines()
| cgiFormStringSpaceNeeded()
| cgiFormSuccess | cgiFormTruncated | cgiGatewayInterface | cgiHeaderContentType()
| cgiHeaderLocation() | cgiHeaderStatus() | cgiIn
| cgiMain() cgiOut | cgiPathInfo | cgiPathTranslated
| cgiQueryString | cgiReadEnvironment() | cgiReferrer() | cgiRemoteAddr
| cgiRemoteHost | cgiRemoteIdent | cgiRemoteUser
| cgiRequestMethod | cgiScriptName | cgiServerName
| cgiServerPort | cgiServerProtocol | cgiServerSoftware | cgiStringArrayFree() | cgiUserAgent | cgiWriteEnvironment()
Boutell.Com, Inc.
|