You can learn Perl now. The language isn't as
hard as people are saying. I will show you how to begin your Perl programming
career, by showing you some examples, and by letting you see how the
language works. I suggest you download a version of Perl for use under
DOS/Windows (ActivePerl), if you run your script with it you can see
if the script has errors...so you don't have to be online all the time.
You can download it for free somewhere on
this
page. You can edit your scripts using a normal text editor, for example
notepad.
This tutorial is written for Perl 5, some
things will not work in older versions!
The first line of your program should always be
something like #!/usr/bin/perl. This may differ if your version
of Perl is located somewhere else. You must always remember that Perl
is CaSe SeNsItIvE, which means that Perl is not thesame as PERL or perl.
The variables in your script are also case-sensitive, and depending
on your server, the filenames can be case-sensitive too.
All the other lines starting with # (the 'shebang') are comments, like
QBasic has REM and '. However, this first line of your script is read
by the system to know which program to call to execute the script.
Now, your first script should be very easy...let's
create a 'hello, world!' example. This script should look like this
(select the text and press CTRL+C to copy it into memory, then go
to your text editor and press CTRL+V to paste):
#!/usr/bin/perl
print "Hello, world!\n";
Now save the file as hello.cgi and try to run it from the DOS Perl
that you just downloaded by typing 'perl hello.cgi'...you will see
a text "Hello, world!" there!
From this first small script you can already learn some things: the
print command prints something to the screen (or browser, if
it is an online script). \n breaks the line, so the next line
that will be printed will appear on a new line. You always put a ;
after commands.
Now, we make an online 'Hello, world' script,
that displays in your browser. To do this, you will first need to
tell the language that it is sending a HTML file to the browser...do
this by typing print "Content-type:text/html\n\n"; (exactly
like that, with 2 \n's). Now save the script again, and start your
FTP client to log in to your homepage. Set it to send as ASCII and
upload your hello.cgi. Next, CHMOD it 755. This changes the file permissions
so you can run the program. You will have to do this every time you
create a new script, if you're re-editing an existing script, the
permissions will remain the same and won't need to be changed again.
CHMOD 755 makes the file readable, writable, and executable (RWX)
for the owner(you), readable and executable for GROUP and OTHER. This
means visitors to your site can run the script.
Now, when that is finished, open your browser and go to the cgi file
by typing in the full address. If everything's right, you will see
the text 'Hello, world!' in your browser window. If not, you must
have done something wrong. Maybe you uploaded your CGI file to another
directory than the cgi-bin and your server can't run CGI files from
there? It sometimes happens...
If it did work, we can continue.
To display a small webpage instead of just a simple text is just easy.
The following code will work:
#!/usr/bin/perl
print "Content-type:text/html\n\n";
print "<html><title>Hello, world!</title>\n";
print "<body>\n";
print "<h2>Hello, world!</h2>\n";
print "</body></html>\n";
That's all that's needed...no additional tags. If you want, you
can try it and upload the file again, just follow the same steps as
above.Ofcourse, this can be done a lot 'cleaner' by removing the multiple
print commands. The following code does thesame thing as the
above code:
print "Content-type:text/html\n\n";
print "<html><title>Hello, world!</title>\n
<body>\n
<h2>Hello, world!</h2>\n
</body></html>\n";
Because the print command uses those ""'s, you will get problems
if you have any HTML code that includes them. But no worries, there
is something to fix that and it is very easy: Just put a \
before it, like this:
print "<A HREF=\"http://www.qb45.com\">\n";
That will make it work!
Probably the cleanest way is like this:
print qq~<A HREF="http://www.qb45.com">\n~;
Now you don't have to worry about any quotes anymore =)
What is a programming language without variables?
Well not much more than some useless trash I think. Ofcourse Perl also
uses variables. So here's an explanation on how to use them!
Small note: There are programming languages that do not use variables.
That is what they call 'functional programming'. Haskell
is an example of that. In functional programming there are no variables,
everything is calculated using functions.
Scalar variables are used to store one value.
There are called like $variable, so $whatever, $x, $y etc. will all
work. Here's how you give them values:
$one = 1;
$name = "Jorden";
$pi = 3.141592;
You can now see that, different from other programming languages,
the scalar ($) variable can hold both numbers AND text. Also, you
don't need a declaration of your variables, just add a line like this
and it will work!
Perl variables can also change from numbers to text or the other way.
Like this:
$age = 17;
$age = "Seventeen ($age).";
Internally Perl can store it as a double, int, float, long, or char.
You can also use arrays. A scalar variable
can only store one value, an array can hold multiple. The array variable
looks like @arrayname. Some example code:
@names = ("Jorden","Rob","Fred");
print "$names[0]\n";
print "$names[1]\n";
print "$names[2]\n";
Ofcourse, there are other ways to do this, easier ways. Just create
some sort of FOR...NEXT loop like in QB, like this:
@names = ("Jorden","Rob","Fred");
foreach $a (@names) {
print "$a\n";
}
I can see that you are already starting to understand more and more
of the language...great isn't it?
Some more array-specific functions:
@names = ("Jorden","Rob","Fred");
$lastname = pop(@names); # returns "Fred", the last value of the array.
$firstname = shift(@names); # returns "Jorden", the first value of
the array.
sort(@names) # sorts the values of @names alphabetically
reverse(@names) # inverts the @names array
$#colors # the length of the @names array
join(", ",@names) # joins @names into a single string, separated by
the expression ", " (you can change that)
To add some code to an array:
push(@names,"Pete"); # adds "Pete" to the end
of the @names array
@names2 = ("Name1","Name2","Name3");
push(@names,@names2); #appends the values in @names2 to the end of
@names.
Note: Sort and reverse
will not work on their own. You can use them like this:
foreach $a (sort @names) { print "$a\n";}
There is another type of variables , hashes
(%). Hashes also are arrays.
Because you probably are using a DOS Perl version,
you can't get input from the browser, for example by filling in a
form. To test functions offline, just use something like this:
#!/usr/bin/perl
$homepagetitle = "Perl programming tutorial";
print "Hello my friend. What is your name?\n";
$you = <STDIN>;
chomp($you);
print "Hi $you. Welcome to $homepagetitle.\n";
(Since $you also contains the carriage return itself, we use chomp($you);
to remove that)
Environment variables are variables of the current
session. They are stored in a hash called %ENV/$ENV.
Here are some useful environment-variables:
Variable Name |
Info |
HTTP_COOKIE |
The visitor's cookie, if one
is set |
HTTP_REFERER |
The URL of the page that is
calling your script. This points to the HTML file that contains
your FORM-code. |
HTTP_USER_AGENT |
The browser type of the visitor |
QUERY_STRING |
The query string |
REMOTE_ADDR |
The IP address of the visitor |
REMOTE_USER |
The visitor's username (for
.htaccess-protected pages) |
REQUEST_METHOD |
GET or POST |
SCRIPT_FILENAME |
The full pathname of the current
CGI |
SERVER_NAME |
Your server's domain name |
There are more, and some servers use other variables
as well...But I don't feel the need to mention those here!
You can use the environment variables in your scripts like this:
print "You asked for file $ENV{'HTTP_FILENAME'}\n";
You need to create a .html file for this example,
because here we start using forms...Copy this text into your .html file:
<form action="env.cgi" method="POST">
Enter your name here: <input type="text" name="name" size=30>
</form>
Now save this file, call it env.htm and upload this file to your page.
Open it in your browser window.
If you would run this code, it will pass the data to the CGI file like
this: name=Firstname+Lastname.
You can also send multiple values like this:
<form action="env.cgi" method="POST">
First Name: <input type="text" name="fname" size=30><p>
Last Name: <input type="text" name="lname" size=30><p>
</form>
This will be passed to the env.cgi script like this::$ENV{'QUERY_STRING'}
= fname=Jorden&lname=Chamid
(separated by &)
This is unusable in most cases, so you will need to decode it. We use
the split function for this. The following code is very much
used, I advise you to use it in your own programs too if you will ever
need it!
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
Now, we have $FORM{'fname'} which contains the first name, and $FORM{'lname'}
with the last name, filled in on the form. Isn't that much better?
The following code is a very much used program for mailing the results
of a form to you...Have a look, and try to understand the code! (it
shouldn't be hard, since it has many comments in it!)
#!/usr/bin/perl
print "Content-type:text/html\n\n";
#This code is used often, you might want to
save this to use in your own programs! It retrieves all the info from
a FORM.
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
$Change this to the path of your mailing program
on your homepage!
$mailprog = '/usr/sbin/sendmail';
# change this to your own email address. Because
we used single quotes('), we can remove the \ before the @!!! With
double quotes, you still need one.
$recipient = 'yourname@domain.com';
open (MAIL, "|$mailprog -t") or &errorhappened("Can't
access $mailprog!\n");
print MAIL "To: $recipient\n";
print MAIL "Reply-to: $FORM{'email'} ($FORM{'name'})\n";
print MAIL "Subject: Form Data\n\n";
#Print all the variables to the mail program:
foreach $key (keys(%FORM)) {
print MAIL "$key = $FORM{$key}\n";
}
#If you're done with mailing, be sure to close
the mailprog!
close(MAIL);
# now print something to the HTML page, usually
thanking the person
# for filling out the form, and giving them a link back to your homepage
print
<h2>Thank You</h2>
Thank you for writing. Your mail has been delivered.<p>
Return to our <a href="index.html">home page</a>.
</body></html>
EndHTML
;
sub errorhappened {
($errmsg) = @_;
print "<h2>Error</h2>\n";
print "$errmsg<p>\n";
print "</body></html>>\n";
exit;
}
Save it as mail.cgi and upload it as you did
before. Don't forget to CHMOD
You can now test the script with the following
code:
<form action="mail.cgi" method="POST">
Your Name: <input type="text" name="name">
Email Address: <input type="text" name="email">
Age: <input type="text" name="age">
Favorite Color: <input type="text" name="favorite_color">
<input type="submit" value="Send">
<input type="reset" value="Clear Form">
</form>
You also can see that this script uses a SUB,
like QBasic has them too. A sub here is created by typing
sub Subname {
then comes the code, and end it with }. You can now call that
sub with &Subname. You can put subs anywhere in the program,
as long as it doesn't change the other code.
If you want the email to be send to more than one email address, just
do it like this:
$recipient = 'yourname1@domain.com, yourname2@domain.com';
etc.
Congratulations, you've just learned how to get
data mailed to you! But what if the user didn't fill out all forms that
are required?
After the data has been mailed to you, you can't let him change it anymore.
So, let's learn how to check variables!
The first thing you will need to know, is how
to check whether a field is filled in. We're gonna use the data from
the previous chapter to do that! It can be done in different ways,
I'm gonna show you some of them;
# We want to check if an email address was filled in
if ($FORM{'email'} eq '') {
&fatal_error ("Please fill in the email field!");
}
#Put the routines that mail it to you here!
sub fatal_error {
local($e) = @_;
print "<html>\n";
print "<title>Fatal Error</title>\n";
print "<font face=Arial SIZE=2>\n";
print "<h2>Fatal Error</h2>\n";
print "<b>$e</b><p>\n\n";
print "If this error continues, you should contact the admistrator.\n</html>";
exit;
}
Now this was one way to do it. We could have
also done it like this:
unless ($FORM{'email'}) {
&fatal_error ("Please fill in the email field!");
}
You might also want to check if the user submitted
a 'legal' email address, by checking for a @ in the field. Try this:
unless ("$FORM{'email'}" =~ "@") {
&fatal_error ("Your email address does not contain a @. Please change
it!");
}
In the first example of this chapter, we used
"eq" to check for two variables to be the same. We could have also
used "==". See the table below for the other conditions!
Test
|
Numbers
|
Strings
|
$x is equal to $y
|
$x == $y
|
$x eq $y
|
$x is not equal to $y
|
$x != $y
|
$x ne $y
|
$x is greater than $y
|
$x > $y
|
$x gt $y
|
$x is greater than or equal to $y
|
$x >= $y
|
$x ge $y
|
$x is less than $y
|
$x < $y
|
$x lt $y
|
$x is less than or equal to $y
|
$x <= $y
|
$x le $y
|
This will sure help your scripting :)
Some more examples, so you can get to understand
better (not related to the example):
if ($firstname eq "Jorden") {
print "Hello Webmaster\n";
}
elsif ($firstname eq "Sander") {
print "Hello brother of the webmaster!\n";
}
else {
print "Hello, I think we haven't met yet!\n";
}
Some additional checks, that will save some
space when scripting:
if ($FORM{'name'} eq "" or $FORM{'email'} eq "" or $FORM{'message'}
eq "") {
&fatal_error("Please fill out the fields for your name, email, and
message!");
}
The For () statement is sort of similar
to the IF statement. However, it works in a loop, unlike IF.
There are 3 arguements in a For () statement. The syntax:
for ($var = 0; $var < $number; $var++)
{
}
The first arguement, $var = 0, tells
the loop what value to start its variable with.
The second arguement, $var < $number, tells the loop to
continue while the main variable ($var) is less than $number.
The third arguement, $var++, tells the loop to add 1 to the
variable, aslo known as the incriment. For example:
for ($i = 0; $i < 5; $i++) {
print "$i\n";
}
Would display:
0
1
2
3
4
You can also use different incriments instead
of $i++ such as $i--, $i = $i + 20, etc.
The Foreach statement is similar to
the FOR statement. Except this time it's used for arrays. Before
I told you about arrays, and I sort of explained the foreach statement,
but not fully.
There are 2 arguements in a Foreach () statement, 1 is optional.
The syntax:
foreach $variable (@array) {
}
$variable is the variable that contains
each value of the array. Everytime the foreach loop cycles, $variable
contains the next "line" of data in the array.
@array is the array that foreach cycles through. On each cycle,
foreach gives the next line of @array to $variable.
For example:
@names = ("Terry", "Midge",
"TTWBDesign", "DustyCor");
foreach $name (@names) {
print "$name\n";
}
Would display:
Terry
Midge
TTWBDesign
DustyCor
The variable (not array) however is optional.
For instance, you can do this:
@names = ("Terry", "Midge",
"TTWBDesign", "DustyCor");
foreach (@names) {
$people++;
}
Split is another function that I mentioned
in the last section. It splits one variable into several other one.
The syntax:
($var1, $var2, $var3, etc.) = split(/$sep/,$variable);
What that does is splits $variable into
$var1, $var2, and $var3 by $sep which is the
separator. For example:
$sentence = "This is a test.";
($var1, $var2, $var3, $var4) = split(/ /,$sentence);
The results will leave $var1 containing
"This", $var2 containing "is",
$var3 containing "a", and $var4 containing
"test.". $sentence was split into 4 variables,
each divided by a single space which was identified by / /.
Reading & Saving
from & to files |
If you get data emailed to you, your mailbox might
get full if a lot of people do that. Also, other people aren't able
to read it. For Discussion boards, Guestbooks, etc., it might be more
useful to save it to a file on your server. Luckily, this is also possible,
and is just as easy as getting your server to send out mail! You just
need to CHMOD the file to 777 first.
Now just look at the example below:
open(HANDLE,"filename");
You use the "HANDLE" to point to the file. After you open it, you can
print data to it like this:
print HANDLE "data you want to add";
The above example will not work though...We opened the file for reading
only! To open a file for (over)writing, use this:
open(OVERWRITE,">filename");
To add data to the end of the file, we need to open for append:
open(APPEND,">>filename");
Please note that I changed the name of the handle...it's a good idea
to do that, so you won't end up trying to write to a READ-only file!
Sometimes servers can act really strange, so I advise you to use the
full path to your files when opening them...for example:
open (READ, "/home/www/yourname/filename.txt");
If it didn't work, nothing will actually happen...the user will not
get a notice of the failing script. So use the following code:
open(READ,"filename.txt") or &fatal_error("Can't open file for reading.");
Well, now to actually do the writing, you can
write it like this:
print APPEND "$FORM{'name'}\n";
print APPEND "This is the end of the file\n";
print APPEND "$emailaddress\n";
Well that shouldn't be too hard to figure out. A hint:$value =~
s/\n/ /g;
This removes all carriage returns from $value, for if you want to
save data on one line (you will also have to remove \n from the code
above when writing the data to a file). To make multiple variable
one line, you must use the join function. Like this:
$addline = join ("|","$FORM{'url'}","$FORM{'email'}");
Ofcourse there are other ways to do it. Like this:
$addline = "$FORM{'url'}|$FORM{'email'}";
Just see which one you like best.
Example of how you could read all the data
from a file (if you can understand this, you can basically do all
the writing you want!):
Reading files goes like this:
@input = <READ>;
This inmediately reads the entire file into the array variable @input.
You can now use the code above on arrays to read specific parts of
it. If you only want to read one line:
$input = <READ>;
The following example shows you how to print an entire data-file to
the screen:
open(READ,"readdata.txt") or &fatal_error("Can't
open file for reading!");
@array = <READ>;
close(READ);
foreach $line (@array) {
chomp($line);
print "$line\n";
}
When you're done reading/writing to a file,
you should better close the file, like this:
close(filehandle);
Small note #1: Try to teach yourself to use UPPERCASE handles
for writing to files. If you, for example, use open(log,"filename.html");,
you will call the log() function, which returns the natural logarithm
of $_. Using uppercase avoids all this.
Small note #2: In Perl 5, the & in &fatalerror above is
optional.
Congrats...You now know Perl CGI Scripting.