1

Chapter 14 – Your First Perl Game

-

Chapter 14 – Your First Perl Game

If you’ve been with us this far, you’ve done quite a bit of learning. So let’s take a break and create a Perl game with all that we’ve learned so far!

This is a Guess a Number (GAN) where the computer makes a random number and you have to guess what the number is within a specified number of guesses. This game will record statistics and report back on whether the guess was too high or too low.

This script assumes you have been learning Perl following our class or tutorial and haven’t learned about databases yet. This is why we are saving our data to textfiles instead of a Perl built-in database. Even though this is a complete script, there are some things missing that would make this more stable (such as $guess checking) which we haven’t gone over yet so these features have been excluded.

For this to work, you need to create two text files before running the script. win.txt and lose.txt.

The code (with line numbers):

01: #!/usr/bin/perl
02:
03: use warnings;
04: use strict;
05:
06: my $guess;
07: my $tries = 0;
08: my $allowed = 5;
09:
10: print “what is the max number you want to try for? “;
11: my $max = <STDIN>;
12: chomp($max);
13: my $answer = int(rand($max))+1;
14:
15: while ($tries < $allowed)
16: {
17: print “Your guess: “;
18: $guess = <STDIN>;
19: chomp($guess);
20: $tries++;
21:
22: if ($guess eq $answer)
23: {
24: last;
25: }
26: elsif ($guess > $answer)
27: {
28: print “\t$guess is too high\n”;
29: }
30: elsif ($guess < $answer)
31: {
32: print “\t$guess is too low\n”;
33: }
34: }
35:
36: if ($guess eq $answer)
37: {
38: print “\nYou got it right!\n”;
39: print “It only took you $tries tries to do it!\n”;
40:
41: open(FILE, “win.txt”) or die “error opening win.txt: $!”;
42: my $stats = <FILE>;
43: close(FILE);
44:
45: $stats++;
46:
47: open(FILE, “> win.txt”) or die “error opening win.txt: $!”;
48: print FILE “$stats”;
49: close(FILE);
50: }
51: else
52: {
53: print “\nYou lose! You’re only allowed $allowed guesses :( \n”;
54: print “Answer was $answer\n”;
55:
56: open(FILE, “lose.txt”) or die “error opening lose.txt: $!”;
57: my $stats = <FILE>;
58: close(FILE);
59:
60: $stats++;
61:
62: open(FILE, “> lose.txt”) or die “error opening lose.txt: $!”;
63: print FILE “$stats”;
64: close(FILE);
65: }
66:
67: open(FILE, “win.txt”) or die “error opening win.txt: $!”;
68: my $wins = <FILE>;
69: close(FILE);
70:
71: open(FILE, “lose.txt”) or die “error opening lose.txt: $!”;
72: my $losses = <FILE>;
73: close(FILE);
74:
75: print “You won $wins and lost $losses”;

Line by line Explanation

line (1-4)
Setting up our script and turning on warnings and strict to help us debug in the off-chance something goes terribly wrong.
line (6-8)
The script we make requires a few variables to be set up. $guess is the guess that you or the user will type in to try to guess the number right. $tries is set at 0 as this variable will count how many “guesses” you took. $allowed is the max number of guesses you want the script to allow before the player loses.
line (10-12)
We print a question to the player on the max number the computer should create a random number for. Ie, if it’s 50 the computer will make a random number no greater than 50 that the player has to guess. You are storing the max number in $max and then chomping it.
line (13)
This is something new to you. We are creating a random integer (number) given the max number the player specified. If you don’t understand this, that’s fine. Just copy and paste the line for now.
line (15-16)
Our main while loop is initiated. This loop will continue to prompt for more guesses UNTIL the condition is no longer true. This means once the guess count equals the max allowed it’ll exit the loop.
line (17-19)
We are inside our loop now so we must ask the user for input and save it to our $guess variable. With all input from the command line, we must chomp() it for the data to be exactly what we need.
line (20)
While in the while() loop we need to auto increment the $tries variable we set to 0 earlier. This way we know exactly how many guesses they took and we can make the program hault when they guesses too many. Each time through the loop that they guess incorrectly, we add 1 to the $tries number.
line (22-33)
After each guess we have to use an if/elsif/else iteration to see whether or not the guess was right AND if it was wrong, check to see if the guess was too high or too low. If the number guessed was correct, we apply a last; to tell the script to exit the while() loop we created earlier because there’s no point to loop again if they have it right. If the answer is wrong, it’ll print to the screen whether the guess was too high or too low and will continue back to the top of the loop.
line (34)
All of our loop is done. They either guessed it right or they ran out of guesses so all we do here is close the bracket } on our while() loop we created earlier.
line (36-39)
We are out of our while loop and now we must check one last time whether they guessed the answer right or they ran out of guesses. If this if() is activated, they guessed it right and it prints out a little message saying they won!
line (41-49)
Because we are going to be storing our statistics to file (since we haven’t learned databases at this point), we need to open our win.txt file for reading and save the contents to our variable. After we get the count that we had saved, we need to auto increment our variable $stats++ because the player beat the game. We then close the filehandle and open the file again for writing. After we open the win.txt file the second time, all we do is print our new statistics to file and close the filehandle FILE.
line (51-65)
This is identical to the last section except this will be executed only if the player ran out of guessed and didn’t get the answer right. We print out a message saying they lost and then we have to open the lose.txt file for reading and then open it for writing. Just like we did for lines 41-49.
line (67-75)
The game is now over. The player either one or lost by this point. We are going to open both the win.txt and the lose.txt file and save the current number for each of them to file. We are doing this so we can print out how many times, in total, the player won or lost this GAN game you just made.

Complete script (without lines) for copying and pasting

#!/usr/bin/perl

use warnings;
use strict;

my $guess;
my $tries = 0;
my $allowed = 5;

print “what is the max number you want to try for? “;
my $max = <STDIN>;
chomp($max);
my $answer = int(rand($max))+1;

while ($tries < $allowed)
{
print “Your guess: “;
$guess = <STDIN>;
chomp($guess);
$tries++;

if ($guess eq $answer)
{
last;
}
elsif ($guess > $answer)
{
print “\t$guess is too high\n”;
}
elsif ($guess < $answer)
{
print “\t$guess is too low\n”;
}
}

if ($guess eq $answer)
{
print “\nYou got it right!\n”;
print “It only took you $tries tries to do it!\n”;

open(FILE, “win.txt”) or die “error opening win.txt: $!”;
my $stats = <FILE>;
close(FILE);

$stats++;

open(FILE, “> win.txt”) or die “error opening win.txt: $!”;
print FILE “$stats”;
close(FILE);
}
else
{
print “\nYou lose! You’re only allowed $allowed guesses :( \n”;
print “Answer was $answer\n”;

open(FILE, “lose.txt”) or die “error opening lose.txt: $!”;
my $stats = <FILE>;
close(FILE);

$stats++;

open(FILE, “> lose.txt”) or die “error opening lose.txt: $!”;
print FILE “$stats”;
close(FILE);
}

open(FILE, “win.txt”) or die “error opening win.txt: $!”;
my $wins = <FILE>;
close(FILE);

open(FILE, “lose.txt”) or die “error opening lose.txt: $!”;
my $losses = <FILE>;
close(FILE);

print “You won $wins and lost $losses”;

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: -1 (from 1 vote)
1

Chapter 13 – Perl Example Login Script

-

Chapter 13 – Perl Example Login Script

In the past few lessons you learned about Perl and the various datatypes. You learned scalars, arrays and hashes. It is a lot to learn and unless you make a practical script that utilizes these variables and the techniques you learned, it’ll make learning and memorizing their appearance and functions very difficult.

In this lesson you will be learning how to create a password script that you can run from your command prompt. This example shows examples on scalars, arrays AND hashes so you can see how they work in the real world.

This script was written as simple as possible trying to only cover functions you have already learned about. There may be a few new things you come across, so if you have questions be sure to read the step-by-step followup.

This login script will loop until you log in successfully. It will prompt for a username and password and when successful, it will print a to do list.

The code (with line numbers):

01: #!/usr/bin/perl
02:
03: use warnings;
04: use strict;
05:
06: my %logins = (“name1″ => “pass1″, “name2″ => “pass2″);
07: my @to_do_list = (“walk the dog”, “paint the house”, “walk to the store and get some pop”, “walk on the moon”);
08:
09: while (1)
10: {
11: print “Enter your login name:”;
12: my $name = <STDIN>;
13: chomp($name);
14:
15: if (exists $logins{$name})
16: {
17: print “\nwhat is the password?”;
18: my $pass = <STDIN>;
19: chomp($pass);
20:
21: my $password = $logins{$name};
22:
23: if ($pass eq $password)
24: {
25: print “You have logged in successfully\n\n”;
26:
27: foreach my $list (@to_do_list)
28: {
29: print “$list\n”;
30: }
31:
32: exit;
33: }
34: else
35: {
36: print “Your login information was incorrect.\n”;
37: }
38: }
39: else
40: {
41: print “Username was not found in our system\n”;
42: }
43: }

Line by line Explanation:

lines (1-4)
Setting up our script and turning on warnings and strict to help us debug in the off-chance something goes terribly wrong.
lines (6-7)
We are setting up our hash of usernames and passwords for the login process and our list of to-do items which will print out after you are logged in.
lines (9-10 & 43)
Since this is a login script, we probably want to loop continuously if they don’t input the write username or password. Otherwise you’d have to start the script again each time you make a mistake. The while(1) loop loops over the ENTIRE script which is why it’s there before we prompt for user input.
line (11-13)
We are printing a message to the user that we want their username. On line 12 we are using <STDIN> which means the script will pause and await for the user to type something in and then press enter. STDIN means Standard Input. Because you click enter, we need to remove the /n character that comes with the input in like 13 by chomping it off. The input is stored in our variable $name.
line (15-16)
After prompting for their username we need to check their input with what we have stored in our hash %logins that we made earlier. We check this using an if() by checking to see if the name they entered exists by if (exists $logins{$name}).
line (17-19)
We are still in the open brace of our if() statement from line 15 which means everything within these braces WILL be executed if the user inputs a name that exists in our hash. If they are here, they got the name right so we’re asking for their password this time and prompt for more input. Again we must chomp() our variable to remove the newline feed that will be added to the end of the input.
line (21)
We are still in the open brace we were in the last few lines so this is still getting executed if they used the right name. On this line we are making a new variable $password and we’re assigning it to the key of our hash ($logins{$name}) which actually stores the value into our new variable. To get the value of any hash key, all you do is assign a $var = $hashname{“keyname”}; and the $var will hold your data. We are saving this in a variable so we can compare the password the user types in to the password we have on file.
line (23-24)
We are STILL in the open brace from before.. Here we are doing another if() test based on their password this time. We are checking to see if the $pass they entered is the same $password we have on file. eq means equal; we are checking to see if $pass is equal to $password. If it is, the first set of brackets will be executed. If it’s wrong, the second set will.
lines (25)
This is the first bracket which means the password the entered was right for the username they signed in as. Since this is all right, we print them a message letting them know they signed in!
line (27-30)
We created an array (list) of things to do near the top of the script. This list is supposed to be password protected so only YOU could login and see it. And since on lines 23-24 you were authenticated and on line 25 you were told you logged in, we are going to print out the list. Remember, to print @arrays we use a foreach() loop on the array name: foreach(@arrayname). You can assign a loop variable like we did with $list so each iteration through the loop, the array element is stored in $list so we can print it out.
lines (32)
We logged in successfully and printed out our list. Since we are in a while(1) loop, the loop will continue forever continuously until you tell it otherwise. For this reason, we are adding an exit; to make the program stop after we are done.
line (34-37)
We stopped the if() loop we created for the password checking. Now begins the second section of else() which is executed when our test fails. This means the password the user entered was wrong. All we do with the else() is print a friendly message letting them know they failed to sign in with the right credentials.
line (39-42)
Similar to lines 34-37. This else() block is executed if the user typed in a username that did not exist in our hash (from when we prompted them quite a few lines earlier). All we are doing here is printing them a message letting them know their login failed.
line (43)
We close the while(1) loop. Just because we close it, it doesn’t mean it tells the loop to stop. We have to close all open braces. This loop will continue until YOU tell it to.

Complete script (without lines) for copying and pasting:

code#!/usr/bin/perl

use warnings;
use strict;

my %logins = (“name1″ => “pass1″, “name2″ => “pass2″);
my @to_do_list = (“walk the dog”, “paint the house”, “walk to the store and get some pop”, “walk on the moon”);

while (1)
{
print “Enter your login name:”;
my $name = <STDIN>;
chomp($name);

if (exists $logins{$name})
{
print “\nwhat is the password?”;
my $pass = <STDIN>;
chomp($pass);

my $password = $logins{$name};

if ($pass eq $password)
{
print “You have logged in successfully\n\n”;

foreach my $list (@to_do_list)
{
print “$list\n”;
}

exit;
}
else
{
print “Your login information was incorrect.\n”;
}
}
else
{
print “Username was not found in our system\n”;
}
}

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)
0

Chapter 12 – Creating A Perl Form Part 2

-

Chapter 12 – Creating A Perl Form Part 2

In this article we will be improving our mailing form we made last week by adding a few new features. Our form worked in that last tutorial but there wasn’t any field checking to see if items were filled in.

One of the other things we will be doing is printing out header and footer files to keep pages in our template.

The code (with line numbers):

001) #!/usr/bin/perl
002)
003) use warnings;
004) use strict;
005)
006) use CGI qw/:standard/;
007) use CGI::Carp ‘fatalsToBrowser’;
008)
009) ########
010) my $admin_mail = “sulfericacid\@qwest.net”;
011) my $subject = “Someone used your form!”;
012) my $sendmail = “/usr/lib/sendmail”;
013) my $header = “header.txt”;
014) my $footer = “footer.txt”;
015) ########
016)
017) print header, start_html(“contact form”);
018) my $submit = param(‘submit’);
019)
020) open(HEADER, “< $header”) or die “Cannot open file header.txt for reading: $!”;
021) while(<HEADER>)
021) {
022) print “$_\n”;
023) }
024) close(HEADER);
025)
026) if ($submit ne “”)
027) {
028)
029) #######
030) # setup dynamic variables
031) #######
032) my $name = param(‘name’);
033) my $email = param(‘email’);
034) my $message = param(‘message’);
035) my $time = localtime();
036) #######
037)
038) if ($name eq “”)
039) {
040) print “<font color=red><center>You must fill in your name.</center></font>”;
041) print “<center>Please click your back button to continue”;
042) exit;
043) }
044)
045) if ($email !~ m/@/)
046) {
047) print “<font color=red><center>You must fill in your email address.</center></font>”;
048) print “<center>Please click your back button to continue”;
049) exit;
050) }
051)
052) if ($message eq “”)
053) {
054) print “<font color=red><center>You must fill in your message.</center></font>”;
055) print “<center>Please click your back button to continue”;
056) exit;
057) }
058)
059) open (MAIL, “| $sendmail -t”) or die “Error opening sendmail: $!”;
060) print MAIL “To: $admin_mail\n”; # required
061) print MAIL “From: $email\n”; # required
062) print MAIL “Subject: $subject\n\n”; # required
063)
064) print MAIL “Name: $name\n”;
065) print MAIL “E-mail: $email\n”;
066) print MAIL “Message: $message\n”;
067) print MAIL “\n\nThis message was sent by $ENV{‘REMOTE_ADDR’} on $time”;
068) close(MAIL) or die “Error closing sendmail: $!”;
069)
070) print “<center><b>Your message has been sent! Thank you.</b>”;
071)
072) }
073)
074)
075)
076) print <<”FORM”;
077) <form method=”POST” action=”">
078) <table width=”307″ border=”0″ cellspacing=”0″>
079) <tr>
080) <td width=”69″><div align=”right”>Name:</div></td>
081) <td width=”234″><input type=”text” name=”name” size=”50″></td>
082) </tr>
083) <tr>
084) <td><div align=”right”>Email:</div></td>
085) <td><input type=”text” name=”email” size=”50″></td>
086) </tr>
087) <tr>
088) <td><div align=”right”>Message:</div></td>
089) <td><textarea name=”message” cols=”43″></textarea></td>
090) </tr>
091) <tr>
092) <td colspan=”2″><div align=”center”>
093) <input type=”submit” name=”submit” value=”submit”>
094) </div></td>
095) </tr>
097) </table>
098) </form>
099)
100) FORM
101)
102) open(FOOTER, “< $footer”) or die “Cannot open file footer.txt for reading: $!”;
103) while(<HEADER>)
104) {
105) print “$_\n”;
106) }
107) close(FOOTER);
108)

Line by line Explanation (new colored lines)

lines (13-14)
Setting up two variables for two text files. These two files will be used to create a template for
our script so it fits in our site layout. Since our text files are within the same folder as our form
script, we just use file.txt. If they were in a different folder, you’d have to put the file path in
there. An example would be: /home/username/public_html/header.txt.
line (20)
Using the first of the two new variables we created. We are opening $header (header.txt) for
reading. We are creating the filehandle HEADER as we don’t edit the file directly, we edit the
file in memory and it transfers when we close the file handle.
lines (21-23)
Our filehandle HEADER is open, to print the contents line-by-line into our script (to make the
layout around the mailing form) we place our print in a while loop. A while loop will continue
until there is nothing left, in this case it’ll print every line until there’s no line left for it to find.
line (24)
It saves us headaches down the road if we close our filehandles the minute we’re done with
them. The longer you keep them open the better chance you have of accidently editing the
contents of it. We printed all that we had in HEADER, so we’re closing it.
line (35)
We are making a new variable $time with the system built-in function localtime(). This tells us
when the script was executed.
lines (38-43)
The first version of our script sent out an email no matter if the user filled in all three text fields
or if they filled in zero of them. We are checking $name against “” (which is an empty
comparison) to see if it was filled in.

If the $name field was blank, we print a few messages telling them what they forgot then we
exit;. Exit slaps Perl in the face and makes it quit the script regardless of what it was doing at
the time.
lines (45-50)
The email field is one of the most difficult things to check against, there actually isn’t a sure
way to do this without sending an email to the address they posted requiring authentication
the account is alive.

This is the most simplistic way (definitely not near one of the better choices, but it’s a learning
tool) is to test $email to see if it contains a @ sign. All email addresses have one in it, so if
what they submitted doesn’t have one, we know they’re lying or very forgetful.

If this doesn’t suit you, pull out the regexes ladies and gentlemen and create a nice hack.
lines (52-57)
Exactly the same as lines 45-50, we are testing to see if they included something in the
message. If not, we exit the program after complaining to them.
line (67)
There are a few built in variables we can include in our mailing script. Two of the more useful
ones are the user’s IP address and the time they sent the email. The IP address of the script
user is stored in $ENV{‘REMOTE_ADDR’}.

If you want to see the full list of %ENV variables, use a foreach loop and print them out. You
can find out a lot of information from your users this way.

$time is calculated by localtime() we defined earlier in the script..
lines (102-107)
Identical to what we did with the header.txt file earlier. We are printing out our footer.txt
($footer) which contains the rest of our HTML code for our layout.
Complete script (without lines) for copying and pasting

#!/usr/bin/perl

use warnings;
use strict;

use CGI qw/:standard/;
use CGI::Carp ‘fatalsToBrowser’;

########
my $admin_mail = “your\@email.com”;
my $subject = “Someone used your form!”;
my $sendmail = “/usr/lib/sendmail”;
my $header = “header.txt”;
my $footer = “footer.txt”;
########

print header, start_html(“contact form”);
my $submit = param(‘submit’);

open(HEADER, “< $header”) or die “Cannot open file header.txt for reading: $!”;
while(<HEADER>)
{
print “$_\n”;
}
close(HEADER);
if ($submit ne “”)
{
#######
# setup dynamic variables
#######
my $name = param(‘name’);
my $email = param(‘email’);
my $message = param(‘message’);
my $time = localtime();
#######

if ($name eq “”)
{
print “<font color=red><center>You must fill in your name.</center></font>”;
print “<center>Please click your back button to continue”;
exit;
}

if ($email !~ m/@/)
{
print “<font color=red><center>You must fill in your email address.</center></font>”;
print “<center>Please click your back button to continue”;
exit;
}

if ($message eq “”)
{
print “<font color=red><center>You must fill in your message.</center></font>”;
print “<center>Please click your back button to continue”;
exit;
}

open (MAIL, “| $sendmail -t”) or die “Error opening sendmail: $!”;
print MAIL “To: $admin_mail\n”; # required
print MAIL “From: $email\n”; # required
print MAIL “Subject: $subject\n\n”; # required

print MAIL “Name: $name\n”;
print MAIL “E-mail: $email\n”;
print MAIL “Message: $message\n”;
print MAIL “\n\nThis message was sent by $ENV{‘REMOTE_ADDR’} on $time”;
close(MAIL) or die “Error closing sendmail: $!”;

print “<center><b>Your message has been sent! Thank you.</b>”;

}
print <<”FORM”;
<form method=”POST” action=”">
<table width=”307″ border=”0″ cellspacing=”0″>
<tr>
<td width=”69″><div align=”right”>Name:</div></td>
<td width=”234″><input type=”text” name=”name” size=”50″></td>
</tr>
<tr>
<td><div align=”right”>Email:</div></td>
<td><input type=”text” name=”email” size=”50″></td>
</tr>
<tr>
<td><div align=”right”>Message:</div></td>
<td><textarea name=”message” cols=”43″></textarea></td>
</tr>
<tr>
<td colspan=”2″><div align=”center”>
<input type=”submit” name=”submit” value=”submit”>
</div></td>
</tr>
</table>
</form>

FORM
open(FOOTER, “< $footer”) or die “Cannot open file footer.txt for reading: $!”;
while(<HEADER>)
{
print “$_\n”;
}
close(FOOTER);

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)
0

Chapter 11 – Creating a Perl Form Part 1

-

Chapter 11 – Creating A Perl Form Part 1

In this article we’ll be creating a very simplistic contact form. We all know what contact forms are, but now that we’ve learned a bit of Perl, it’s time to put projects together and make physical scripts you can use.

This contact form is setup and tested for accuracy, this does work on this server and with very minor alterations it will work on yours as well. This is as basic as it gets, there is minimal error checking and features because this will be a growing project for us.

We will continue to build on this form to make it more stable, visually pleasing and to add more features.

The code (with line numbers):

01) #!/usr/bin/perl
02)
03) use warnings;
04) use strict;
05) use CGI qw/:standard/;
06) use CGI::Carp ‘fatalsToBrowser’;
07)
08) ########
09) my $admin_mail = “you\@email.com”;
10) my $subject = “Someone used your form!”;
11) my $sendmail = “/usr/lib/sendmail”;
12) ########
13)
14) print header, start_html(“contact form”);
15) my $submit = param(‘submit’);
16)
17) if ($submit ne “”)
18) {
19)
20) #######
21) # setup dynamic variables
22) #######
23) my $name = param(‘name’);
24) my $email = param(‘email’);
25) my $message = param(‘message’);
26) #######
27)
28) open (MAIL, “| $sendmail -t”) or die “Error opening sendmail: $!”;
29) print MAIL “To: $admin_mail\n”; # required
30) print MAIL “From: $email\n”; # required
31) print MAIL “Subject: $subject\n\n”; # required
32)
33) print MAIL “Name: $name\n”;
34) print MAIL “Message: $message\n”;
35) close(MAIL) or die “Error closing sendmail: $!”;
36)
37) print “Your message has been sent! Care to send another?”;
38)
39) }
40)
41)
42) print <<”FORM”;
43)
44) <form method=”POST” action=”">
45) <table width=”307″ border=”0″ cellspacing=”0″>
46) <tr>
47) <td width=”69″><div align=”right”>Name:</div></td>
48) <td width=”234″><input type=”text” name=”name” size=”50″></td>
49) </tr>
50) <tr>
51) <td><div align=”right”>Email:</div></td>
52) <td><input type=”text” name=”email” size=”50″></td>
53) </tr>
54) <tr>
55) <td><div align=”right”>Message:</div></td>
56) <td><textarea name=”message” cols=”43″></textarea></td>
57) </tr>
58) <tr>
59) <td colspan=”2″><div align=”center”>
60) <input type=”submit” name=”submit” value=”submit”>
61) </div></td>
62) </tr>
63) </table>
64) </form>
65)
66) FORM
67)

Line by line Explanation:

lines (1-4)
Setting up our script and turning on warnings and strict to help us debug in the off-chance something goes terribly wrong.
lines (5-6)
To make this into a CGI script, we use the CGI module. We also turn on fatalsToBrowser
which is another debugging aid that works specifically for CGI. This line should be removed
after the design and implementation of the script, but use these often to help troubleshoot problems.
lines (9-10)
Here we are setting up the static variables for the form. We are setting our the administrator’s email address and the subject of the email we want displayed.

The email address needs to have the escape character \ before the @ sign. This is because
the @ is actually used by the array variable. And to prevent this from happening, we escape
it and treat the @ character as text.
line (9)
We are setting up another variable, this time with the location of sendmail on our server. This location can differ from server to server but this is the one that’s used the majority of the time. Sendmail is one of many Perl modules to email data.
line (14)
We are printing out the HTTP headers. Before we can print any information to our web
site, we need to print the headers. start_html(”) is the title of the page by default.
line (15)
We are making a variable with the contents from the form paramaters. my $var =
param(“FORM_FIELD_NAME”); is how we take the information from our textlines, text
areas, check boxes, etc. The name of our form field is the name of our param(“”); and we
store this into our variable so we can use it.

If you look at the HTML source for our form, you’ll see that our form submit button is
named submit so this is the value we are storing in $submit.
line (17)
This line is testing our variable for existence. Literally, it is checking to see if our variable
does not equal an empty string (or a false value). If $submit (which is the value of our form)
has a value– which means it was pressed– then the code in the braces will be executed.
line (18)
This is the beginning of our execution block for line 17. If our test on line 17 comes back
true, everything starting from this line until line 39 will be executed.
lines (23-25)
We are creating more variables from our form fields. Our HTML form has three user-defined
fields: name, email address and message. We are storing these parameters into these three
variables.
line (28)
We are opening up the sendmail module and storing it in our filehandle MAIL. We are
using taint mode -t because it helps the security a little.
lines (29-34)
Here we are printing our information to our filehandle. This is where our email message
actually comes from. To send an email you need a TO:, FROM: and SUBJECT: field. You
need to add a \n to the end of these fields (the SUBJECT field requires 2 \n\n).

The other fields are always optional, but you might want some information to send, right? :)
So we are also printing the name and message from the user. These optional fields do not
require you to use a description and a colon (Ie. Name: ), everything here on out is printed as
text and will be seen in your email. You could use print MAIL “$name”; if you wanted.
lines (35-37)
We are done printing our information to our filehandle so we close it. At this time our email
is sent (or in the process of being sent). Line 37 is just a message to let them know the
contact form did something.
line (39)
We are done with our emailing, so we close the brace we started on line 18. Everything
following this will be executed each time the script is run.
line (42)
This is a heredoc. This is how you print multiple lines of code with a single print statement,
we could use print “”; line by line but using a heredoc saves our fingers and our sanity.
This will print everything as text (with the exception of scalars which retain their values) until
it reaches the line you started.

Our heredoc starts with the word FORM, to end a heredoc you need to enclose the word
FORM on it’s own line without trailing spaces. You also need a blank line underneath it.
lines (43-64)
This is our entire HTML source code for the form. You can add an entire page of source
code here if you want to spaz it up a little bit. One thing you need to make sure to do, when
you are setting up your HTML form field names, be sure you set up the variables for them
earlier in the script.
lines (66-67)
Our heredoc is ended because it reaches FORM. Line 67 is a not option, you need a new
line under the closing line of a heredoc.

Complete script (without lines) for copying and pasting

#!/usr/bin/perl

use warnings;
use strict;

use CGI qw/:standard/;
use CGI::Carp ‘fatalsToBrowser’;

########
my $admin_mail = “you\@email.com”;
my $subject = “Someone used your form!”;
my $sendmail = “/usr/lib/sendmail”;
########

print header, start_html(“contact form”);
my $submit = param(‘submit’);

if ($submit ne “”)
{

#######
# setup dynamic variables
#######
my $name = param(‘name’);
my $email = param(‘email’);
my $message = param(‘message’);
#######

open (MAIL, “| $sendmail -t”) or die “Error opening sendmail: $!”;
print MAIL “To: $admin_mail\n”; # required
print MAIL “From: $email\n”; # required
print MAIL “Subject: $subject\n\n”; # required

print MAIL “Name: $name\n”;
print MAIL “Message: $message\n”;
close(MAIL) or die “Error closing sendmail: $!”;

print “Your message has been sent! Care to send another?”;

}
print <<”FORM”;
<form method=”POST” action=”">
<table width=”307″ border=”0″ cellspacing=”0″>
<tr>
<td width=”69″><div align=”right”>Name:</div></td>
<td width=”234″><input type=”text” name=”name” size=”50″></td>
</tr>
<tr>
<td><div align=”right”>Email:</div></td>
<td><input type=”text” name=”email” size=”50″></td>
</tr>
<tr>
<td><div align=”right”>Message:</div></td>
<td><textarea name=”message” cols=”43″></textarea></td>
</tr>
<tr>
<td colspan=”2″><div align=”center”>
<input type=”submit” name=”submit” value=”submit”>
</div></td>
</tr>
</table>
</form>

FORM

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)
0

Chapter 10 – Perl Filehandling

-

Chapter 10 – Perl Filehandling

Sooner or later you’ll want the ability to read, write, set permissions, search or many other options to or from files. Working with files makes data storage and retrieval a simple yet powerful task, especially for projects that don’t require full blown databases.

If you have been reading the tutorials from the beginning, you’ll have come across on at least on occasion of us opening a file for both reading and writing. This is the partial outline for this tutorial but it will be broaden to include all aspects of file handling.


Opening a file for reading:

One of the most powerful and fundamental tools in Perl is the ability to open a file and read the contents into the script for processing.

open (FILEHANDLE, “file.txt”);

When reading or writing a file, it is important to know that the file contents are stored into the scripts memory. Once the information is in the filehandle, you can call back on the filehandle as often as you want for either reading OR writing. You know longer have direct access to the file, you slurp the contents or write the contents to the filehandle, the filehandle either has the information to read or it has the information to write back to it.

FILEHANDLE can be nearly anything you want, most programmers prefer to type these in all caps to prevent confusion and these should start with a letter.

open (DATA, “file.txt”);

This is the same as the above, only difference is we are storing the contents of file.txt inside the filehandle DATA.

open (DATA, “file.txt”) or die “an error occured: $!”;

By default, if you attempt to open a file that cannot be opened (if the permissions were set improperly, the file doesn’t exist, etc), you will not be informed of this problem. Your script will appear to be running properly but the information you attempted to read or write will have undesirable results. or die will force the script to crash if for any reason the file you are trying to access is not available or functioning properly. $! is Perl’s built-in error variable, if the script dies the last error before it terminated will be stored in this variable.

If file.txt did not exist, you may get an error: “an error occurred: file does not exist” which is very helpful information in figuring out the source of the problem. You always want to include this sanity check when opening a file.

To print the entire slurped contents of your file, you could use a while loop on the file handle which will continue to print everything line-for-line until it reaches the EOF. Remember, while loops will continue until EOF or until something forces it to return a non-true value.

while(<FILEHANDLE>)
{
  print “$_\n”;
}


File Attributes

This is the chart of the different attributes you may use while opening a file.

FILE SETTINGS
—————————————-

< file READ
> file WRITE, CREATE, TRUNCATE
>>file WRITE, APPEND, CREATE
+< file READ, WRITE
+> file READ, WRITE, TRUNCATE, CREATE
+>> file READ, WRITE, CREATE, APPEND, CREATE


Closing a file:

All opened files close in order of opening at the end of your script automatically but it’s safer if you close the filehandles when you’re done using them. If you are done with them, close them to prevent any accidental file changes later on. If you happen to open three of them and not choose to close any of them, you may accidentally overwrite the contents.

close(FILEHANDLE);

You close the file by closing the filehandle you named when you originally opened it. A common practice is to also catch errors if the filehandle fails to close for some unforeseen language. This is done using the same method as above.

close(FILEHANDLE) or die “an error occurred while trying to close the file: $!”;


Opening a file for writing:

We know how to read the contents of a file, now it’s time to learn how we can store our information into one. The syntax between opening for reading and writing are virtually the same, the only difference is the mode.

open(FILEHANDLE, “>file.txt”) or die “cannot open file for reading: $!”;

The mode is the character prepended to the file name, in this case it’s “>”. This tells Perl we want to open the file for writing, not for reading.

Writing to a filehandle is much like printing text to your screen on web site. We do this using the print() method but when writing to a filehandle, we need to specify that’s what we want to do.

open(FILEHANDLE, “>file.txt”) or die “cannot open file for reading: $!”;
print FILEHANDLE “I love goldfishes, they’re so delicious!”;

We are specifically telling it to write our sentence to the FILEHANDLE instead of printing it to screen. file.txt now contains the phrase “I love goldfishes, they’re so delicious!.

You can print anything you want to a filehandle: text, variables, lists, you name it!

print FILEHANDLE “$name”;
print FILEHANDLE @list;
print FILEHANDLE %hash;

If we defined these variables, we could print them each to file. The array and hash are not embedded in quotes as to not interpolate them.

If you print like we did above, all the content will be on the same line (or rather, it will be multi-line but without separators between the data). This means if we had

my $cat = “meow”;
my $dog = “purrr”;

open(FILEHANDLE, “>file.txt”) or die “cannot open file for reading: $!”;
print FILEHANDLE “$cat”;
print FILEHANDLE “$dog”;

Our results would be on one line: “meowpurrr”. Typically when writing to a file, we want to include line breaks so we know where new pieces of information begin. Tack on a new line feed \n to the prints and it will break the content for you.

my $cat = “meow”;
my $dog = “purrr”;

open(FILEHANDLE, “>file.txt”) or die “cannot open file for reading: $!”;
print FILEHANDLE “$cat\n”;
print FILEHANDLE “$dog\n”;

meow
purr

Remember, as we did when opening the file, we should close the filehandle when we are done writing data to it.

close(FILEHANDLE);

Binmode

Writing to a file doesn’t necessarily mean text or strings, you can write to files in binary format. When trying to write an image, a sound file or an executable, you’ll need to write it in binary because some systems will translate all newline feeds \n into carriage returns /r/n.

To prevent some systems from automatically rewriting this, we use binmode.

binmode FILEHANDLE;

Binmode may take a second argument DISCIPLINE. DISCIPLINE is used to set the mode; either :raw for binary or :crlf. If the discipline is not found, by default it will write as binary.

binmode FILEHANDLE, DISCIPLINE;

binmode FILEHANDLE, :raw; # this is for binary files

binmode FILEHANDLE, :crlf; # this is for text files

Please do not use the first set of these three and literally reads DISCIPLINE, this was merely to show you where you set the mode, this is not the actual code for you to use.

We switch on binmode after we open the filehandle but before we do anything else. Let’s say we are opening a file to write a string to it but we wanted to convert it to binary first..

open(FILEHANDLE, “>text.dat”) or die “an error occured: $!”;
binmode FILEHANDLE;
print “Hello there, aliens from Earth!”;
close(FILEHANDLE);


Buffering

When printing something to screen, it is first stored into a buffer. A buffer will not print the information until the buffer is filled with information. In some cases, we do not want to rely on the buffer and we want our data to print as it comes up– no more waiting for the buffer to get filled.

This is very useful when you have a lot of individual processing that needs to be completed and output displayed each step along the way. An example where I’ve used anti-buffering was when I created the Link Checker tool.

It scans complete chunks of code from the url’s it’s given and then prints a message for each process. This has a large overhead and if I kept the buffering at default, parts of the program would hang until there was enough information to satisfy it.

$| = 1;

$| is among many of the other built-in functions. If this is set to any non-zero (literally means if this is true) value it will turn off buffering.


Retrieving by characters:

We know how to read and write files, are there any other neat tricks for us to use? There certainly is! One of them is getc. Instead of reading globs of the file at one time (or literally one line of the file at once), we can retrieve the files one character at a time.

We do this using getc, which is short for Get Character.

getc FILEHANDLE;

To retrieve just the very first character in a filehandle, we would do something like this..

open (FILEHANDLE, “< test.txt”) or die “oops: $!”;
my $char = getc FILEHANDLE;
print $char;
close(FILEHANDLE);

If we wanted to read the first X characters of a file, we could use a for loop. The following example will read the first 20 characters of your filehandle and print them to screen.

for ( 1 . . 20)
{
  open (FILEHANDLE, “< test.txt”) or die “oops: $!”;
  my $char = getc FILEHANDLE;
  print $char;
  close(FILEHANDLE);
}

You can also print the entire file until EOF using getc, even though this entirely defeats the purpose of this function, here is an example of how you could do it, not that you should!

open (FILEHANDLE, “< test.txt”) or die “oops: $!”;
while(<FILEHANDLE>)
{
  my $char = getc FILEHANDLE;
  print $char;
}
close(FILEHANDLE);
Seek

Let’s say we have a 30MB text file and there is only a portion of it we want to read. It would be a waste of resources and load time if we loaded the entire file into memory if all we wanted was a few lines.

seek gives us the power to begin reading a file wherever you want, instead of always from the beginning and reading the entire file. If your opening your file for reading creates a large overhead, seek may just be the solution you are looking for.

seek FILEHANDLE, POSITION, OPTION;

Option gives us a little more control over position. The possible attributes are 0– set the new position, 1– set new position plus position, 2– sets position to the end of the file .

Position is the location in the file, in bytes, where you want the next input to begin from. If we wanted to read from the 10th byte until the end of file, we would use..

open (FILEHANDLE, “< test.txt”) or die “oops: $!”;
seek FILEHANDLE, 10, 0;
while(<FILEHANDLE>)
{
  print;
}
close(FILEHANDLE);


Get current location in file

If we wanted to know the location of our last read in the filehandle, we use tell. This will show us the current position in the filehandle if one is specified, if there is no specified filehandle then the last read will be used.

tell FILEHANDLE;

Using the last example from seek, we are reading from the 10th byte. Just to be sure, we will use tell to inform us where we actually are within the filehandle.

open (FILEHANDLE, “< test.txt”) or die “oops: $!”;
seek FILEHANDLE, 10, 0;
print tell FILEHANDLE;
close(FILEHANDLE);

2


File Statistics:

There is so much more information you can find out about a particular file. You can check the size of the file, the time it was last accessed, the owner of the file,etc. This is extremely helpful if you are a system administrator and you need to watch how files are being used or if you build a file management system.

An example from this site that uses a few file statistics is the File Upload Pro which determines the file size in bytes and then recalculates it into larger units of measure if possible.

Chart:
$dev – the file system device number
$ino – inode number
$mode – mode of file
$nlink – counts number of links to file
$uid – the ID of the file’s owner
$gid – the group ID of the file’s owner
$rdev – the device identifier
$size – file size in bytes
$atime - last access time
$mtime - last modification time
$ctime - last change of the mode
$blksize - block size of file
$blocks – number of blocks in a file

stat();

For our first example, we will determine the size of a given file. We are setting our variable $file (which could be any other name) to a filename then setting up all possible file stats.

my $file = “test.txt”;

my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($file);

print $size;

108664

All of the possible file statistics are already inside of these variables. You can pick and choose which of these you are interested in and manipulate/print the information.

Another example, if you wanted to see the owner’s ID of the file, we’d use $gid.

my $file = “test.txt”;

my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($file);

print $uid

0

Feel free to experiment with these other settings to get a feel for what each of them have to say about a file (or file) you’re working with.


Challenges

1) What does the special variable $! do and what is an example of how we would use it?

One possible solution is:
————————————————————————
$! is a built-in variable that holds the last recorded error in a program. If your program errors out and you print $!, you may get an error that helps you debug the program.

An example:
open(FILE, “file.txt”) or die “Oops, we had an error: $!”;
————————————————————————

2) What is a filehandle and what is the purpose behind them?
————————————————————————
A filehandle is the reference to a file. It’s an exact copy of the entire file stored in memory. The purpose behind these is it is much safer for you to read/write to filehandles than the actual files themselves. What you do with your filehandle will not directly affect the file unless you instruct it to.
————————————————————————

3) We want to write to an image file, if we write as usual to the file we will get unexpected results. What must we remember to do?
————————————————————————
When using files to create images, sounds, flash, etc., you need to remember to switch binmode on to tell Perl to write in binary. Failure to do this will make the file you’re writing to inaccessible.
————————————————————————

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)
0

Chapter 9 – Perl Regular Expressions

-

Chapter 9 – Perl Regular Expressions

In the last tutorial, we went over the three regex operators. We also learned what regexes were and why we’d use these in our scripts. This tutorial will be going deeper in the many uses to manipulate our data in any way we wish.

Regular Expressions are a huge topic all on its own, there is no possible way to go over all of them here so you may wish to purchase a book on the topic (yes, complete books are dedicated to these) for future reading and understanding.

We’ll use the same originally example on a basic regex before we continue.

while (<STDIN>)
{
  if(m/exit/)
  {
    exit;
  }
}
Special Characters

Before we begin, there are many special characters we need to be aware of. Please note the backslash \ preceding the character(s) is not optional and everything is case-sensitive.

\077 octal character
\a internal alarm
\c[ control character
\D match a non-digit characte
\d match a digit character
\E end case modifier
\e escape key
\f form feed character
\L lowercase all characters until the end case modifier \E is found
\l lowercases preceeding character
\n new line feed
\r return
\S matches a non-white space character
\s matches a white space character
\t inserts tab
\U uppercase until the end case modifier \E is found
\u uppercase the next character
\W matches a non-word character
\w matches a word character


Match (nearly) any characters

One of the most useful special characters in regexes is the . (the dot). This matches any and all characters other than the new line \n. This means, all letters a-z, numbers 0-9, dashes - and any weird @$()! character will be matched except the new line feed.

my $sentence = "this is a sentence, woohoo!";
$sentence =~ s/./T/;
print $sentence;

This is a sentence, woohoo!

The . (dot) matches any non-new line character and since we're doing a substitution for "T", the first character it comes across will be replaced with this letter. The "t" was replaced by "T".

If . is a metacharacter,what if we really wanted to match a period in our regex? This comes up very frequently, especially with the period, and lucky for us there is a very quick solution. If you place a backslash in front of the metacharacter, it acts as a normal character instead of being special.

my $sentence = "We have ourselves a .";
$sentence = s/\./period/;
print $sentence;

We have ourselves a period

The only change from the first example and this one to match the period is adding \. to the regex. So instead of matching any character whatsoever, we're literally matching a period and nothing more.

It is easy for us to match all characters at one time as well. We already know the dot matches nearly all characters, so we use that along with the global modifer /g to substitute any and all matches.

my $sentence = "This is a sentence, woohoo!";
$sentence =~ s/./-/g;
print $sentence;


Character Classes

Instead of matching entire words or phrases, we can also match characters. You can set a character class within square brackets [] such as [abc123] and you can set up a range of characters such as [a-zA-Z]. The latter checks to see if any case of any letter appears in our string.

The range operator can work on parts of the alphabet such as c-f or numerics such as 0-9 or 2-5. Remember everything is case sensitive, that’s why we used [a-zA-Z] to match all cases of the letters.

my $string = “We’re off to see the wizard, the most wonderful wizard of all!”;
if ($string =~ m/!/)
{
  print “hey hey now, there’s no reason to shout!”;
}

In our above example, we are testing to see if we can match our explanation point which we can see at the end of the line, it indeed matches. Now lets do a range test that fails. We’ll rewrite $string so it’s all lowercase and see if it contains any uppercase characters.

my $string = “we’re off to see the wizard, the most wonderful wizard of all!”;
if ($string =~ m/[A-Z]/)
{
  print “I wonder if this will print..”;
}

The above example will not print because nothing in our character range exists. Remember, you can check for any letter or number in a range or you can check for any character inside square brackets[].


Multiple chances with matching

You can do multiple tests to see if a variable or string contains this, that or another thing. If you wanted to see if your string had the word “blue” or the color “red”, you don’t have to write to separate regexes to see if it matches. We use the alternative match pattern instead.

Alternative matching matches one or the other, or in some cases another other :) It is not used to test to see if both cases are found, it will stop at the first match it finds and end, whether this be the first possible match or the sixteenth.

while(<STDIN>)
{
  if(m/red|blue/)
  {
  print “these are my fav colors”;
  exit;
  }
}

This will loop endlessly until it finds something that matches either “red” or “blue” literally. “Red” and “bLue” will not match, neither will any of the alternative ways to write these.

You separate each possible match with a pipe |, and you can use a single word, a single character, a sentence, a number or anything else you want to stick inside. This idea is pretty straight forward so we’ll assume the one example will suffice, remember to not just follow the examples written in these tutorials but to make your own and TEST, TEST, TEST!


Negative Matching

Instead of matching a character class, all digits or any a-zA-Z character, we also have the ability to tell it what not to match.

my $string = “hello there, world”;

if ($string =~ m/[^A-Z]/)
{
  print “Oops!”;
}

The above is saying “If the $string does not contain any A-Z characters, print Oops!”. Instead of checking to see if it does contain A-Z characters, we test to see if they aren’t found. This would be particularly useful if you wanted to test a string to see if it contained any non-numbers (if your script required just numeric input): $string =~ m/^0-9];


Quantifiers

Along with simple matching to see if one thing exists or not, we can check to see how many times it exists. Or rather, make sure it matches exactly the number of times we want.

We do this using the quantifiers from the list below:

* : matches zero or more times
+ : matches one or more times
? : matches either one or zero times
{#} : matches a precise number of times
{#,} : matches at least a certain number of times
{#,#} : matches between first number and second number times

In our first example, we will be using the + quantifier to match one or more instances of our test. If it does, we’ll do a simple substitution.

my $quantifier = “The frog goes rrribbit, rrribbit”;
$quantifier =~ s/r+/r/g;

print $quantifier;

results: The frog goes ribbit, ribbit

Since the + quantifier matches only characters or words that exist atleast one, maybe more, times, we replaced all occurrences of more than one “r” consecutively. This would work if you had one “r” or 100,000 of them. As long as it’s more than one, Perl is happy.

In this next example, we are checking to see if the user typed in between 10 and 30 characters.

while(<STDIN>)
{
  if(m/.{10,30}/)
  {
  print “good for you!\n”;
  }
}

Quantifiers are greedy by nature. This means they’ll slurp up the biggest match as they can that follows the match you’re telling it to. So instead of taking the first applicable match, it will take the biggest (in terms of character size) as possible thus occasionally providing unwanted results.

my $quote = “to be or not to be, that is the question”;
$quote =~ s/.*be/To/;
print $quote;

   Results: To, that is the question

What we tried to do was change the first word from “to” to “To” with a capital “T” by substituting any and all characters before “be”. Remember, .* means to match all characters and as we placed the characters “be” after it, we tried to match the first few characters of our sentence.

What really happened was it found a bigger match– instead of substituting the first match of “to”, it matched everything and substituted everything until the word before the comma.

Regex Anchors (assertions)

Often times we need total control over what to match and where. Rather than matching the first match or taking your chance using a quantifier, we can tell our regex to match specific conditions. These conditions include matching at the beginning or end of a string, match word or non-word boundaries, etc.

Here is a chart of the majority of the anchors we can use that will give us the power we need for accurate results and matching.

^ : matches the beginning of the line
$ : matches the end of the line
\A : matches the beginning of the string
\B : matches a non-word boundary
\b : matches a word boundary
\Z : matches the end of the line
\z : matches the end of the line

The \A and \Z are pretty much the same as ^ and $, the main difference is ^ and $ can match once and once only– at the beginning or the end of a string. The \A and \Z can match multiple times for internal boundaries.

Let’s use an example we came across above. We’re trying to see if the user typed exit. This time, we’re making sure exit is the only thing the user typed. This will not match if the user typed “I need an exit” or “exit is that way”.

while (<STDIN>)
{
  if(m/^exit$/)
  {
    exit;
  }
}

We just used two of the anchors we learned from the list we read earlier. ^exit is explicitly telling it to match exit at the beginning of the string. exit$ is telling it to match at the end of the string. In short, by using both the ^ and $ anchors, you are asking it to match if it’s the only word or set of characters (or even a single character) in the string.

If we just wanted to match the beginning of the string, we would have just used the ^ carrot. Likewise with the $ if all we wanted to do was match the end of the string.

Word boundaries are anything separated by a whitespace, just like our every day text. To match a word boundary means to match anything between one whitespace and the next.

VN:F [1.9.22_1171]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)