Perl Receiving and Maintaining Poll Results

Provides an example script for taking and receiving a poll using Perl code.

#!/usr/bin/perl
#******************************************************
# This script creates and adds responses to a database
# of Operating Systems Characteristics survey responses. 
#******************************************************
$database_file = "/home/httpd/data/oschar1.dat";

$ASCII_thirteen = pack("c", 13);
$space = " ";

#Check to see if a cookie with the name ospoll1 and value done or start are on the client
$rcvd_cookies = $ENV{'HTTP_COOKIE'};
@cookies = split /;/, $rcvd_cookies;
foreach $cookie (@cookies)
{
   if ($cookie eq "ospoll1=done")
   { 
      $polltaken=1; #Poll was previously taken
   }
   if ($cookie eq "ospoll1=start")
   {
       $pollready=1;
   }
}

#If poll was not taken and this is not for display only as indicated by the query string
if (($ENV{'QUERY_STRING'} ne "display") && ($polltaken != 1) && ($pollready == 1))
{
    $polltaken=2;  
# Format the Web data received and make sure
# it does not contain any server-side includes
   %data_received = &Get_Data();
   &No_SSI(*data_received);

# Make sure all mandatory fields are full and
# truncate all strings to a maximum of 255 characters
# Also make sure no new-line characters.
   foreach $key (keys(%data_received)) {
	 $data_received{$key} =~ s/$ASCII_ten//ge; 
	$data_received{$key} =~ s/$ASCII_thirteen/$space/ge;
   }

   if (%data_received)
   {
      open(DATABASE,">>$database_file") || die "Content-type: text/html\n\nCannot open database.";

# Because the Web server could receive several requests for a CGI script at the same time
# Lock the database file now.
# The second parameter to the flock function, which in this case is 2, 
# is a code that determines the type of lock to be placed on the file. 
# The number 2 designates setting a write lock on the specified file stream. 
   flock(DATABASE, 2);

# each element in the %data_received associative array is printed one at a time, 
# surrounded by quotes and separated by commas

      print DATABASE $data_received{"expertise"} . "," . 
	$data_received{"security"} . "," . 
	$data_received{"stability"} . "," . 
	$data_received{"ease"} . "," . 
	$data_received{"networking"} . "," . 
	$data_received{"monitoring"} . "," . 
	$data_received{"learning"} . "," . 
	$data_received{"documentation"} . "," . 
	$data_received{"cost"} . "," . 
	$data_received{"compatability"} . "," .
        $data_received{"communication"} . "," . 
        $data_received{"speed"} . "," .
        $data_received{"people"} . "," .
        $data_received{"support"} . "," .
        $data_received{"scalability"} . "," .
        $data_received{"bugfix"} . "\n";


# The number 8 designates removing all locks from the specified file stream
      flock(DATABASE, 8);
      close(DATABASE);
   }  # end if data was received
}   # end if the poll was not taken
 
# Place a cookie on the user's machine to show the poll was taken.
if ($polltaken == 2)
{
    $fut_time=gmtime(time()+365*24*3600)." GMT";  # Add 12 months (365 days)
    $cookie = "ospoll1=done; path=/; expires=$fut_time; $secure";
    print "Set-Cookie: " . $cookie . "\n";
}

# Report statistics
# Generate database statistics for reporting
    open(DATABASE,"<$database_file") || die "Content-type: text/html\n\nCannot open database.";
    @lines = <DATABASE>
    $responses = 0;
    $expertise = 0;
    $security = 0;
    $stability = 0;
    $ease = 0;
    $networking = 0;
    $monitoring = 0;
    $learning = 0;
    $documentation = 0;
    $cost = 0;
    $compatability = 0;
    $communication = 0;
    $speed = 0;
    $people = 0;
    $support = 0;
    $scalability = 0;
    $bugfix = 0;
foreach $line (@lines)
{
    $responses++;
    @entries = split(/,/, $line);
    $security += $entries[1];
    $stability += $entries[2];
    $ease += $entries[3];
    $networking += $entries[4];
    $monitoring += $entries[5];
    $learning += $entries[6];
    $documentation += $entries[7];
    $cost += $entries[8];
    $compatability += $entries[9];
    $communication += $entries[10];
    $speed += $entries[11];
    $people += $entries[12];
    $support += $entries[13];
    $scalability += $entries[14];
    $bugfix += $entries[15];
}
$security = (10 * $security)/$responses;
$stability = (10 * $stability)/$responses;
$ease = (10 * $ease)/$responses;
$networking = (10 * $networking)/$responses;
$monitoring = (10 * $monitoring)/$responses;
$learning = (10 * $learning)/$responses;
$documentation = (10 * $documentation)/$responses;
$cost = (10 * $cost)/$responses;
$compatability = (10 * $compatability)/$responses;
$communication = (10 * $communication)/$responses;
$speed = (10 * $speed)/$responses;
$people = (10 * $people)/$responses;
$support = (10 * $support)/$responses;
$scalability = (10 * $scalability)/$responses;
$bugfix = (10 * $bugfix)/$responses;
close(DATABASE);

# Output success message
print "Content-type: text/html", "\n\n";        # MIME header.
print "<HTML>", "\n";
print "<HEAD>";
print "<TITLE>Poll Results.</TITLE>", "\n";
print "</HEAD>", "\n";
print '<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#51188E" ALINK="#FF0000" BACKGROUND="../gifs/clouds.gif">';
print "\n";
print '<center><A href="index.html" target="_top">Operating Systems Contents Page</A></center>' . "\n";
print "<center><H1>Current Poll Results</H1></center>\n";
print "<H2>Responses: $responses</H2>\n";
print "<B>Security:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $security . '%" color="ff0000">' . "\n";
print "<B>Stability:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $stability . '%" color="00ff00">' . "\n";
print "<B>Ease of Use:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $ease . '%" color="0000ff">' . "\n";
print "<B>Networking:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $networking . '%" color="800000">' . "\n";
print "<B>Monitoring and Auditing:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $monitoring . '%" color="008000">' . "\n";
print "<B>Learning:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $learning . '%" color="000080">' . "\n";
print "<B>Documentation:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $documentation . '%" color="800080">' . "\n";
print "<B>Cost:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $cost . '%" color="808000">' . "\n";
print "<B>Compatability:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $compatability . '%" color="008080">' ."\n";
print "<B>Communication with foreign OSs:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $communication . '%" color="ff0000">' . "\n";
print "<B>Speed:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $speed . '%" color="00ff00">' . "\n";
print "<B>Available IT people:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $people . '%" color="0000ff">' . "\n";
print "<B>Support:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $support . '%" color="800000">' . "\n";
print "<B>Scalability:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $scalability . '%" color="008000">' . "\n";
print "<B>Speed of getting bugs fixed:</B>\n";
print '<HR SIZE="15" ALIGN="left" width="' . $bugfix . '%" color="000080">' ."\n";
print "<BR>\n";
print '<center><A href="index.html" target="_top">Operating Systems Contents Page</A></center>' . "\n";

print "</BODY>", "\n";
print "</HTML>", "\n";



sub Get_Data { 
	local (%user_data, $input_string, $nv_pair, 
		@nv_pairs, $name, $value); 

	# If the data was sent via POST, then it is available 
	# from standard input. Otherwise, the data is in the 
	# QUERY_STRING environment variable. 
	if ( $ENV{'REQUEST_METHOD'} eq "POST" )
        {
#                $len = $ENV{`CONTENT_LENGTH`};
		read(STDIN,$input_string,$ENV{'CONTENT_LENGTH'});
	} 
	else {
		$input_string = $ENV{'QUERY_STRING'}; 
	}
	
	# This line changes the + signs to spaces. 
	$input_string =~ s/\+/ /g;

	# This line places each name/value pair as a separate 
	# element in the name_value_pairs array. 
	@nv_pairs = split(/&/, $input_string); 
	# This code loops over each element in the name_value_pairs 
	# array, splits it on the = sign, and places the value 
	# into the user_data associative array with the name as the 
	# key.
	foreach $nv_pair (@nv_pairs) {
	       ($name, $value) = split(/=/, $nv_pair); 

		# These two lines decode the values from any URL
		 # hexadecimal encoding. The first section searches for a 
		# hexadecimal number and the second part converts the 
		# hex number to decimal and returns the character 
		# equivalent. 
		$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/ge; 
		$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/ge; 

		# If the name/value pair has already been given a value, 
		# as in the case of multiple items being selected, then 
		# separate the items with a ":".
		if (defined($user_data{$name})) {
			$user_data{$name} .= ":" . $value; } 
		else { 
			$user_data{$name} = $value; 
		} 
	} 
	return %user_data;
}

sub No_SSI {
	 local (*data) = @_;
	 foreach $key (sort keys(%data)) { 
		$data{$key} =~ s/<!--(.|\n)*-->//g; 
	}
}