Index

Where to find information on Perl

How to send a gif to a server

A script that selects a random file

Use of associative arrays

String handling in Perl

How to avoid that error messages from scripts go to the Web page

Links

CGI Programming Class

Most popular documents CGI script

Learning Perl


This is tutorial material on Perl mostly in the form of CGI programs that I write from time to time, trying to learn Perl. Perl isn't an easy language also for experienced programmers. I hope this material can be helpful to other people learning Perl.

Where to find information on Perl

These are trailblazer pages on Perl:

How to send a gif to a server

Sending a gif to a http server in response to a:
<img src=script.pl?>
request , can be obtained with the following code:

#!/usr/local/bin/perl
print "HTTP/1.0 200 OK\n";
print "Content-type: image/gif\n\n";
   open GIF,'/user/gruppo_1/zito/zito/WWW/hidden.gif';
   print while <GIF>;

A small script that selects a random file in a directory

#!/usr/local/bin/perl
print "HTTP/1.0 200 OK\n";
print "Content-type: image/gif\n\n";
opendir (HOMEDIR ,"/user/www/data/temp") ||
           die (" Impossibile aprire la directory ");
@files = readdir(HOMEDIR);
closedir(HOMEDIR);
$total = 0;
foreach $file (sort @files) {
         if(substr($file,0,4) eq "temp" && substr($file,14,3) eq "gif"){
         @filename[$total] = $file; $total=$total + 1;}
 }
srand;
$num = int(rand($total));
#   print $filename;

   open (GIF,"/user/www/data/temp/".@filename[$num]);
   print while <GIF>;

Use of associative arrays

One of the most powerful features of Perl are associative arrays. In this small CGI script I use this feature to produce a list of the most popular pages on my server.
  
#!/usr/local/bin/perl
print "HTTP/1.0 200 OK\n";
print "Content-type: text/html\n\n";
$guestbook = "/user/gruppo_1/zito/zito/WWW/java/greetings.log";
open (IN, $guestbook) || die "Can't open $guestbook";
print "<HTML><HEAD>";
print "<TITLE>Most popular documents</TITLE>";
print "</HEAD><BODY bgcolor=white>\n";
print "<center><H2>Most popular documents</H2></center><table border=5>\n";
@content = ;
close (IN);
@content = reverse (@content);
$numvis = @content;
$count = 0;
while($count < $numvis) {
   $entry = @content[$count];
   $line = substr($entry,0,index($entry,"http"));
   if (index($entry,"http") >= 0){
    if (index($entry,"pcba10") > 20 || index($entry,"pcba10") <0 ) {  
    $url = substr($entry,index($entry,"http"));
    $url = substr($url,0,index($url,"\n"));
    $stat{$url} += 1 ;
      }
    }
   $count++;
   }
$count = 0;
foreach $url(keys(%stat)) {
   $pline[$count]= "<tr><td> $stat{$url}\n <td><a href=$url>$url</a>\n";
   $count++;
   }
@pline = sort numer (@pline);
$numlin = @pline;
$count = 0;
while($count < $numlin) {
   print "$pline[$count] \n";
   $count++;
   }
print "</table></BODY></HTML>\n";
sub numer {
 local ($numa, $numb);
 $numa = substr($a,8,index($a,"\n"));
 $numb = substr($b,8,index($b,"\n"));
 $retval = $numb <=> $numa;
 }
 end
Note that the simple instruction %stat{$url} += 1 is enough to set up a counter for each url and increment it.
The statement: foreach $url keys(%stat)) is used afterwards to scan the associative array. I could at this point have printed the url but they are not ordered. For this reason I put them in a normal array @pline and I order them with sort numer(@pline). The subroutine numer is needed since we want to order using the numeric values for the counter instead of its characters.

String handling in Perl

String handling is what makes Perl so powerful but also so difficult to learn.Yes in Perl you have variables where you can put strings of characters.
$sentence = 'Nel mezzo del cammin di nostra vita';
Yes you have the index and substr functions like in other languages,so you can write:
$mezzo = substr($sentence,4,5); or
$initmezzo = index($sentence,"mezzo");
But the powerful string handling is done with the operators =~ and s . To use these operators you have to learn regular expressions and here is most of the problem. Regular expressions are included in / / and indicate pattern to match and replace. A pattern matching is done with the syntax: if ($sentence =~ / /)
A pattern substitution with the syntax:
$sentence =~ s/ / /;
A substitution character by character with the syntax:
$sentence =~ tr/ / /;
For example tr/a-z/A-Z/; will change all lowercase characters to uppercase. Another important thing to know about strings in Perl is that string operators use the predefined variable $_ as default operand. In this case you can write simply: /regexp/ to match/extract a pattern and s/regexp/new/ to replace a pattern.
As an example let's say that in a file we have the line:
Program status PSFLAG =        3.10
We can write the following commands to extract the "3.10" from the file.
$_ = `grep 'PSFLAG =' /user/gruppo_1/zito/temp/temp.lis`;
($psflag) = /([0-9]+.[0-9]+)/;
The round brackets are essential otherwise $psflag will get the number of matches.The round brackets mean in Perl a list in this case of a single variable.
A quick introduction about these maddening regular expressions can be found in this
Perl tutorial.
Also, if you use a Unix machine you can experiment with regular expressions using the egrep program.

Another useful string manipulating function is split. With split you can transform a single string in a vector of strings that contains the pieces obtained cutting at some separator character. As an example, here I get from a complete Unix file specification the name of the file.

            @dirtree = split (/\//,$filename);
            $numdir = @dirtree;
            $filename1 = @dirtree[$numdir - 1 ];

How to avoid that error messages from scripts go to the web page

$temp = "/user/gruppo_1/zito/zito/temp.txt";
open (TEMPFILE,">$temp");
open (STDERR,">&TEMPFILE")  || die ("open STDERR failed");
open (STDOUT,">&TEMPFILE")  || die ("open STDOUT failed");
close (TEMPFILE);
close (STDERR);
close (STDOUT);
All messages to stdout and stderr will go to the file temp.txt

Maintained by Giuseppe Zito: Giuseppe.Zito@ba.infn.it. Last modified: