Apache Server Survival Guide asg05.htm
|
|
|
#!/bin/sh # HelloInSh - A trivial example of a shell CGI # This program returns html content. The very first line of this # listing # Comments lines used for providing more information to the programmer # or documentation lines have the '#' character as the first character # in the line. The first # symbol is special, it's not a comment. # It informs the operating system to use the program /bin/sh # as the command interpreter for the script that follows. # The very first thing, we do on our CGI is tell the server # what type of data we are returning, in this case it is html: # echo Content-type: text/html # # then we need to add a single line blank line, that separates the # 'header' from the actual stuff in our output: # echo # # At this point we need to provide 'body' that includes all the usual # tags and structure required by html. # because some of the characters such as the angle brackets # are interpreted by the sh as a redirection, we need to enclose them # with a single quote: # echo '<HTML>' echo '<HEAD>' echo '<TITLE> Hello World!</TITLE>' echo '</HEAD>' echo '<BODY>' echo '<H1>Hello World!</H1>' echo '</BODY>' echo '</HTML>' |
#!/usr/local/bin/perl # HelloInPerl, a trivial example of a CGI in Perl # # Output appropriate header for server, we included two newlines, the '\n'. # print "Content-type: text/html\n\n"; # # Use a 'here' document format for easy readability and avoid need for many # many printf() statements. All the lines following the print line are 'printed' # verbatim, until the 'STOP' tag is found. # print <<STOP; <HTML> <HEAD> <TITLE> Hello World!</TITLE> </HEAD> <BODY> <H1>Hello World!</H1> </BODY> </HTML> STOP # # Now we tell the operating system that this run of the program proceeded without # any errors by 'exiting' with a zero status. # exit(0); |
/* HelloInC - A trivial example of a CGI in C. */ #include <stdio.h> int main (void) { printf ("Content-type: text/html\n\n"); /* As our Perl or sh examples, the first thing to output is the Content-type */ printf("<HTML>"); printf("<HEAD>"); printf("<TITLE>Hello World!</TITLE>"); printf("</HEAD>"); printf("<BODY>"); printf("<H1>Hello World!</H1>"); printf("</BODY>"); printf("</HTML>"); return; } |
http://localhost/cgi-bin/HelloInSh http://localhost/cgi-bin/HelloInPerl http://localhost/cgi-bin/HelloInC |
You should get a result similar to the screen shown in Figure 5.1.
Figure 5.1. The output for the any of the Hello World! programs.
If you are having problems with the programs, see if you can get them to run on a terminal. If it will output the header and some HTML, and it doesn't give you an error, the problem may be with UNIX permissions. Recheck that your program is executable. If the problem is with a script, check that the location of the interpreter program is where I list it (the first line of the script). If it is not, change the first line to the absolute path of your command interpreter and try again (if the program is found anywhere in any of the directories specified by your path, it will be listed by using the whereis command. For more information on how to use the whereis program, please refer to your UNIX documentation). Note that the !# are required symbols that tell the shell that the script should be run by the specified command processor .
|
QUERY_STRING = Name=My+Name&Address=Some+Street+Rd.%0ACity%2C+State++12345& name=Submit |
The Name field contains the data
My+Name The space between My and Name is encoded to a +.
The Address field contains
Some Street Rd. City, State 12345 In the second field, spaces are also converted to + characters. In addition, the newline after Rd. is encoded to %0A. The %2C corresponds to a comma (,).
|
#!/bin/sh echo Content-type: text/plain echo echo SERVER_SOFTWARE = $SERVER_SOFTWARE echo SERVER_NAME = $SERVER_NAME echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE echo SERVER_PROTOCOL = $SERVER_PROTOCOL echo SERVER_PORT = $SERVER_PORT echo REQUEST_METHOD = $REQUEST_METHOD echo HTTP_ACCEPT = $HTTP_ACCEPT echo PATH_INFO = $PATH_INFO echo PATH_TRANSLATED = $PATH_TRANSLATED echo SCRIPT_NAME = $SCRIPT_NAME echo QUERY_STRING = $QUERY_STRING echo REMOTE_HOST = $REMOTE_HOST echo REMOTE_ADDR = $REMOTE_ADDR echo REMOTE_USER = $REMOTE_USER echo AUTH_TYPE = $AUTH_TYPE echo CONTENT_TYPE = $CONTENT_TYPE echo CONTENT_LENGTH = $CONTENT_LENGTH |
The same CGI can be written in Perl, as shown in Listing 5.5.
Listing 5.5. The simple CGI script in Perl .
|
#!/usr/local/bin/perl print "Content-type: text/plain\n\n"; print <<STOP; SERVER_SOFTWARE = $ENV{SERVER_SOFTWARE} SERVER_NAME = $ENV{SERVER_NAME} GATEWAY_INTERFACE = $ENV{GATEWAY_INTERFACE} SERVER_PROTOCOL = $ENV{SERVER_PROTOCOL} SERVER_PORT = $ENV{SERVER_PORT} REQUEST_METHOD = $ENV{REQUEST_METHOD} HTTP_ACCEPT = $ENV{HTTP_ACCEPT} PATH_INFO = $ENV{PATH_INFO} PATH_TRANSLATED = $ENV{PATH_TRANSLATED} SCRIPT_NAME = $ENV{SCRIPT_NAME} QUERY_STRING = $ENV{QUERY_STRING} REMOTE_HOST = $ENV{REMOTE_HOST} REMOTE_ADDR = $ENV{REMOTE_ADDR} REMOTE_USER = $ENV{REMOTE_USER} AUTH_TYPE = $ENV{AUTH_TYPE} CONTENT_TYPE = $ENV{CONTENT_TYPE} STOP |
The Perl program is similar to the C program, shown in Listing 5.6. The only notable difference is that the $ENV{variable_name} syntax is used to inform Perl that I am referring to an environment variable.
Listing 5.6. The simple CGI script in C .
|
#include <stdio.h> #include <stdlib.h> main (int argc, char *argv[]) { char *p; // Keep the server happy. Put in a Content-type header: printf("Content-type: text/plain\n\n"); /* Most versions of printf will handle a NULL pointer as "(Null // Pointer)" otherwise printf may crash. The solution is a macro that // always returns something valid. The macro below tests to see if // getenv returned something. If it returns NULL, it returns a // "VARIABLE NOT SET" message, that should make old versions of printf /* happy. #define sgetenv(x) ((p = getenv(x)) ? p : "VARIABLE NOT SET") printf("SERVER_SOFTWARE = %s\n", sgetenv("SERVER_SOFTWARE")); printf("SERVER_NAME = %s\n", sgetenv("SERVER_NAME")); printf("GATEWAY_INTERFACE = %s\n", sgetenv("GATEWAY_INTERFACE")); printf("SERVER_PROTOCOL = %s\n", sgetenv("SERVER_PROTOCOL")); printf("SERVER_PORT = %s\n", sgetenv("SERVER_PORT")); printf("REQUEST_METHOD = %s\n", sgetenv("REQUEST_METHOD")); printf("HTTP_ACCEPT = %s\n", sgetenv("HTTP_ACCEPT")); printf("PATH_INFO = %s\n", sgetenv("PATH_INFO")); printf("PATH_TRANSLATED = %s\n", sgetenv("PATH_TRANSLATED")); printf("SCRIPT_NAME = %s\n", sgetenv("SCRIPT_NAME")); printf("QUERY_STRING = %s\n", sgetenv("QUERY_STRING")); printf("REMOTE_HOST = %s\n", sgetenv("REMOTE_HOST")); printf("REMOTE_ADDR = %s\n", sgetenv("REMOTE_ADDR")); printf("REMOTE_USER = %s\n", sgetenv("REMOTE_USER")); printf("AUTH_TYPE = %s\n", sgetenv("AUTH_TYPE")); printf("CONTENT_TYPE = %s\n", sgetenv("CONTENT_TYPE")); printf("CONTENT_LENGTH = %s\n", sgetenv("CONTENT_LENGTH")); exit(0); } |
The one notable thing occurring in this program is the use of the getenv(variable_name) function . This function returns the string stored in the environment variable matching the name of the argument provided. The following is an example:
string_pointer = getenv("HOME"); This call would return a pointer to a string describing the location of the home directory of the user running the program. If you look closely, you'll notice that I created a macro for the getenv function called sgetenv. This macro is a safeguard for users of older versions of the printf() function. If getenv returns a NULL pointer, ancient versions of printf may crash the program. My program safeguards against this condition by always returning a printable string. In this case, a NULL value will return the string VARIABLE NOT SET.
If you want to write CGI programs in C, probably the best way to write them would be to use Thomas Boutell's cgic library. This library is available from http://www.boutell.com. I have included a copy of the library on the CD-ROM for your convenience. I have written a similar Hello World! application using cgic, shown in Listing 5.7.
Listing 5.7. Hello World! in cgic.
|
/**************************** * * HelloWorld.cgi * * This program prints out all the environment variables using Thomas * Boutell's cgic library. Make sure cgic.h is in your current dir- * ectory, and that libcgic.a is installed in the usual place (most of * the time /usr/local/lib. Please follow the cgic installation * instructions. * *******************************/ #include <stdio.h> #include "cgic.h" #define FIELD_SIZE 51 #define DEBUG 0 int cgiMain() { #if DEBUG /* Load a saved CGI scenario if we're debugging */ cgiReadEnvironment("/tmp/capcgi.dat"); #endif cgiHeaderContentType("text/html"); fprintf(cgiOut, "<HTML><HEAD>\n"); fprintf(cgiOut, "<TITLE>Hello World!</TITLE></HEAD>\n"); fprintf(cgiOut, "<BODY><H1>Hello World!</H1>\n"); fprintf(cgiOut, "cgiServerSoftware=%s<BR>\n", cgiServerSoftware); fprintf(cgiOut, "cgiServerName=%s<BR>\n", cgiServerName); fprintf(cgiOut, "cgiGatewayInterface=%s<BR>\n", cgiGatewayInterface); fprintf(cgiOut, "cgiServerProtocol=%s<BR>\n", cgiServerProtocol); fprintf(cgiOut, "cgiServerPort=%s<BR>\n", cgiServerPort); fprintf(cgiOut, "cgiRequestMethod=%s<BR>\n", cgiRequestMethod); fprintf(cgiOut, "cgiPathInfo=%s<BR>\n", cgiPathInfo); fprintf(cgiOut, "cgiPathTranslated=%s<BR>\n", cgiPathTranslated); fprintf(cgiOut, "cgiScriptName=%s<BR>\n", cgiScriptName); fprintf(cgiOut, "cgiQueryString=%s<BR>\n", cgiQueryString); fprintf(cgiOut, "cgiRemoteHost=%s<BR>\n", cgiRemoteHost); fprintf(cgiOut, "cgiRemoteAddr=%s<BR>\n", cgiRemoteAddr); fprintf(cgiOut, "cgiAuthType=%s<BR>\n", cgiAuthType); fprintf(cgiOut, "cgiRemoteUser=%s<BR>\n", cgiRemoteUser); fprintf(cgiOut, "cgiRemoteIdent=%s<BR>\n", cgiRemoteIdent); fprintf(cgiOut, "cgiContentType=%s<BR>\n", cgiContentType); fprintf(cgiOut, "cgiAccept=%s<BR>\n", cgiAccept); fprintf(cgiOut, "cgiUserAgent=%s<BR>\n", cgiUserAgent); fprintf(cgiOut, "</BODY></HTML>\n"); return 0; } |
% setenv 'REQUEST_METHOD' 'GET' % setenv 'QUERY_STRING' 'color=red&size=large' % somecgi.cgi [results] |
These commands assume that you are using csh, of course. If you are using the Bourne shell (sh), declare environment variables as follows:
|
% REQUEST_METHOD=GET % QUERY_STRING="color=red&size=large" % export REQUEST_METHOD % export QUERY_STRING % somecgi.cgi [results] |
Just set the environment variables yourself and run the CGI program from the prompt. Can you do the same thing with POST? After all, POST is done virtually the same way except for stdin. Well, this is what you'd have to do:
|
% setenv 'REQUEST_METHOD' 'POST' % setenv 'CONTENT_LENGTH' '20' % somecgi.cgi (waiting for input) color=red&size=large % [results] |
<HTML> <HEAD> <TITLE>WhoAreYou</TITLE> </HEAD> <BODY BGCOLOR="#ffffff"> <FORM ACTION="/cgi-bin/printenv" ENCTYPE="x-www-form-encoded" METHOD="GET"> <HR> <IMG SRC="1.gif" WIDTH="57" HEIGHT="77" ALIGN="MIDDLE"> <STRONG>Your name: </STRONG> <INPUT NAME="Name" TYPE="text" SIZE="53"><BR> <IMG SRC="2.gif" WIDTH="57" HEIGHT="77" ALIGN="MIDDLE"> <STRONG>Your Address: </STRONG> <TEXTAREA NAME="Address" ROWS="6" COLS="50"></TEXTAREA> <BR> <HR> <P><CENTER><INPUT NAME="name" TYPE="submit" VALUE="Submit"></CENTER> </FORM> </BODY> </HTML> |
This code produces a form that looks like Figure 5.1, when viewed under Microsoft's Internet Explorer version 3.
Figure 5.2. A simple form viewed with Microsoft's Internet Explorer version 3.
You can create forms by just typing the specifications, but sometimes it's a lot easier to use a graphical tool . Graphical tools allow you to lay out the form in an attractive and useful way. I like creating the basic form template in a program called Adobe PageMill. PageMill is an easy-to-use program for the Macintosh that generates HTML pages.
When you submit this form, your browser will return something similar to the following:
|
SERVER_SOFTWARE = Apache/1.1.1 GATEWAY_INTERFACE = CGI/1.1 DOCUMENT_ROOT = /NextLibrary/WebServer/htdocs REMOTE_ADDR = 204.95.222.3 SERVER_PROTOCOL = HTTP/1.0 REQUEST_METHOD = GET REMOTE_HOST = lithium HTTP_REFERER = http://hydrogen/book/WhoAreYou.htmld/ QUERY_STRING = Name=Alberto+Ricart&Address=N70+W6340+Bridge+Rd. %0D%0ACedarburg%2C+WI++53012&name=Submit HTTP_USER_AGENT = Mozilla/2.0 (compatible; MSIE 3.0B; Windows 95;640,480 HTTP_ACCEPT = */* HTTP_ACCEPT_LANGUAGE = en SCRIPT_NAME = /cgi-bin/printenv SCRIPT_FILENAME = /NextLibrary/WebServer/apache/cgi-bin/printenv HTTP_PRAGMA = no-cache SERVER_NAME = localhost SERVER_PORT = 80 HTTP_HOST = hydrogen SERVER_ADMIN = webmaster@ACCESSLINK.COM |
|
package CGILIB; ################################### # Print the content-type header. # # &print_header; sub print_header { print "Content-type: text/html\n\n"; } ##################################### # Print a canned header with title as argument. # # sub canned_header { my( $title ) = @_; print "<HTML>\n"; print "<HEAD>\n"; print "<TITLE>$title</TITLE>\n"; print "</HEAD>\n"; } #################################### # Print the closing lines for an HTML document. # # &print_closing; sub print_closing { print "</BODY></HTML>\n"; } #################################### # Parse the HTML header and form # information # # %ASSOC_ARRAY = &parse_form; sub parse_form { my ($buffer,$name,$value,%FORM); my ($content_length,$query_string,$request_method); $content_length = $ENV{'CONTENT_LENGTH'}; $query_string = $ENV{'QUERY_STRING'}; $request_method = $ENV{'REQUEST_METHOD'}; # If the REQUEST_METHOD was POST, read from stdin, else the string is in QUERY_STRING if ($request_method eq 'POST') { read(STDIN, $buffer, $content_length); } else { $buffer = $query_string; } # Split the name-value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); # Un-Webify plus signs and %-encoding $name =~ tr/+/ /; $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # Stop people from using subshells to execute commands # Not a big deal when using sendmail, but very important # when using UCB mail (aka mailx). $value =~ s/~!/ ~!/g; # Uncomment for debugging purposes # print "Setting $name to $value<P>\n"; $FORM{$name} = $value; } %FORM; # Returns %FORM to caller source... } #End Sub form_mail ############################## # # sub dump_env_vars # # Dumps the contents of %ENV in HTML # # INPUTS: \%ENV # ############################### sub dump_env_vars { my ($ENV) = @_; foreach (keys %$ENV) { print "$_=$$ENV{$_}<BR>"; } } # For require files 1; |
Listing 5.9. mail.cgi .
|
#!/usr/local/bin/perl -w # # mail.cgi: This is an CGI program that sends the results of the fill-out # form to the recipient indicated in the form. # # Note: This CGI program relies on hidden variables in the form associated # with this listing. require CGILIB; #Use the lib included in book use strict; #Make sure we declare all our variables $| = 1; #Flush STDOUT my( %FORM ); #Declare all the variables my( $recipient, $sender, $thank_you ); my( $mailprog ); %FORM = CGILIB::parse_form(); $mailprog = '/usr/lib/sendmail'; # Location of thank_you page to be displayed after submitting form $thank_you = $FORM{thank_you_location}; $recipient = $FORM{recipient}; $sender = $FORM{email}; #Grab some environment info $FORM{Date} = `date`; $FORM{ServerProtocol} = $ENV{'SERVER_PROTOCOL'}; $FORM{RemoteHost} = $ENV{'REMOTE_HOST'}; $FORM{RemoteAddress} = $ENV{'REMOTE_ADDR'}; $FORM{HTTPUserAgent} = $ENV{'HTTP_USER_AGENT'}; email_recipient(); say_thank_you(); exit(0); ################################ # # email_recipient() : calls the mail program and sends a message. # sub email_recipient { my( $key ); open (MAIL, "|$mailprog $recipient") || die "Cant open mail program: $!"; print MAIL "To: $recipient\n"; print MAIL "From: $sender ($FORM{name})\n"; print MAIL "Reply-To: $sender ($FORM{name})\n"; print MAIL "Subject: Email from Web Form :) \n\n"; #Need two \n's for foreach ( keys %FORM ) { print MAIL "$_ : $FORM{$_}\n"; } print MAIL "\n\n End of email message.\n"; close( MAIL ); } ################################## # # say_thank_you() : redirects user to the thank-you page. # sub say_thank_you { print "location: $thank_you\n\n"; } |
Listing 5.10. form.html .
|
<HTML> <HEAD> <TITLE>My Cool Email Form</TITLE> </HEAD> <BODY> <FORM METHOD="GET" ACTION="mail.cgi"> <INPUT NAME="recipient" TYPE="hidden" VALUE="youremail@yourdomain.com"> <INPUT NAME="thank_you_location" TYPE="hidden" VALUE="http://www.yourdomain.com/ thank_you.html"> <P> <STRONG>Name:</STRONG><BR> <INPUT NAME="name" TYPE="text" SIZE=40> </P> <P> <STRONG>Email:</STRONG><BR> <INPUT NAME="email" TYPE="text" SIZE=40> </P> <P> <STRONG>Comments:</STRONG></BR> <TEXTAREA NAME="comments" COLS=40 ROWS=10></TEXTAREA> </P> <INPUT TYPE="submit"> </FORM> </BODY> </HTML> |
As you can see, I have included an example form. You may be wondering about the thank_you.html URL in the variable thank_you_location. Well, you have to create it. It is what your page visitors will see after they submit their form to the mail.cgi program. The process used is called redirection. A location header followed by two newline characters is sent, which redirects the user to the desired page.
The next program listing e-mails form results like the others, but uses Thomas Boutell's cgic library. Also, the form (shown in Listing 5.11) used is slightly different.
Listing 5.11. The form in cgic .
|
/********************************************** * * email.cgi: * * This program reads the fields of the given form and emails * the contents to the destination, kept in the hidden field from within * the form. The program uses Thomas Boutell cgic library. * ************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "cgic.h" #define FIELD_SIZE 51 #define ADDRESS_SIZE 500 #define DEBUG1 0 #define TO "webmaster@foo.bar.com" /* Substitute your address */ #define FROM "Web Fill-Out Form" void printEnvironmentVariables(); int cgiMain() { char name[FIELD_SIZE]; char address[ADDRESS_SIZE]; FILE* mailer; #if DEBUG1 /* Load a saved CGI scenario if we're debugging */ cgiReadEnvironment("/tmp/capcgi.dat"); #endif cgiFormStringNoNewlines( "Name", name, FIELD_SIZE); cgiFormString( "Address", address, ADDRESS_SIZE); /* Open a pipe to sendmail */ mailer = popen( "/usr/lib/sendmail -t", "w" ); if (mailer <= 0) { perror( "Unable to open pipe to sendmail\n" ); exit( 1 ); } #if DEBUG printf( "popen: Done\n" ); #endif /* Now fill in the sendmail headers */ fprintf( mailer, "To: " TO "\n" ); fprintf( mailer, "From: " FROM "\n" ); #if DEBUG printf( "From: Done\n" ); #endif fprintf( mailer, "Subject: Results of fill-out form for %s\n\n", name ); /* Now give the results of the form */ fprintf( mailer, "Name: %s\n", name ); fprintf( mailer, "Address: \n%s\n", address ); fprintf( mailer, "\nEnd of form submission.\n" ); pclose( mailer ); cgiHeaderContentType("text/html"); fprintf(cgiOut, "<HTML><HEAD>\n"); fprintf(cgiOut, "<TITLE>Form Mailed!</TITLE></HEAD>\n"); fprintf(cgiOut, "<BODY><H1>Form Mailed!</H1>\n"); fprintf(cgiOut, "Thank you, %s. Your email will be read ASAP!<BR>\n", name ); printEnvironmentVariables(); fprintf(cgiOut, "</BODY></HTML>\n" ); return 0; } void printEnvironmentVariables() { fprintf(cgiOut, "cgiServerSoftware=%s<BR>\n", cgiServerSoftware); fprintf(cgiOut, "cgiServerName=%s<BR>\n", cgiServerName); fprintf(cgiOut, "cgiGatewayInterface=%s<BR>\n", cgiGatewayInterface); fprintf(cgiOut, "cgiServerProtocol=%s<BR>\n", cgiServerProtocol); fprintf(cgiOut, "cgiServerPort=%s<BR>\n", cgiServerPort); fprintf(cgiOut, "cgiRequestMethod=%s<BR>\n", cgiRequestMethod); fprintf(cgiOut, "cgiPathInfo=%s<BR>\n", cgiPathInfo); fprintf(cgiOut, "cgiPathTranslated=%s<BR>\n", cgiPathTranslated); fprintf(cgiOut, "cgiScriptName=%s<BR>\n", cgiScriptName); fprintf(cgiOut, "cgiQueryString=%s<BR>\n", cgiQueryString); fprintf(cgiOut, "cgiRemoteHost=%s<BR>\n", cgiRemoteHost); fprintf(cgiOut, "cgiRemoteAddr=%s<BR>\n", cgiRemoteAddr); fprintf(cgiOut, "cgiAuthType=%s<BR>\n", cgiAuthType); fprintf(cgiOut, "cgiRemoteUser=%s<BR>\n", cgiRemoteUser); fprintf(cgiOut, "cgiRemoteIdent=%s<BR>\n", cgiRemoteIdent); fprintf(cgiOut, "cgiContentType=%s<BR>\n", cgiContentType); fprintf(cgiOut, "cgiAccept=%s<BR>\n", cgiAccept); fprintf(cgiOut, "cgiUserAgent=%s<BR>\n", cgiUserAgent); } |
The associated HTML code for the form is shown in Listing 5.12.
Listing 5.12. The new HTML code .
|
<HTML> <HEAD> <TITLE>WhoAreYou</TITLE> </HEAD> <BODY BGCOLOR="#ffffff"> <FORM ACTION="/cgi-bin/email.cgi" ENCTYPE="x-www-form-encoded" METHOD="GET"> <HR> <IMG SRC="1.gif" WIDTH="57" HEIGHT="77" ALIGN="MIDDLE" SIZE=50> <STRONG>Your name:</STRONG> <INPUT NAME="Name" TYPE="text" SIZE="53"><BR> <IMG SRC="2.gif" WIDTH="57" HEIGHT="77" ALIGN="MIDDLE"> <STRONG>Your Address:</STRONG> <TEXTAREA NAME="Address" ROWS="6" COLS="50"></TEXTAREA><BR> <HR> <BR> <P ALIGN=CENTER> <INPUT NAME="name" TYPE="submit" VALUE="Submit"> </P> </FORM> </BODY> </HTML> |
As you can see from the C code, the only thing really different about calling sendmail using C is that you use the popen() system call within the unistd.h header file. This system call is actually also what Perl uses internally when you do an open() to a pipe.
|
"http://www.foobar.com","http://www.yoursite.com/banners/foobar.gif","BORDER=0" "http://www.anothersite.com","http://www.yoursite.com/banners/anothersite.gif", "BORDER=0" "http://www.foobar.com","http://www.yoursite.com/banners/foobar.gif","BORDER=0" "http://www.foobar.com","http://www.yoursite.com/banners/foobar.gif","BORDER=0" |
In this configuration file, there are only two advertisers who have banners. However, foobar.gif will be seen 75 percent of the time (3 out of 4), while anothersite.gif will be seen 25 percent of the time (1 out of 4). This allows for a schedule of rates, as I mentioned.
Listing 5.13. The Perl randomizer .
|
#!/usr/local/bin/perl -w # # random.cgi - prints a graphic at random from a configuration file # # $conf_file: the absolute path to your configuration file (your listing of # URL's to the graphics. # # $ad_tag: the string outputted to the web page SSI location # # Call this script from a server-parsed html document (.shtml for example) and make # sure that server-side includes are enabled. # # Use the following example code: # # <!--#exec cmd="/yourpath/random.cgi"--> # # Of course, substitute your actual path to the random.cgi for / yourpath. Again, # this won't work unless Server-Side Includes are activated for Apache... use strict; # Declare all our variables before using them $| = 1; # Flush the output buffer #Variables my( $conf_file, $URL, $graphic, $ad_tag, $border ); my( @Graphics ); my( $num_graphics, $rand_graphic ); $conf_file = "/path-to-config-file/graphics.conf"; srand; open( IN, $conf_file ) || die "Cannot open $conf_file: $!"; @Graphics = <IN>; close( IN ); $num_graphics = @Graphics; #Get length of @Graphics array $rand_graphic = int( rand( $num_graphics - 1 ) ); ($URL,$graphic,$border) = split( /,/, $Graphics[$rand_graphic] ); $URL =~ s/\"//g; $graphic =~ s/\"//g; $border =~ s/\"//g; $ad_tag = "<A HREF=\"$URL\"><IMG SRC=\"$graphic\" $border></A>"; print $ad_tag; exit( 0 ); |
#!/usr/local/bin/perl -w # # board.cgi # # This program writes messages to a message board. # unshift (@INC,"/NextLibrary/WebServer/htdocs/perl/lib"); use strict; require CGILIB; # Parse the form data my(%FORM) = CGILIB::parse_form(); # The location of the messageboard file. This should be something # other than /tmp if you want the messages to hang around in case # your system goes down. However, /tmp is fine if all you want is # a chat session. my($board_file) = "/tmp/messageboard"; # Add a message if ( $FORM{action} =~ /add/ ) { # Add message only if message body isn't empty if ( $FORM{message} ne "" ) { add_message(); } } # Clear the board of messages. elsif ( $FORM{action} =~ /clear/ ) { system( "rm $board_file" ); } # Default actions display_form(); display_board(); exit(0); ################################ # # sub display_form() # # Prints out the header and the HTML for the form part of the page. # sub display_form { CGILIB::print_header(); print <<STOP; <HTML> <HEAD> <TITLE>Message Board</TITLE> </HEAD> <BODY> <H1>Message Board</H1> <FORM METHOD="GET" ACTION="board.cgi"> <TEXTAREA NAME="message" ROWS=10 COLS=40 WRAP=VIRTUAL></TEXTAREA> <BR> <INPUT NAME="action" TYPE="submit" VALUE="add"> <INPUT NAME="action" TYPE="submit" VALUE="clear"> <INPUT NAME="action" TYPE="submit" VALUE="update"> </FORM> <HR> STOP } ############################## # # sub display_board() # # Displays each message, in the order of most recent to least recent. # sub display_board { my( @board ); my( $count ) = 0; my( $message ); # Check to see if messageboard file exists. if (-e $board_file) { # Load message file and slurp all the messages into an array. # One message per line. Newline is the delineator. open( BOARD, $board_file ) || die "Cannot read $board_file: $_"; @board = <BOARD>; close( BOARD ); # Since messages are appended to the end of the file, simply # reversing the array will order them in most-recent-first. @board = reverse( @board ); # Now traverse the array, printing each message foreach $message (@board) { $count++; print "<STRONG>Message $count:</STRONG>\n"; print "<BLOCKQUOTE>$message\n"; print "</BLOCKQUOTE><BR>\n"; } } # Else message board is empty else { print "<EM>Message Board empty</EM>\n"; } print "</BODY></HTML>\n"; } ############################### # # sub add_message() # # Appends a message to the end of the messageboard file. Converts # all newlines to <BR> tags for convenient processing. # sub add_message { my( $message ); # Open messageboard file for appending. open( BOARD, ">>$board_file" ) || die "Cannot write $board_file: $_"; $message = $FORM{message}; # Convert newlines (\n) to <BR> $message =~ s/\n/<BR>/g; print BOARD "$message\n"; close( BOARD ); } |
|