From uhog.mit.edu!news.mathworks.com!newsfeed.internetmci.com!info.ucla.edu!news.ucdavis.edu!cassatt.ucdavis.edu!ez026264 31 Mar 1996 03:00:48 GMT
Path: uhog.mit.edu!news.mathworks.com!newsfeed.internetmci.com!info.ucla.edu!news.ucdavis.edu!cassatt.ucdavis.edu!ez026264
From: ez026264@cassatt.ucdavis.edu (Speed Raver)
Newsgroups: comp.lang.perl.misc
Subject: Uniform - Universal HTTP/CGI Form Parser
Date: 31 Mar 1996 03:00:48 GMT
Organization: University of California, Davis
Lines: 409
Message-ID: <4jksh0$pee@mark.ucdavis.edu>
NNTP-Posting-Host: cassatt.ucdavis.edu
X-Newsreader: TIN [version 1.2 PL2]

Uniform is a CGI script to be installed by an administrator in the cgi-bin 
directory of an HTTP server. Uniform does what a lot of CGI form 
processors do: it takes the information in the form and makes a mail 
message out of it, mail the message, and sends the form-filler-outter 
person a document acknowledging their submission. What's special is the 
way it's done. Most CGI scripts are tailored to the script they process. 
The parameters such as who to mail to, how to format the mailed message, 
and what to tell the person after their submission are hardcoded into the 
CGI script. Uniform looks for them in the form itself.

This confers a few benefits. First, the user who wants an interactive form
only has to ask the administrator to install Uniform. No further
intervention by the administration is necessary. The vital and variable
parameters mentioned above are contained in the form itself, so not only
is changing the form/script pair much easier for the administration and
the owner of the form, but all users can pass forms to Uniform and get
them processed, even users not on the host running Uniform.

Comments, etc:  mosheh@thalia.muse.net

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1996-03-30 18:54 PST by <root@thalia>.
# Source directory was `/tmp'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   1702 -rwxr-xr-x uniform.pl
#   3663 -rw-r--r-- freds.html
#   6988 -rw-r--r-- README
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
# ============= uniform.pl ==============
if test -f 'uniform.pl' && test X"$1" != X"-c"; then
  echo 'x - skipping uniform.pl (file already exists)'
else
  echo 'x - extracting uniform.pl (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'uniform.pl' &&
#!/usr/bin/perl
# Uniform 1.0  -  Universal Form Parser for HTTPD
# Copyright (c) 1996 Gregor Mosheh   mosheh@thalia.muse.net
# Please read the file README for information.
X
# Set this to the program to use for mail.
$mailprog = "mail";
X
# Get the input
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
X
# Split the name-value pairs
@pairs = split(/&/, $buffer);
X
# Process the name=value pairs and pout them into %FORM
foreach $pair (@pairs) {
X    ($name, $value) = split(/=/, $pair);
X    # Un-Webify plus signs and %-encoding
X    $value =~ tr/+/ /;
X    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
X    # Remove potential subshell includes when using mail.
X    $value =~ s/~!/ ~!/g; 
X
X    # Uncomment for debugging purposes
X    # print "Setting $name to $value<P>";
X
X    $FORM{$name} = $value;
}
X
# Thank the user for their input
$reply = $FORM{'reply'} ;
@keys = keys(%FORM);
foreach (@keys) {
X	# escape out double colons and whatever is after them
X	# and replace with the value of the scalar
X	$val = $FORM{"$_"};
X	$reply =~ s/\:\:$_/$val/g ;
}
print "Content-type: text/html\n\n";
print "$reply\n";
print "<p>Uniform 1.0   &copy; 1996, Gregor Mosheh mosheh@thalia.muse.net<p>\n";
X
# Generate the letter to send to the recipient.
# Same formatting as with the reply.
$letter = $FORM{"letter"};
@keys = keys(%FORM);
foreach (@keys) {
X	$val = $FORM{"$_"};
X	$letter =~ s/\:\:$_/$val/g ;
}
X
# Yank the recipient's email address and the subject line.
$to = $FORM{'to'};
$subject = $FORM{'subject'};
X
# Open the mail filehandle and send the letter
open(MAIL,"|$mailprog -s '$subject' $to");
print MAIL "$letter";
print MAIL "\n\n-------------------------------------\n";
print MAIL "Uniform 1.0   (c) 1996, Gregor Mosheh  mosheh@thalia.muse.net\n\n";
close(MAIL);
X
SHAR_EOF
  $shar_touch -am 0330174096 'uniform.pl' &&
  chmod 0755 'uniform.pl' ||
  echo 'restore of uniform.pl failed'
  shar_count="`wc -c < 'uniform.pl'`"
  test 1702 -eq "$shar_count" ||
    echo "uniform.pl: original size 1702, current size $shar_count"
fi
# ============= freds.html ==============
if test -f 'freds.html' && test X"$1" != X"-c"; then
  echo 'x - skipping freds.html (file already exists)'
else
  echo 'x - extracting freds.html (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'freds.html' &&
<!-- Uniform 1.0  -  Universal Form Parser for HTTPD
X     Copyright (c) 1996  Gregor Mosheh  mosheh@thalia.muse.net
X     This form is an example of how users without root access would
X     write a form for Uniform to process. Read the file README
X     before playing with this file.
-->
X
<html>
<title>Uniform Example Document</title>
<body>
<center><h3>Uniform Demo Form - Fred's Bakery</h3></center>
X
Welcome to Fred's Bakery, an example of Uniform's superiority 
over all other CGI mail processing scripts. Just fill out the handy form 
below and your order will be submitted.<p>
X
<form method="post" action="http://thalia.muse.net/cgi-bin/uniform.pl">
X
<dl>
<dt><font size=+1>Doughnuts</font></dt>
<dd>Our fluffy doughnuts are made from scratch three times a day to 
guarantee freshness. A wonderful bargain at $2.99 for a box of a 
dozen.<br>How many boxes of doughnuts? <input type="text" 
name="doughnuts" value="0" size=3 maxlength=3><p>
<dt><font size=+1>Bagels</font></dt>
<dd>Bagels are delicious, nutritious, and a great portable snack any 
time. Our bagels won the Werner Award for Best Baked Good at the 
1995 Townsville County Fair. A box of a dozen bagels is quite a bargain 
at $3.50.<br><input type="text" name="bagels" value="0" size=3 maxlength=3><p>
<dt><font size=+1>Catalogues</font></dt>
<dd>What you see here is only a sample of what's available from Fred's 
Bakery. Our full colour catalogues show our whole range of baked goods.<br>
Would you like a catalogue included with your order? <input type="text" 
name="catalogue" value="yes" size=3 maxlength=3"><p>
</dl>
X
<!-- Here is where we define the hidden tags that contain the special, 
form-dependent data parsed by the script. The name and type tags should 
not be changed, but the value tags are what you really need to change. 
This example should show what you need to do.
X     There are four tags to define. All of them must be defined.
X     reply   The value of reply is a small HTML script displayed
X             to the user after they submit the form.
X     letter  The value of letter is a short text document containing
X             the letter to be sent to the owner of the form.
X     to      The value of to is the email address to whom the completed
X             letter will be sent. Usually, this is the owner of the page.
X     subject The value of subject is the subject header of the letter
X             sent by Uniform to the page's owner.
Note that the reply and to values can contain :: escapes. A :: escape is 
a :: followed by the name of the variable to be substituted. Read the 
documentation for more help on :: escapes.
NOTE: Using quotation marks, ampersands, etc. is generally
not a great idea. Use their entities instead. Use &quot; for a quotation 
mark. Use &amp; for an ampersand, etc.
-->
X
<!-- CHANGE THIS!!! -->
<input type="hidden" name="reply" value="
<html><body><title>Order Sent</title>
<center><h3>Your Order Has Been Sent</h3></center>
You ordered the following:<br>
<ul>
<li>::doughnuts boxes of doughnuts
<li>::bagels boxes of bagels
</ul>
Send a catalogue? ::catalogue<p>
Thanks again from Fred's Doughnuts.<p>
<hr></body></html>
">
X
<!-- CHANGE THIS!!! -->
<input type="hidden" name="letter" value="
Request received from World Wide Web interface.
Patron requests:
X     ::doughnuts boxes of doughnuts
X     ::bagels boxes of bagels
X
Send catalogue? ::catalogue
">
X
<!-- CHANGE THIS!!! -->
<input type="hidden" name="to" value="mosheh@thalia.muse.net">
X
<!-- CHANGE THIS!!! -->
<input type="hidden" name="subject" value="Incoming Order via WWW">
X
<center><input type="submit" name="SUBMIT YOUR ORDER"><p></center>
</form>
X
<hr>
<!-- End of body -->
</body>
</html>
X
SHAR_EOF
  $shar_touch -am 0330172496 'freds.html' &&
  chmod 0644 'freds.html' ||
  echo 'restore of freds.html failed'
  shar_count="`wc -c < 'freds.html'`"
  test 3663 -eq "$shar_count" ||
    echo "freds.html: original size 3663, current size $shar_count"
fi
# ============= README ==============
if test -f 'README' && test X"$1" != X"-c"; then
  echo 'x - skipping README (file already exists)'
else
  echo 'x - extracting README (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README' &&
X           Uniform 1.0  -  Universal Form Parser for HTTPD
X                 Copyright (c) 1996, Gregor Mosheh  mosheh@thalia.muse.net
X
X
Uniform is a CGI script to be installed by an administrator in the cgi-bin 
directory of an HTTP server. Uniform does what a lot of CGI form 
processors do: it takes the information in the form and makes a mail 
message out of it, mail the message, and sends the form-filler-outter 
person a document acknowledging their submission. What's special is the 
way it's done. Most CGI scripts are tailored to the script they process. 
The parameters such as who to mail to, how to format the mailed message, 
and what to tell the person after their submission are hardcoded into the 
CGI script. Uniform looks for them in the form itself.
X
This confers a few benefits. First, the user who wants an interactive form
only has to ask the administrator to install Uniform. No further
intervention by the administration is necessary. The vital and variable
parameters mentioned above are contained in the form itself, so not only
is changing the form/script pair much easier for the administration and
the owner of the form, but all users can pass forms to Uniform and get
them processed, even users not on the host running Uniform.
X
Let's get to the installation and use, you'll see what I mean.
X
X
INSTALLING UNIFORM
X
To install uniform, just copy uniform.pl into the cgi-bin directory. Then 
set it world executable (chmod 0755 uniform.pl). Edit the first line of 
the script to point to your perl parser, if it's not /usr/bin/perl. The 
command "which perl" will generally tell you what to change this line to.
X
Now edit the $mailprog line to point to the program you use to send mail. 
Don't point it to sendmail, point it to your friendlier mail program. 
Common values for this are "mail" "Mail" "/bin/Mail" and "/usr/ucb/mail". 
You most likely don't have to change this, but some people would rather 
use "Mail" than "mail"...
X
Congratulations. It's installed. Almost painless, no?
X
X
USING UNIFORM
X
Using Uniform is only a matter of creating/editing a form. The server 
script itself requires no modification or customization.
X
Call Uniform as the ACTION line of an HTML form, using the POST method. 
IN a form, this would look something like this:
<form method="post" action="http://thalia.muse.net/cgi-bin/uniform.pl">
X    NOTE: As long as Thalia.Muse.Net stays alive, there will be a Uniform 
X    server on it, so this particular action/method combo should work
X    for the forseeable future.
X
Now, define in your form four input fields that will be used by Uniform. 
THIS IS THE IMPORTANT PART!  These input fields are of the type "hidden"
and will thus be passed to Uniform without user intervention. The four
fields are named "reply", "letter", "to", and "subject".
X
The "to" and "subject" fields contain, respectively, the address to whom 
the output of this form should be sent and the subject header of the mail 
that is sent. Here are examples:
X     <input type="hidden" name="to" value="mosheh@thalia.muse.net">
X     <input type="hidden" name="subject" value="Merchandise Order">
The Uniform-processed output of the form will be sent to 
mosheh@thalia.muse.net with the subject of "Merchandise Order".
X
The "reply" field contains a miniature HTML document that will be returned
to the person who filled out the form. Generally, this will be a short
acknowledgement of the user's submission.
X     <input type="hidden" name="reply" value="
X     <html><title>Request Received</title><body>
X     <h3>Thank You For Your Input</h3>
X     Thank you for your input. It means a lot to us. Your comments
X     will be processed as soon as possible. Thank you.<p>
X     <hr>
X     </body></html>
X     ">
X
The "letter" field contains a template for the letter that will be mailed 
to the person specified in the "to" field. Note the use of :: substitutions.
X     <input type="hidden" name="letter" value="
X     World Wide Web (WWW) interface received request for:
X          ::paper reams of paper
X          ::paint buckets of paint
X     Mailing address:
X          ::address
X     ">
X
X
Your form is now Uniform compliant.
X
X
SUBSTITUTION
When acknowledging submissions and when communicating via mail the 
particulars of those substitutions, it is often necessary to include in 
acknowledgements and letters entities that will be substituted by the 
actual values of variables defined by a user in the script. In "letter" 
and "reply" fields, an input field's value can be replaced with the value 
input by the user by prefixing the name of the field. An example would 
serve to describe here much better than words.
X
X     What is your real name?<br>
X     <input type="text" name="realname" size=20 maxlength=30><p>
X     <input type="hidden" name="letter" value="
X     The real name of the submitter is ::realname.
X     ">
Here, the value entered in the form by the user will be substituted for 
the string "::realname" in the letter sent to the page's owner.
X
X
EXAMPLE FORM
X
Enclosed is a form named freds.html. It's a small, simple example of 
how one would write a Uniform-compliant page and configure Uniform. A 
smaller example is given here:
X
<form method="post" action="http://thalia.muse.net/cgi-bin/uniform.pl">
What is your name?<br>
<input type="text" name="realname"><p>
What do you want?<br>
<input type="text" name="want"><p>
<input type="hidden" name="to" value="mosheh@thalia.muse.net">
<input type="hidden" name="subject" value="Somebody Wants Something!">
<input type="hidden" name="letter" value="
Some poor fool was using a form and decided to complain! ARGH! ;-)
Their name is ::realname.
I asked what they wanted and they said:
::want
X
So get to work on it, you lazy bastard!
X                 - Your Favorite Script
">
<input type="hidden" name="reply" value="
<html><title>Thanks a Lot</title><body>
<center><font size=+2 color=#000FF>You've Been Heard</font></center>
All that you have said and done has been told to the great one, 
::realname. If what you ask is not granted within three days, send mail 
to ::to and you stand a fighting chance of seeing anything done.<p>
Have a nice day.<p>
<center><a href="http://www.muse.net/">Back To Our Home Page</a></center>
<p><hr></body></html>
">
</form>
X
X
KNOWN SHORTCOMINGS
X
Uniform is very useful for taking the load off administrators when it 
comes to CGI-interactive forms. It does this by acting as a generic form 
parser and mailer and counting on the form itself to pass the details in. 
This gives inherent limitations, such as:
X	* Replies and letters are dumb, supporting only the special 
feature of variable substitution. Replies and letters can't modify 
themselves according to the input. i.e. Uniform will output blanks where 
blank input was given. If you want complicated things, write your own. 
This is meant to cover those cases where nothing complex is needed.
X	* The script can't act differently under different input 
conditions. It always acknowledges and forwards and can't do much else.
X
X
SHAR_EOF
  $shar_touch -am 0330185396 'README' &&
  chmod 0644 'README' ||
  echo 'restore of README failed'
  shar_count="`wc -c < 'README'`"
  test 6988 -eq "$shar_count" ||
    echo "README: original size 6988, current size $shar_count"
fi
exit 0

