Out of the Oven
September 18, 2000
That smell is in the air! We can now imagine an output script that retrieves
the cookie and takes appropriate action. Let's walk through such a script
bit by bit (or should we say chunk by chunk, chip by chip, ...?).
#!/usr/bin/perl
#Cookie-based output results script
use CGI;
my $cgiobj=new CGI;
#Fill preferences hash from subroutine
my %prefs=%{&get_prefs};
First, the obligatory setup for the CGI module. Next, we build a preferences
hash, known as %prefs, which will contain the personalization
settings that we want to use. The subroutine &get_prefs will
actually build the hash, so let's look at that routine now:
sub get_prefs {
#Retrieve saved preferences from cookie, if present
#Or else set to default values
my %prefs=();
if ($cgiobj->cookie('searchprefs')) {
%prefs=$cgiobj->cookie('searchprefs');
}
else { #default values
%prefs=( "resultsPerPage"=>10,
"linkColor"=>"#0000FF",
"fontType"=>"Arial, Helvetica, sans-serif",
"fontSize"=>3,
"returnField"=>"PRNAME"
);
}
return \%prefs;
}
The routine checks for the presence of a cookie named searchprefs,
which the browser will have delivered if this script meets the domain and
path criteria. If present, we fill a hash with the values from the cookie,
quite simply using the cookie method of the CGI object. The
keys/values returned from the cookie will represent the keys/value that were
stored in the previous script, based on the names/values of the form fields
in the web page where the user chose their settings. To this end, we named
those form fields "resultsPerPage", "linkColor",
etc.
Should there be no cookie present, we set some default values for the
preferences hash, again using the key names that we had used for the
original HTML form fields.
In the real world this script would have to generate something to output,
whether those are results from a database query, or whatever. We're not
concerned with that here, and so to simplify things let's imagine that the
"search results" are contained in a simple hash.
##HERE WOULD BE CODE THAT PERFORMED SEARCH
##AND RETRIEVED RESULTS INTO A PERL DATA STRUCTURE
##SUCH AS A HASH
my %results=%{&do_search};
sub do_search {
#A real subroutine would perform the actual search
my %results=( "Product 1"=>"29.99",
"Product 2"=>"39.99",
"Product 3"=>"9.99"
);
return \%results;
}
As you can see, we've rigged some simple results, a hash with product names
as the keys and prices as the values.
We now have the two key elements for generating personalized results: the
result data and the personalized preference data. All that remains is to
output the result data, and modify the output where appropriate to conform
to the personalized settings.
print $cgiobj->header();
print &dump_results(\%results,\%prefs);
sub dump_results{
#Output search results modified by preferences
my ($results,$prefs)=@_;
#unpack 'returnField' parameter into a hash of fields to return
my %returnFields=();
foreach (split /\0/,$prefs->{returnField}) {
$returnFields{$_}++;
}
The browser prepared for output, courtesy of the header method, we
print the results of the subroutine &dump_results. Early in this
routine, we face a small challenge. The original personalization page
allowed the user to select which fields to display in the search results.
These fields were represented by checkbox form fields, and each checkbox
was assigned the same name, "returnField". In case the user
selected two or more field names, the CGI script would have received several
values with the same key, "returnField". When the cookie was
created, the CGI object would have automatically packed each of these values
into the one key name, separating each with a null character, also
represented by the escape sequence \0.
At this stage, we want to unpack this data, so that we can create a hash
representing each field name that the user does want displayed. Thus, we
create a hash to keep track of which fields to display,
%returnFields, and we populate this hash by splitting the
returnField key on the null delimiter. Notice that these field names
are stored as keys in the %returnFields hash, not as values. We use
this technique to quickly determine whether an item is "on the
list" or not.
Continuing with the &dump_results subroutine...
my $resultHTML="";
#debugging summary
foreach (keys %{$prefs}) {
$resultHTML.="$_ -> ".$prefs->{$_}."<br>";
}
$resultHTML.="<TABLE WIDTH='75%'>";
my $count=1;
foreach my $result (sort {$a cmp $b} keys %{$results}) {
$resultHTML.= "<TR>";
$resultHTML.= "<TD><FONT FACE='".$prefs->{fontType}. "' SIZE='".$prefs->{fontSize}. "'>$result</FONT></TD>" if ($returnFields{PRNAME});
$resultHTML.= "<TD><FONT FACE='".$prefs->{fontType}. "' SIZE='".$prefs->{fontSize}."'>".$results->{$result}. "</FONT></TD>" if ($returnFields{PRPRICE});
$resultHTML.= "<TD><A HREF='/cgi-bin/searchresults.cgi?PRNAME=". CGI::escape($result)."'><FONT FACE='".$prefs->{fontType}. "' SIZE='".$prefs->{fontSize}."' COLOR='".$prefs->{linkColor}. "'>More details</FONT></A></TD>" if ($returnFields{PRLINK});
$resultHTML.="</TR>";
$count++;
if ($count>$prefs->{resultsPerPage}) {
last;
}
}
$resultHTML.="</TABLE>";
return $resultHTML;
}
Here on in, we construct the HTML that will be output. First, a small
foreach loop summarizes each of the keys in the %prefs hash, for
debugging purposes while we test the script. Now we begin building each row
of the result table. The $count variable keeps track of how many rows
have been output, so that we can stop before reaching the
resultsPerPage limit the user had chosen.
For each row, we wrap the output inside a <FONT> tag whose attributes
are filled in using values from the personalization data. Each string
assignment to $resultHTML represents one tabular column
(<TD>...</TD>) of the result table. Notice at the end of each
string assignment, in bold for legibility, is an if statement.
This statement tests whether that particular field is "on the
list" of requested fields, which we built into %returnFields
from the personalization data. Should the if statement prove false, the
clause preceding it (e.g. the whole column) will not be created.
Once the result rows are completed, we finish off the table HTML and return
the results. The key lesson in this code was how we continually made
reference to keys in the %prefs hash to modify the behavior of the
output script in accordance with parameters inherited from the
personalization data that was retrieved from the cookie.
In the Kitchen with Perl
The Perl You Need to Know
Crumbs
|