Learn Perl for CGI Programming - O'Reilly...

74
Learn Perl f or CGI Programming Lesson 1: Introduction What is CGI? What is Perl? Why do you use CGI? What is Perl? Lesson 2: Creating your First CGI Program The Script The Web Page The Most Common Server Error Lesson 3: Environment Variables What are Environment Variables? About the Perl Code in the Script Lesson 4: Forms The HTML Form The Perl Script The POST Method The HTML Form The Perl Script Lesson 5: Parsing Information How to Get Information into a Readable Format Step 1: Remove the '&' Signs Step 2: Remove the '=' Signs Step 3: Remove the '+' Signs Step 4: Convert the Hex Codes Into ASCII Characters Some Things to Try On Your Own Lesson 6: Regular Expressions Introduction to Regular Expressions Multipliers Matching between delimiters: Lesson 7: Variables and Operators Variables Variable Operators An 'Assignment' for You! Strings Lesson 8: Arrays and Hashes Arrays Operations with Arrays Hashes Operations with Hashes Lesson 9: Control Structures if, while, for, foreach, and more!

Transcript of Learn Perl for CGI Programming - O'Reilly...

Learn Perl for CGI ProgrammingLesson 1: Int ro duct io n

What is CGI? What is Perl?Why do you use CGI?What is Perl?

Lesson 2: Creat ing yo ur First CGI Pro gramThe Script

The Web Page

The Most Common Server Error

Lesson 3: Enviro nment VariablesWhat are Environment Variables?

About the Perl Code in the Script

Lesson 4: Fo rmsThe HTML Form

The Perl Script

The POST MethodThe HTML FormThe Perl Script

Lesson 5: Parsing Inf o rmat io nHow to Get Information into a Readable Format

Step 1: Remove the '&' SignsStep 2: Remove the '=' SignsStep 3: Remove the '+' SignsStep 4: Convert the Hex Codes Into ASCII CharactersSome Things to Try On Your Own

Lesson 6 : Regular Expressio nsIntroduction to Regular Expressions

MultipliersMatching between delimiters:

Lesson 7: Variables and Operat o rsVariables

Variable Operators

An 'Assignment' fo r You!

Strings

Lesson 8 : Arrays and HashesArrays

Operations with Arrays

HashesOperations with Hashes

Lesson 9 : Co nt ro l St ruct uresif, while, fo r, fo reach, and more!

The if StatementThe while StatementThe for StatementThe do StatementThe foreach Statement

Lesson 10: Funct io nsUsing Functions in Perl

Creating and Using LibrariesPassing Parameters

Lesson 11: Creat ing FilesOpening and Writing to Files

Lesson 12: Guest bo o kMaking a Guestbook

Improving the GuestbookUnderstanding the new guestin.plMake guestout.pl to Read the Data

Lesson 13: ChatMake a Web Chat

Auto RefreshHints fo r making it better

Lesson 14: Running Ext ernal Pro cesses o n t he ServerHow to Send E-mail with CGI

Using BackquotesUsing Processes as Filehandles

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Introduction

Welcome to the O'Reilly School o f Technology's (OST) Learn Perl f o r CGI Pro gramming course. We hope you enjoy theprocess o f learning this practical language with us and then using it to reso lve all sorts o f programming challenges.

Learning with O'Reilly School of Technology CoursesAs with every O'Reilly School o f Technology course, we'll take a user-active approach to learning. This means that you(the user) will be active! You'll learn by do ing, building live programs, testing them and experimenting with them—hands-on!

To learn a new skill o r techno logy, you have to experiment. The more you experiment, the more you learn. Our systemis designed to maximize experimentation and help you learn to learn a new skill.

We'll program as much as possible to be sure that the principles sink in and stay with you.

Each time we discuss a new concept, you'll put it into code and see what YOU can do with it. On occasion we'll evengive you code that doesn't work, so you can see common mistakes and how to recover from them. Making mistakesis actually another good way to learn.

Above all, we want to help you to learn to learn. We give you the too ls to take contro l o f your own learning experience.

When you complete an OST course, you know the subject matter, and you know how to expand your knowledge, soyou can handle changes like software and operating system updates.

Here are some tips for using O'Reilly School o f Technology courses effectively:

T ype t he co de. Resist the temptation to cut and paste the example code we give you. Typing the codeactually gives you a feel fo r the programming task. Then play around with the examples to find out what elseyou can make them do, and to check your understanding. It's highly unlikely you'll break anything byexperimentation. If you do break something, that's an indication to us that we need to improve our system!T ake yo ur t ime. Learning takes time. Rushing can have negative effects on your progress. Slow down andlet your brain absorb the new information thoroughly. Taking your time helps to maintain a relaxed, positiveapproach. It also gives you the chance to try new things and learn more than you o therwise would if youblew through all o f the coursework too quickly.Experiment . Wander from the path o ften and explore the possibilities. We can't anticipate all o f yourquestions and ideas, so it's up to you to experiment and create on your own. Your instructor will help if yougo completely o ff the rails.Accept guidance, but do n't depend o n it . Try to so lve problems on your own. Going frommisunderstanding to understanding is the best way to acquire a new skill. Part o f what you're learning isproblem so lving. Of course, you can always contact your instructor fo r hints when you need them.Use all available reso urces! In real- life problem-so lving, you aren't bound by false limitations; in OSTcourses, you are free to use any resources at your disposal to so lve problems you encounter: the Internet,reference books, and online help are all fair game.Have f un! Relax, keep practicing, and don't be afraid to make mistakes! Your instructor will keep you at ituntil you've mastered the skill. We want you to get that satisfied, "I'm so coo l! I did it!" feeling. And you'll havesome pro jects to show off when you're done.

Lesson FormatWe'll try out lo ts o f examples in each lesson. We'll have you write code, look at code, and edit existing code. The codewill be presented in boxes that will indicate what needs to be done to the code inside.

Whenever you see white boxes like the one below, you'll type the contents into the editor window to try the exampleyourself. The CODE TO TYPE bar on top o f the white box contains directions for you to fo llow:

CODE TO TYPE:

White boxes like this contain code for you to try out (type into a file to run).

If you have already written some of the code, new code for you to add looks like this. If we want you to remove existing code, the code to remove will look like this. We may also include instructive comments that you don't need to type.

We may run programs and do some other activities in a terminal session in the operating system or o ther command-line environment. These will be shown like this:

INTERACTIVE SESSION:

The plain black text that we present in these INTERACTIVE boxes is provided by the system (not for you to type). The commands we want you to type look like this.

Code and information presented in a gray OBSERVE box is fo r you to inspect and absorb. This information is o ftenco lor-coded, and fo llowed by text explaining the code in detail:

OBSERVE:

Gray "Observe" boxes like this contain information (usually code specifics) for you to observe.

The paragraph(s) that fo llow may provide addition details on inf o rmat io n that was highlighted in the Observe box.

We'll also set especially pertinent information apart in "Note" boxes:

Note Notes provide information that is useful, but not abso lutely necessary for performing the tasks at hand.

Tip Tips provide information that might help make the too ls easier fo r you to use, such as shortcut keys.

WARNING Warnings provide information that can help prevent program crashes and data loss.

What is CGI? What is Perl?CGI stands for Co mmo n Gat eway Int erf ace . Before we get into the particulars o f CGI, let's discuss the client-servermodel o f the world wide web. The client side refers to where you are sitting right now. You are looking at a web pagethat was retrieved by you from our computer in Champaign, Illino is. Our computer is responsible for actions on theserver side. The computer that houses our web pages is called a server, because it is always connected to the internetand has perpetually running software called server software. The software that serves web pages is called a webserver. So when people say "server," sometimes they are talking about a computer, and sometimes they are talkingabout a software program.

On the client side, you have a piece o f so ftware called a web browser, such as Internet Explorer or Safari o r Firefox.When you click a link or button, the browser (or client) contacts the web server with a request. The web server finds thefile you are looking for and sends a response.

So when we say CGI is a Co mmo n Gat eway Int erf ace , that's a fancy way o f saying that the web server so ftwarecan "interface" with programs that you write and store on the server side. When a client requests a file from a server,the server determines what kind o f file is being requested based on the file's extension.

Note A file's extension is the suffix, usually 2-4 letters, fo llowing a period, that lets you know what kind o f file itis. For example resume.do c is a document, and myso ng.mp3 is an MPEG Layer 3 file.

The server then decides what the response will be. For example, HTML files have an .ht m o r .ht ml file extension. Ifyou click a link that is directed to mypage.ht ml, the HTML file is retrieved and displayed in your browser window.

If the server sees a .pl (Perl file) or a .cgi (c or c++ file) file extension, it executes the file as a program—or at least triesto ! If you click a link that is directed to mypro gram.pl, the file is executed as a program and the output is sent to you.

Some servers are configured so that all o f these programs must reside in ONE directory called a CGI bin. As a studento f O'Reilly School o f Technology (OST), you'll soon find out that your programs must reside in a fo lder named cgiwithin your directory.

Why do you use CGI?

CGI is used by web programmers (you!) to retrieve information submitted by users (visito rs to your pages)and respond accordingly. Guestbooks, shopping carts, vo ting and po lling pages, web-based quizzes, creditcard payments, web-based calendars, web counters, web chats (non-java), and search engines are allexamples o f CGI applications.

What is Perl?

Perl is an acronym for Pract ical Ext ract io n and Repo rt Language . I have no idea what that is supposedto mean. Perl was created by and for UNIX system operators to help them do whatever it is they do. In thebeginning, the internet was made up o f a bunch o f UNIX machines that were connected together. Therefore,the first web masters were UNIX system administrators. These UNIX system administrators liked using Perl.Thus, the language still used most fo r CGI is Perl.

Perl is an interpreted, o r scripting, language. This means that .pl files remain text files until they are requested.Once files are requested, the Perl interpreter "compiles" and runs the program. The fact that .pl files don't needto be compiled in a separate step means they are quick and easy to write and test.

In the next tutorial, you'll start writing your own CGI/Perl applications. See you then!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Creating your First CGI Program

You're now ready to write your first CGI program! This requires you to create two files. First, you need to write the CGI script thatwill be executed on the server. Second, you need to write the HTML file that the use will see—and, we hope, click on—to run theCGI program.

The ScriptWe'll be using CodeRunner® to write the script. CodeRunner® runs over the Internet, and allows you to write, save,and execute code.

In the CodeRunner® too lbar, there's a drop-down menu for setting syntax. As a multi-purpose editor, CodeRunner®can be used for creating plain text files or recognizing code written in several languages and providing codehighlighting based on the syntax setting. In this course, we'll be setting the syntax to either HT ML o r Perl to create ourfiles. Generally, our HTML files will be forms that call our CGI scripts.

Go ahead and select Perl from the menu:

Click in the editing window so you can type, and you are ready to begin!

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

print "hello world";

Save your script to the server and check t he synt ax. To do this, click the button. A Save Filewindow will open that will allow you to name and save your script and check it fo r syntax errors. Click the cgi fo lder sothat the line it is on is light blue.

This will cause the file to be saved in the cgi fo lder. (After a file has been saved and has a name, clicking CheckSynt ax will save the file without prompting for a file name, and then check the syntax.) Enter the name myscript .pland click Save . It should look like this:

A window displays the results o f checking the syntax o f your script. For now, just go ahead and close the Result swindow. Notice that, when we save a file, the tab just below the CodeRunner® too lbar changes from saying unt it ledto the name of the file, in this case myscript .pl.

If you want to keep an existing CGI script under one name but save a revised version under another name, perhaps to

try different things while keeping a version that you know works, you can click the Save As button to save the fileunder a new name. But after you've done that, you will still want to click Check Synt ax before trying it out under thenew name.

Let's examine the script you wrote carefully. This script contains everything that MUST go into every CGI script you write.Let's discuss this script, line by line.

OBSERVE:

#!/usr/bin/perl

This should be the first line o f every CGI script you write. It tells the web server where to find the Perl interpreter (thething that converts your text into binary commands that the computer can understand), so don't fo rget to include thisline.

Note Make sure there are no blank spaces before the first character (#) o f this line! Your script will no t workproperly if # is not the first character o f the first line o f your script.

OBSERVE:

print "Content-type: text/html\n\n";

This statement print s the co nt ent -t ype header to the beginning o f your program output. The content-type header isa type o f response header. There are a few other response headers you can add, but the content-type header isneeded every time. The content-type header is used by your browser to determine that the output o f your CGI programwill be text with HTML formatting. This means that any text that comes after the header in the output should be treatedas HTML.

Notice the newline characters (\n\n) at the end o f this statement. The will place two blank lines below the header in theprogram output. You MUST have two new lines fo llowing the content header.

OBSERVE:

print "hello world";

This statement prints the words "hello wo rld" to the program output.

The Web PageNow that we have the CGI script, we need to make a web page that will run it. For now, let's keep it simple. We'll useHTML to create a link to our .pl file so that when we click on the link, the script will be executed.

Click the New File button and select HT ML from the syntax menu in the too lbar. You can move back and forthbetween the the CGI script and the HTML file you create by clicking on the tab for the one you want to view or edit.

With the syntax set to HTML, type the fo llowing text into the Editor below:

<head><title>Run my script</title></head><body><center> <a href="cgi/myscript.pl">Click here to run the script</a></center></body>

Click button to save this file using the name myscript .ht ml. Unlike the CGI script, this file should be saved in yourHo me fo lder, not the cgi fo lder. Select the button, which is located on the too lbar. (Notice that when thesyntax is set to HT ML there is a Preview button and when the syntax is set to Perl there is a Check Synt ax button.)You should see the web page that you just created. Click the link that is on this page. What happens? Your web pageshould change and the words hello wo rld should display.

You may not have noticed, but something great just happened! You wrote and ran a CGI program!!! Congratulations!

Of course, this wasn't a very interesting CGI program. After all, we could have done the same thing using JavaScript oreven plain o l' HTML. As we go on, we are go ing to learn how to take input from users using forms, and how to savethis input so we can make a guestbook and a chat.

The Most Common Server ErrorNow do me a favor. I'd like you to see what happens when you forget to include the co nt ent -t ype header o r if youmake a mistake typing it. Let's see what happens when one o f the new lines (\n) are left out. Click on the tab to go backto the myscript .pl script and change it as shown:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

print "hello world";

Click Check Synt ax to save this script and check the syntax. Then click the myscript .ht ml tab, and click Preview tosee the web page you created earlier. Click the link on the web page, just as you did before. What happens? Youshould see something like this:

Script ErrorThe server encountered an error in your script and was unable to complete your request.

If you are the author of the CGI applicat ion, we suggest you examine your error logs for a report ofpossible problems.

Whenever you see this error, it's because there's a syntax error somewhere in your script. If you select the link on thispage, you'll see your error log. The last line o f your error log will indicate where the problem occured so that you cango back and correct your script.

Take a short break and pat yourself on the back! Then go on to the next learning lab where we'll see how to get inputfrom the user.

When you finish each lesson, do your homework! In the top left pane, click to complete any Quizzes or Objectives forthe lesson:

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Environment Variables

What are Environment Variables?Every time someone clicks a link or button on the Internet, information about their browser is sent to a web server. Youcan access this information from your CGI programs through the use o f Environment Variables. In addition to providinginformation about your browser, some of the Environment Variables can be used to access information about the webserver.

Here are all o f the Environment Variables that can be used in your CGI scripts:

Enviro nment Variable Descript io n

GATEWAY_INTERFACE The revision number o f the Common Gateway Interface that the server uses.

SERVER_NAME The server's hostname or IP address.

SERVER_SOFTWARE The name and version o f the web server so ftware.

SERVER_PORT The port number the server is running on.

SERVER_PROTOCOL The name and revision o f the information the request came in with.

PATH_INFO Extra path information passed to a CGI program.

PATH_TRANSLATED The translated version o f the path given by the variable PATH_INFO.

SCRIPT_NAME The virtual path o f the script being executed.

DOCUMENT_ROOT The directory from which Web documents are served.

QUERY_STRING The query information passed to the program.

REMOTE_HOST The remote hostname of the user making the request.

REMOTE_ADDR The IP address o f the requesting machine.

AUTH_TYPE The authentication method used to validate a user.

REMOTE_USER The authenticated name of the user.

CONTENT_TYPE The MIME type o f the query data.

CONTENT_LENGTH The length o f the data in bytes passed to the CGI program.

HTTP_ACCEPT A list o f the MIME types the Client can accept.

HTTP_USER_AGENT The browser the client is using to issue the request.

HTTP_REFERER The URL of the document that the client is on before accessing the CGI program.

To illustrate how to use Environment Variables, let's write a CGI program that will return the values that are held insome of the variables. We'll use the print statement so that we can see this information on a web page. Notice that weprint HTML tags to the page in order to accomplish this. Create the fo llowing program with the syntax set to Perl:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

print "<HEAD><TITLE>Environment Variables</TITLE></HEAD>\n";print "<BODY><H1>Some Environment Variables</H1>\n";print "<HR><PRE>\n";print "Your current IP address is: $ENV{'REMOTE_ADDR'}<BR>\n";print "Your browser is: $ENV{'HTTP_USER_AGENT'}<BR>\n";print "The page you were just on is: $ENV{'HTTP_REFERER'}<BR>\n";print "The server sending you this page is: $ENV{'SERVER_NAME'}<BR>\n";print "</PRE></BODY>\n";

Click Check Synt ax and save the script to the /cgi fo lder as variables.pl.

Next, make an HTML file with a link to run the CGI program when we click on it.

CODE TO TYPE:

<head><title>variable test</title></head><body bgcolor=white><center><a href="cgi/variables.pl">Environment Variables Example</a></center></body>

Save this file to your Ho me fo lder as variables.ht ml (at this po int, I'll stop reminding you to save CGI scripts to the/cgi fo lder and HTML files to the Ho me fo lder. But please continue to do so!). Click Preview to see your HTML page,and then click on the link on that page.

In this example we only printed four o f the 19 Environment Variables. See if you can figure out how to print the rest o fthem! Please note that some of the variables won't return anything because they are not relevant and that the names o fthe environmental variables must be in all uppercase letters, just as in the table above.

About the Perl Code in the ScriptSince we're starting to use Perl code, it seems like a good time to talk about some of the details o f the code we'reusing. You may be wondering what a variable is and what the heck it has to do with the environment? Excellentquestions! Let's go over both.

Variables are objects that ho ld values. These values can be accessed and changed depending on the situation. Whatdoes that mean? A variable is like a drawer. You can put stuff into it and you can take stuff out. To see what's in adrawer at any given time, you simply open it and look. You can do the same thing with an Environment Variable! Theonly difference is that instead o f checking your drawer, you check your variable. Your variable is identified by the nameyou give it and you can have as many as you want (assuming you don't want more variables than you disk and/ormemory can ho ld—which would be a truly huge number).

Every time you click a link on a web page, your browser passes values to the server. These values change for everybrowser connecting to the server. The information must be stored somewhere. Enter Environment Variables! These arethe "drawers" we use to store and retrieve these values.

Variables in Perl are designated with a $ . This makes variables easy to spot in CGI programs. There is a specialsyntax used to access Environment Variables. The syntax is:

OBSERVE:

$ENV{'the variable name'}

...where the variable name is the name of any environment variable from the table above.

In the next lab, we'll see how to get input from users visiting our pages from anywhere in the world using Forms!

Remember to do your homework!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Forms

Review the HTML Forms Tutorial before you begin this tutorial.

HTML Forms are used to obtain information from visito rs to your webpage. Visito rs can use forms to vote, add entries to aguestbook, or participate in a web chat. In general, any information users are willing to provide to you will be entered usingforms. You can then store this information and use it fo r various purposes.

In this lesson, you're go ing to create your HTML page first. Then you'll write the CGI script to obtain and use your visito rs' inputfrom the HTML page.

The HTML FormLet's make an HTML page that takes a survey o f our visito rs' favorite web sites. We'll ask them to enter the URL of theirfavorite web site and then ask them to explain why they like it. Let's get busy! With the syntax set to HT ML, create thefo llowing file:

CODE TO TYPE:

<HEAD><TITLE>Example Using Forms</TITLE></HEAD><BODY BGCOLOR="white">

<FORM NAME="mysurvey" ACTION="cgi/websurvey.pl" METHOD="get">

What is the URL of your favorite web site?<br>

<INPUT TYPE="text" size="40" NAME="favoriteurl" VALUE=""><BR><BR>

Why is this your favorite web site?<BR>

<TEXTAREA COLS="40" ROWS="10" NAME="reason"></TEXTAREA><BR><br>

<CENTER><INPUT TYPE="submit" VALUE="Submit"></CENTER>

</FORM></BODY>

Click the Preview button to see the form elements on your HTML page, saving the file as ht mlf o rm.ht ml. Of course,if you click the Submit button, it wo n't wo rk because we haven't written the CGI script yet.

Before we work on the CGI script, let's discuss the form:

OBSERVE:

<FORM NAME="mysurvey" ACTION="cgi/websurvey.pl" METHOD="get">

On this web page, there is a form named mysurvey. When the Submit button is clicked, the information entered in theform is sent to the CGI script designated in ACT ION="cgi/websurvey.pl" . There are two ways to send information tothe CGI program: the "post" method and the "get" method. MET HOD="get " instructs the server to use the get methodto send the information to the CGI program. We'll discuss the post method a little later. For now, we'll use the getmethod as our default method.

OBSERVE:

<INPUT TYPE="text" size="40" NAME="favoriteurl" VALUE=""><BR><BR>

There are three elements in this fo rm. The first element called INPUT , has the attributes T YPE="t ext " , size="40" ,NAME="f avo rit eurl" , and VALUE="" . VALUE="" means that there is no value yet. VALUE will eventually be equal tothe information entered in the text field by the user. The NAME and VALUE of the text field will be passed (o r submitted)

to the CGI script, as you will see shortly.

OBSERVE:

<TEXTAREA COLS="40" ROWS="10" NAME="reason"></TEXTAREA><BR><br>

The next element is T EXT AREA. Again, the NAME and VALUE will be passed to the script, and the VALUE will beequal to the information entered in the TEXTAREA.

OBSERVE:

<INPUT TYPE="submit" VALUE="Submit">

Finally, we have an element that EVERY form needs: a Submit button. When the Submit but t o n is clicked, the formis sent to the CGI script fo r processing.

The Perl ScriptNow we'll make a script that takes the input from our fo rm and prints the information to the browser window. That way,you'll be able to see the information that is passed to the CGI script. This script is an instructional script, and it'sunlikely you'll ever need to do something like this with a CGI script out in the world. We'll build on this script later,though, to develop something a bit more practical. Create a new file, set the syntax to Perl, and type the fo llowing codein the Editor below:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

$forminfo = $ENV{'QUERY_STRING'};

print $forminfo;

What's go ing on here? First, we print out the Content-type header. Next, we create our own variable $f o rminf o .Remember, variables begin with a $ . We can call this variable anything we want, I just happen to like the word"forminfo ." This variable is set equal to the environmental variable QUERY_ST RING. This means that $forminfocontains the query information that passes to the program when the Submit button is clicked on the HTML form.Finally, we print out the contents o f $forminfo .

Click Check Synt ax to save this script using the name websurvey.pl. Then, switch to the HTML file, and clickPreview to view the HTML page you made earlier. Go ahead and fill out the form and Submit it. What happens?

OBSERVE:

favoriteurl=http%3A%2F%2Fwww.oreillyschool.com&reason=Because+I+love+learning.

I guess I've got some explaining to do, eh? What is this mess anyway?

Well, when you submit information to a CGI script using the get method, the browser takes the data and attaches it tothe end o f the URL. This is called URL Encoding. This allows the information to be sent as one long string (that is, oneword). Here's how the data gets "strung" together:

First, the name and value attributes for each form element are paired using the = symbol. These are called key-valuepairs. Second, all key-value pairs are combined using the symbol & to separate each pair. Next, all blank spaces in thevalues are replaced with the symbol + so that there will be one long string. Finally, each non-alphanumeric character isreplaced with its corresponding hexadecimal value (we'll discuss hexadecimal values shortly). In this example, the : isreplaced with %3A and / with %2F. Now you can see why the QUERY_STRING variable is called QUERY_STRING—itis a string!

Try submitting o ther values, adding more form elements to your HTML page, etc. Take some time to experiment, soyou fully understand what is happening.

You can also submit to a CGI program without using a form! You do this by adding the query string to the URL of theCGI script yourself. Open another browser window, and enter the fo llowing URL in the address bar, replacing

yourdomainname with your OST domain name (your OST login fo llowed by .o re illyst udent .co m ). This script doesthe same thing as your previous script:

Enter the fo llowing URL into the address bar o f another browser window:

http://yourdomainname/cgi/websurvey.pl?favoriteurl=http%3A%2F%2Fwww.oreillyschool.com&reason=because+it+rocks

This is called a canned query. Using this script, you can put any string after the ? and it will be printed to the browserwindow.

Getting and storing the information in the query string is not very useful and certainly not very pretty. In the next lab, we'llsee how we can parse the information and format it to make it more useful and pretty. For now, let's learn about the"POST" method.

The POST MethodAbove we made an HTML form and CGI script, and we used the get method o f sending and retrieving the information.Now let's use the post method, see how it works, and discuss the advantages o f each method.

The HTML Form

The only difference between the form below and the one from the previous section is that, instead o fmet ho d="get " , it has met ho d="po st " , and the script we're accessing is changed from websurvey.pl towebsurvey2.pl. Edit your htmlform.html as shown and then save it as ht mlf o rm2.ht ml.

CODE TO TYPE:

<HEAD><TITLE>Example Using Forms</TITLE></HEAD><BODY BGCOLOR="white"> <FORM NAME="mysurvey" ACTION="cgi/websurvey2.pl" METHOD="post">

What is the URL of your favorite web site?<br>

<INPUT TYPE="text" size="40" NAME="favoriteurl" VALUE=""><BR><BR>

Why is this your favorite web site?<BR>

<TEXTAREA COLS="40" ROWS="10" NAME="reason"></TEXTAREA><BR><br>

<CENTER><INPUT TYPE="submit" VALUE="Submit"></CENTER></FORM></BODY>

That's all there is to it. It's the same form, except that we are using the POST method.

The Perl Script

Now that we are using the POST method, the information is no longer contained in the QUERY_STRINGenvironment variable. Instead, the information is passed through the STANDARD INPUT stream, calledST DIN. Instead o f using $f o rminf o =$ENV{"QUERY_ST RING"} , we'll use the standard input:$f o rminf o =<ST DIN> . Enough talk though—let's go ahead and do it, and discuss it later. You know theroutine by now: start a New File and set the syntax to Perl.

CODE TO TYPE:

#!/usr/bin/perl

$forminfo=<STDIN>;

print "Content-type: text/html\n\n";

print $forminfo;

Okay, now click Check Synt ax and save this script as websurvey2.pl (notice the 2 at the end to distinguishit from websurvey.pl).

Now go back to the HTML file and click Preview, then fill out the form and Submit it. What happened? That'sright. You got the same result as when we used the "GET" method.

OBSERVE:

favoriteurl=http%3A%2F%2Fwww.oreillyschool.com&reason=Because+I+love+learning.

I know what you're thinking. You're wondering why we did this, right? Why bother with two different methodsthat produce the same results? It took me a while to figure this out too. Here are the reasons:

With the GET method, you can generate "canned queries" by adding KEY-VALUE pairs to the end o f the URL(like we did earlier), but there are limitations on the size o f the data that can be added onto the URL. Therefore,if you have a form that you expect to pass a lo t o f information, you should use the POST method. Forexample, you might want to use a textarea to co llect users' stories or essays (which could be long). In thiscase you'd want to use the POST method. But you can't use the POST method to generate "canned queries"by adding KEY-VALUE pairs to the end o f the URL. So when you want to generate "canned queries," you'llwant to use the GET method.

If you're wondering what "limitations on size" means, there's really no precise answer. The maximum size o fa GET depends on the browser and the server. A good rule o f thumb is to use the POST method when youexpect to have more than 256 characters sent to your CGI. We'll go over the POST method in the next lab.

So, let's move on to the next learning lab, where we will learn how to parse and format our data.

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Parsing Information

How to Get Information into a Readable FormatIn the last lab, you learned how to read form information into your script. Then you printed it back to the client(browser). By do ing this, you found that the information was in one long ugly string—yuck! We need to figure out howto "parse out" and format information. Fortunately, Perl was designed specifically fo r that—Perl is great fo r working withtext!

Let's start where we left o ff in the previous lab and use the same HTML and Perl documents we used before. If you'vebeen fo llowing along, then you can retrieve your files from your directory. To open an existing file, click on the Lo ad

button and select the file from the Lo ad File window. Retrieve both the CGI script websurvey2.pl and the HTMLfile ht mlf o rm2.ht ml.

In case you didn't save them, below are the HTML and Perl files. Type them into the Editor with the syntax set to HTMLand Perl respectively.

With the syntax set to HTML, type the fo llowing text into the Editor below:

<HEAD><TITLE>Example Using Forms</TITLE></HEAD><BODY BGCOLOR="white">

<FORM NAME="mysurvey" ACTION="cgi/websurvey2.pl" METHOD="post">

What is the URL of your favorite website?<br>

<INPUT TYPE="text" size="40" NAME="favoriteurl" VALUE=""><BR><BR>

Why is this your favorite web site?<BR>

<TEXTAREA COLS="40" ROWS="10" NAME="reason"></TEXTAREA><BR><br>

<CENTER><INPUT TYPE="submit" VALUE="SUBMIT"></CENTER>

</FORM></BODY>

Save this HTML file as ht mlf o rm2.ht ml.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

$forminfo = <STDIN>;

print $forminfo;

Click Check Synt ax to save it using the name websurvey2.pl

Recall from Learning Lab 4 that when you fill out the HTML form and submit it, this script simply prints back the querystring contained in the variable $f o rminf o . After you submit it, you should get something like this:

OBSERVE:

favoriteurl=http%3A%2F%2Fwww.oreillyschool.com&reason=Because+I+love+learning.

Now let's use Perl to parse this data into something we can use. What do I mean by parsing? Well, we have the

information from our various form inputs divided by special characters. Input fields are divided by & signs. The name ofthe input is separated from what the user typed in by an = sign. All o f the spaces are replaced by + signs. Parsingmeans using the locations o f these characters to put the information into a form that's easier to use. By do ing this, wecan extract just the information we want. If we only want the "favoriteurl" part o f the form, we can retrieve it by parsing itusing Perl.

We are go ing to approach this in four steps:

Step 1: Remove the '&' Signs

First, we'll break this long single string,"f avo rit eurl=ht t p%3A%2F%2Fwww.o reillyscho o l.co m&reaso n=Because+I+lo ve+learning" intothe parts that are separated by an & sign. In this specific case, there are two parts separated by an & sign thatcorrespond to the two KEY-VALUE pairs. Below, the first KEY-VALUE pair is red and the second is blue andthey are separated by a black & sign:

OBSERVE:

favoriteurl=http%3A%2F%2Fwww.oreillyschool.com&reason=Because+I+love+learning

When we break this string into two parts, we'll need to put each part somewhere. That somewhere will be anARRAY. We'll discuss arrays more later in this lab, and at length in a future lab.

Step 2: Remove the '=' Signs

Next, we'll split up each KEY-VALUE pair and save them in an array. In this particular case we'll end up withfour parts: two KEYS and two VALUES.

Step 3: Remove the '+' Signs

Next, we'll get rid o f all o f the + signs.

Step 4: Convert the Hex Codes Into ASCII Characters

Finally, we'll convert the Hexadecimal codes back into ASCII characters. (Computers only understandnumbers—an ASCII code is the numeric representation o f a character such as 'a' o r '@' or an action o f somesort. We'll explain hexadecimal stuff in a little bit.)

Let's go ahead and perform these steps. Add the fo llowing code to your Perl script:

With the syntax set to Perl, type the fo llowing text into the Editor below.

#!/usr/bin/perl

print "Content-type: text/html\n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo); foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}print $FORM_DATA{'favoriteurl'}, "\n\n"; print $forminfo;

Please don't freak out (yet)! This has to look pretty strange to you right now (it certainly looked strange to mewhen I first saw Perl)! As I said, we'll be go ing over this topic not only in this lab, but in more detail in the nexttwo labs about Arrays and Regular Expressions. For now, just type the code and make sure you can get thisscript to run.

Click Check Synt ax to save this script and check the syntax. Then, switch to the HTML file and Preview theweb page. Fill out the form and submit it. What happened? Whatever you put into the f avo rit eurl text fieldshould print back to the screen.

Alright. So now you're probably wondering what we just did, right?

Let's break down the program line by line. First, look at:

OBSERVE:

@key_value_pairs = split(/&/,$forminfo);

The first thing we should talk about is what that split operation is do ing. Split takes a string and splits it intotwo strings at some character. For example, we could use split to break the word calif o rnia into the twostrings separated by the f , in this case cali and o rnia. The syntax for this would be split (/f /,"calif o rnia");.The two arguments (represented by the two entries in the parentheses, one before the comma, one after thecomma) tell us which character to split around (called a "token") and which string to split, respectively. In ourspecific cgi example, instead o f a specific string in quotes like "califo rnia", we have the variable $f o rminf o(which is ho lding a string—the user-entered URL).

Split separates the string at EVERY occurrence o f the "token" (the character that we are splitting around);hence we can end up with many key/value pairs from one string—one key/value pair fo r each occurrence o fthe token. The forward slashes "/" surrounding the token, like /f / in our califo rnia example and /&/ in the CGIscript are an example o f pattern matching. When you surround a string o f characters with two forward slashes,you are asking the program to MATCH that pattern. For example, what two strings do you think would comeout o f split (/if o /,"calif o rnia");?

Once we split a string, we have to store all o f the smaller strings in an array. Basically, an array is like avariable that can ho ld a list o f entries, each o f which can be accessed individually. For instance, with ourcalif o rnia example, we can do the fo llowing:

OBSERVE:

@an_array = split(/i/,"california");

Similar to variables, which begin with $ , arrays begin with @ .

So the @an_array array looks like ("cal" ," f o rn","a") . In o ther words, the first element in the array is "cal",the second is "fo rn," and the third is "a". To access the individual elements, you simply call $an_array[0] fo rthe first element, $an_array[1] fo r the second element, and $an_array[2] fo r the third element (the elementsare numbered such that the first is 0 , the second is 1, etc.).

In our example, $an_array[0] is "cal" and $an_array[1] is "f o rn". (yes, to access the array ELEMENTS, use$ in front o f the arrayname, as well as brackets enclosing the number o f the array element).

Now let's look at the next line o f our parsing script:

OBSERVE:

foreach $pair (@key_value_pairs){ ...

}

This part takes an array (in this case, the elements o f the array @key_value_pairs), assigns each element toa variable (in this case, the variable called $pair), then executes the block o f code between the { and } . Theidea is that the block o f code should do something with each element, one at a time. Therefore, the f o reachstatement sticks one element into the variable $pair, then executes the code that does something with thatvariable. Then, when the code is done, f o reach clears the variable, puts the next element into it, and so on.

Now let's look at the block o f code that finishes the parsing for us. We have already split the data into the partsseparated by &, so we have already gotten rid o f all the & characters. What we have in our case (dependingon how many form elements there are), are two or more elements in our @key_value_pairs array. Our arrayis ho lding the key/value pairs, which are separated by an = . Specifically, in our program our@key_value_pairs array looks something like this:

OBSERVE:

$key_value_pairs[0] = favoriteurl=http%3A%2F%2Fwww.oreillyschool.com

$key_value_pairs[1] = reason=Because+I+love+learning

We still need to do something to get rid o f the = and + signs, and convert the Hex representations like %3A totheir actual characters (%3A is a co lon (:) and %2F is a fo rward slash (/)) .

The fo llowing line in our program splits the string temporarily stored in $pair at the = sign, and stores thevalues in the variables ($key,$value) .

OBSERVE:

($key,$value) = split(/=/,$pair);

The very next line takes the string stored in $value and replaces all the + signs with spaces. Let's figure outhow it does that:

OBSERVE:

$value =~ s/\+/ /g;

As you will see, the =~ operator can be read as "becomes," when used with operations like the substitutionoperator s we are using here. So you can read this line in English as "$value becomes s/\+/ /g;".

We still have to figure out what the right side says. First o f all, the s means subst it ut e . We are using itbecause we want to substitute the + signs with spaces. The substitution operator always has three forwardslashes with it. The string you want to replace goes between the first and second slashes, and the string youwant to replace it with goes between the second and third slashes. So the whole thing, s/\+/ /g, says, "findoccurrences o f the + character" (the backslash "\" means "treat the + sign as a character and not anoperator") and replace it with a space (notice there is a space between the second and third forward slashes).Finally, the g tells the substitution operator to replace ALL occurrences (g stands for global).

Now the last transformation:

OBSERVE:

$value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;

The goal o f this line is to find all hexadecimal representations o f characters and replace them with their ASCIIcharacters. For example, we need to replace %3A with a : (co lon). We use a regular expression to find andreplace all o f them with just one line.

%([0-9a-f A-F][0-9a-f A-F]) matches any string o f the form %nX. That is, the string has a percent signfo llowed by a pair o f characters, each o f which is either a number 0 - 9 or one o f the upper or lower-caseletters A - F. (We'll explain HOW it does this in another lesson).

pack("C", hex($1)) converts any matches found in the first part (passed to it through the $1 variable) toreadable ASCII characters.

Finally, the s operator substitutes all o f the hex with their ASCII equivalents.

Look at the last line o f the block o f code in the f o reach loop:

OBSERVE:

$FORM_DATA{$key} = $value;

Here, we are putting the value from the $value variable into an array called FORM_DAT A. This is a differentkind o f array, called a Hash o r an associative array. The elements o f this kind o f array are indexed by any stringyou want, instead o f by integers (like normal array elements use). The elements o f a Hash are called values,and the indexes are called keys. As we will see in a later lesson, there are several ways to fill a hash. For ourpresent purpose, we'll do it one at a time. We are setting two keys: favoriteurl and reason, and two associatedvalues (depending on what the users have typed): http://www.oreillyschoo l.com and "Because I love it." So if

we use the key to access a value, then to access the value indexed by the favoriteurl key, we do the fo llowing:

OBSERVE:

$FORM_DATA{"favoriteurl"}

Which in this case would be... http://www.oreillyschoo l.com.

Finally, we print out the value held in the $FORM_DATA{"favoriteurl"} hash.

So that's it! Whew! We're all done talking about your first real Perl script. In lessons to come, we'll spend moretime go ing over arrays and regular expressions (which make Perl so powerful).

Some Things to Try On Your Own

Try applying the substitution operator to o ther characters. For instance, substitute lower case w withcapital W, just to see if you can.Add more forms to your HTML form page.Print out different fo rm variables.

See you in the next lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Regular Expressions

Introduction to Regular ExpressionsIn the last lab, we touched on regular expressions (sometimes shortened to regex). In this lab, we'll get an even betterfeel fo r regular expressions and their power. To start, we'll need a way o f getting feedback when we try using regularexpressions. Right now, retrieve the Perl files you were using in the last lab, websurvey2.pl and ht mlf o rm2.ht ml.I'm assuming that you saved these files, but in case you didn't I'll give you the code below again. Remember, set theEditor syntax to Perl fo r Perl files and HTML for HTML files before you create them. When you retrieve them,CodeRunner® will automatically set the Editor into the proper syntax, based on the file extension.

Here is ht mlf o rm2.ht ml:

CODE TO TYPE:

<HEAD>><TITLE>>Example using FORMS</TITLE>></HEAD>><BODY BGCOLOR="white">>

<FORM NAME="mysurvey" ACTION="cgi/websurvey2.pl" METHOD="post">>

What is the URL of your favorite website?<br>>

<INPUT TYPE="text" size="40" NAME="favoriteurl" VALUE="">><BR>><BR>>

Why is this your favorite web site?<BR>>

<TEXTAREA COLS="40" ROWS="10" NAME="reason">></TEXTAREA>><BR>><br>>

<CENTER>><INPUT TYPE="submit" VALUE="SUBMIT">></CENTER>>

</FORM>></BODY>>

Here is websurvey2.pl:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}print $FORM_DATA{'favoriteurl'}, "\n\n";

A regular expressio n is a template or pattern that is used to match a string. We have already seen an example usingregular expressions with the substitution operator s. We searched the string contained in the $value variable for +(plus) signs and substituted them with spaces. Let's try some more. Let's substitute "t he " with "da" wherever it occursin our string. To get output and thus feedback, we'll add lines to the websurvey2.pl program as shown below:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $value =~ s/the/da/g; $FORM_DATA{$key} = $value;}print $FORM_DATA{'favoriteurl'}, "\n\n";

print $FORM_DATA{'reason'}, "\n\n";

Be sure to Check Synt ax to save this script and check the syntax.

Why do you suppose I had you add the line print $FORM_DATA{'reason'}, "\n\n";?

Now switch to the HTML form page and Preview. Type any URL, and then type the fo llowing sentence into the bottomtextarea:

T he reaso n t he chicken cro ssed t he ro ad was t o get t o t he o t her side.

What happened?

Try removing the g at the end o f the command. What happens? The g tells the substitution to replace all occurrences.

Now, suppose you want to replace every vowel with an "X" (fo r some reason; just bear with me!). We can do that, butnow we are searching for a class o f characters. We could search and replace each vowel one at a time, like this:

OBSERVE:

$value =~ s/a/X/g;$value =~ s/e/X/g;$value =~ s/i/X/g;$value =~ s/o/X/g;$value =~ s/u/X/g;

But if you ask me, that takes too much typing! Fortunately, there's a shortcut—we can search for a class o f characters. Acharacter class is represented using a pair o f square brackets. So to search for a, e, i, o , and u at the same time, weuse the character class [aeio u] . Let's try it.

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $value =~ s/the/da/g; $value =~ s/[aeiou]/X/g; $FORM_DATA{$key} = $value;}print $FORM_DATA{'favoriteurl'}, "\n\n"; print $FORM_DATA{'reason'}, "\n\n";

You probably know the routine by now. Click on Check Synt ax to save this script and check the syntax, and then go tothe HTML form, Preview it, type any sentence you like, and click Submit . What happened? Well, it should havereplaced each o f the vowels with an "X." What happens if you type in capital letters and in particular, capital vowels?

If you want to replace CAPITAL vowels as well as lowercase vowels, then add them to the character class:

OBSERVE:

$value =~ s/[aeiouAEIOU]/X/g;

Now, suppose that you want to put an "X" in front o f every vowel instead o f replacing it. To do that, you'll need to matchthe vowel, remember it, and then substitute the matched vowel with an "X" fo llowed by the remembered vowel. Howcan we remember the matched character? By putting a set o f parentheses around it. This tells Perl to put the matchedcharacter into memory so we can access it later. Add the parentheses to your regular expression as shown:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $value =~ s/([aeiou])/X$1/g;

$FORM_DATA{$key} = $value;}print $FORM_DATA{'favoriteurl'}, "\n\n";print $FORM_DATA{'reason'}, "\n\n";

Click Check Synt ax to save this script and check the syntax and then go to your HTML form to test it out. Whathappens? Did it put the "X" in front o f the vowels instead o f replacing them?

Let's discuss what is go ing on with this line. The parentheses surrounding the character class tells Perl to save thematched character into the variable $1. (If we had a second set o f parentheses saving something else into memory, itwould use the variable $2, a third would be $3, and so on.) We then substitute the matched character with X$1, which inthis case is simply X fo llowed by the character we matched. So, fo r instance, if the word were f riend then the outputafter passing through the above command would be f rXiXend.

Here are some other character class examples:

[aeiouAEIOU] matches any lower or Upper case vowel

[^aeiouAEIOU] matches an non vowel character. The "^" means NOT

[0-9 ] matches any single digit

[^0-9 ] matches any non single digit. The "^" means NOT.

[a-z] matches any lower case letter

[a-zA-Z] matches any lower OR upper case letter

[a-zA-Z0-9] matches any digit o r letter

Perl also has some predefined character classes to make it easier fo r you:

\d is equivalent to [0 -9 ] i.e. it matches any single digit

\w is equivalent to [a-zA-Z0-9] i.e. it matches any word character

\s matches any space character

The fo llowing are their negations:

\D matches non digits

\W matches any non word character

\S matches any non space

We can use these predefined classes with the o ther character classes too; fo r example, [\da-zA-Z ] is equivalent to [0-9a-zA-Z ] .

Try different combinations in your script, then try typing different things in your HTML form and see what happens.

Before we start talking about multipliers, lets talk about ".". If you want to match any character, you use a "." (period).For example, the fo llowing matches any string like "but", "bat", "btt", etc. and substitutes it with "stuff":

OBSERVE:

$value =~ s/b.t/stuff/g;

Multipliers

If you want to match something like bbt o r bbbbt o r bbbbbbbt , you can use an "*" (asterisk). This is calleda multiplier because it matches multiple instances o f the previous character. This multiplier matches zero ormore instances o f the previous character. For example, the fo llowing matches t , bt , bbt , bbbt and so on,and replaces it with the word "stuff":

OBSERVE:

$value =~ s/b*t/stuff/g;

Other multipliers are the plus sign (+), matching one or more o f the previous characters, and the questionmark (?), matching zero or one o f the previous characters. For example, /b+t b?t / matches bt t , bbt t , bt bt .bbt bt , bbbt bt etc., but not t bbt .

Suppose we only want to match strings with only so many occurrences o f a character. If we have 16 "b"'s in arow and we only want to replace 5 to 10 o f them with "stuff," we would use {N,M}. N is the minimum amounto f characters to match and M is the maximum. Try each the fo llowing in your script, then type a whole bunch o fb's in a row in your HTML form and see what happens.

T he f o llo wing mat ches 5 ,6 ,7 ,8,9 o r 10 inst ances o f t he let t er "b" in a lo ng st ring o f b's:

OBSERVE:

$value =~ s/b{5,10}/stuff/g;

The fo llowing matches AT LEAST 5 b's:

OBSERVE:

$value =~ s/b{5,}/stuff/g;

The fo llowing matches AT MOST 5 b's:

OBSERVE:

$value =~ s/b{0,5}/stuff/g;

The fo llowing matches EXACTLY 5 b's:

OBSERVE:

$value =~ s/b{5}/stuff/g;

Matching between delimiters:

Now, suppose we want to match everything that is between two characters, say X and Z. To do that, we use".*" Let's see how this works. We are go ing to replace all the characters between the first X and the last Z.

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $value =~ s/X.*Z/stuff/g; $FORM_DATA{$key} = $value;}print $FORM_DATA{'favoriteurl'}, "\n\n";

Click on Check Synt ax to save this script and check the syntax. Then go to your HTML form and type thefo llowing in the textarea:

Here's a bunch o f t eXt wit h everyt hing f ro m A t o Z in it and we're go ing t o see ho w t hereplacement wo rks.

Then Submit it.

What happens? It should replace all the text between the first X and the last Z. Try including several X's andseveral Z's and see what happens. Since the ".*" expression is looking for the last occurrence o f Z, it is calledgreedy—it wants to match as much as it possibly can.

If you want to match the first X and the first occurrence o f Z, fo llow the ".*" with a "?":

Add "?" to your expression like so:

OBSERVE:

$value =~ s/X.*?Z/stuff/g;

Try typing some text into your HTML form, making sure that you include capital X's and Z's.

To substitute an X and a Z that happen to be separated by EXACTLY 5 characters, use the fo llowing:

OBSERVE:

$value =~ s/X.{5}Z/stuff/g;

We're done with discussing regular expressions for now, but since you will be seeing more o f regularexpressions in future lessons, you might want to look at this Reference Guide.

See you in the next lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Variables and Operators

In this lab, we will discuss variables. You have already used variables in previous labs, and we have discussed them briefly.Let's take the time to learn more!

VariablesVariables are objects that ho ld values. The values may change depending on the situation. Variables can only ho ldone value at time. You can think o f a variable as a drawer that ho lds only one specific type o f item. The value o f thedrawer is based on the amount o f stuff in it. The amount o f stuff changes, even though the drawer stays the same.

In Perl, all variable names begin with $ . The rest o f the name can be anything you want, provided that the first characteris a letter. Variable names are case sensitive, so be aware that $A is a different variable from $a. It's a good idea touse descriptive variable names that are relevant to their purpose in your program.

The values you assign to your variables will be one o f two categories—numbers or strings. To assign a variable equalto a number, the syntax looks like this:

OBSERVE:

$first_variable = 3;$first_variable = 3.75;

To assign a variable equal to a string, you must use quotation marks. The syntax looks like this:

OBSERVE:

$second_variable = "chris";$second_variable = "u";

We can also assign values to variables that depend upon o ther variables:

OBSERVE:

$third_variable = "I owe $second_variable at least $first_variable dollars.";

Let's try using some variables. Set the editor to Perl mode and enter code as shown below:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

$a = 3;

$b = "Chris";

$c = "I owe $b at least $a dollars";

print $a;print "<br>\n";print $b;print "<br>\n";print $c;

Click Check Synt ax and save this script using the name variables.pl. The Result s window appears. If the syntaxwas okay, click Preview. You'll see:

OBSERVE:

3ChrisI owe Chris at least 3 dollars

As you can see, the values stored in the three variables are displayed in the browser window.

Now that we know how to assign values to variables, let's learn how we can use variable operations to manipulatethem.

Variable OperatorsThe assignment operator is the most common. As its name implies, the assignment operator assigns a value to avariable. You just learned that = (equals sign) is the assignment operator used in Perl. Sometimes you may want tochange the value o f a variable. This can be accomplished using common math functions:

Example Descript io n

$the_number = 2; $the_number is assigned an initial value o f 2.

$the_number = $the_number +4; 4 is added to the initial value. Because 2 + 4 = 6 , $the_number is now equal to 6 .

$the_number = $the_number *3;

$the_number is multiplied by 3. Because 6 * 3 = 18, $the_number is now equal to18.

$the_number = $the_number /6 ; $the_number is divided by 6 . Because 18 / 6 = 3, $the_number is now equal to 3.

$the_number = $the_number **2; $the_number is squared. Because 3^2 = 9 , $the_number is now equal to 9 .

An 'Assignment' for You!Try to use these variable operations in a script. Print the variable each time it is assigned a new value. That way youcan see the result o f variable operations yourself!

Operations like the ones you just learned are so common that o ther operations have been devised to shorten thesetypes o f expressions. These shortened operators are called binary assignment operators. Let's perform the sameoperations we did earlier using binary assignment operators.

Example Descript io n

$the_number = 2; $the_number is assigned an initial value o f 2.

$the_number += 4; 4 is added to the initial value. Because 2 + 4 = 6 , $the_number is now equal to 6 .

$the_number *= 3; $the_number is multiplied by 3. Because 6 * 3 = 18, $the_number is now equal to 18.

$the_number /= 6 ; $the_number is divided by 6 . Because 18 / 6 = 3, $the_number is now equal to 3.

$the_number **= 2; $the_number is squared. Because 32 = 9 , $the_number is now equal to 9 .

There are two o ther operators that you will find useful—the autoincrement (++) and autodecrement (--) operators.Adding or subtracting 1 from a variable is a very common thing to do in programming. These operators are used forthis purpose. Here's how they work:

Example Descript io n

$the_number = 2; $the_number is assigned an initial value o f 2.

$the_number++; $the_number is incremented by 1. Because 2 + 1 = 3, $the_number is now equal to 3.

$the_number = 2; $the_number is assigned an initial value o f 2.

$the_number--; $the_number is decremented by 1. Because 2 - 1 = 1, $the_number is now equal to 1.

Strings

So far, all o f the operations we have discussed are used when your variable is a number. But there is also anoperation you can use if your variable is a string. This operation is called concatenation, and it is used to combine twostrings to make one string. The concatenation operator is a period (.). Let's see how it works!

Example Descript io n

$company_name ="User"."Active";

"User" is combined with "Active". $company_name is now equal to"UserActive."

Throughout the upcoming lessons, there are lo ts o f opportunities to practice the operations we've just gone over. Take sometime, then, to experiment with the concepts you learned here.

You're do ing great—see you in the next lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Arrays and Hashes

ArraysI'm sure you use list s o ften; you make grocery lists, o r "to do" lists, all the time. A list in Perl has the fo llowingrepresentation:

OBSERVE:

(1st_element, 2nd_element, 3rd_element)

That was a list with three elements. An array is a variable that ho lds a list. For example:

OBSERVE:

@an_array = (1st_element, 2nd_element, 3rd_element);

That was an array called an_array. Notice that array names begin with @ in the same way variable names begin with$ .

An array is like a file cabinet with numbered folders that you keep stuff in. For example, suppose the fo llowing is anarray called @names. It currently has some names in it.

Again, notice that Perl array names begin with @ . Also notice that the first "folder" (array element) is number 0. Thebeauty o f using arrays is the convenience it allows when we access elements. For examplee, if we want to know whichname is in the fourth fo lder o f @names, we simply ask for $names[3] .

This would return "T o ny" in this case. When we access array elements, we use $ in front o f the array name, becauseeach element in an array is viewed as a variable.

If we want to change the element in $names[4] from Mike to Jo sh, we assign the new value:

OBSERVE:

$names[4] = "Josh";

Our array would now look like this:

Now it's your turn to try this out. Create the fo llowing Perl script:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

@numbers = (1 .. 19);

$names[4] = "josh";

$names[7] = "trent";

print "names[4] is $names[4] \n";

print "<br><br>"names[6] is $names[6] \n";

print "<br><br>"names[7] is $names[7] \n";

print "<br><br>"numbers[4] is $numbers[4] \n";

Click Check Synt ax and save the script using the name array.pl. This script doesn't need an HTML form, so you canyou can preview your script on the web by clicking Preview in the Results window.

With the example script we just made, we filled the array called @names with some strings that happen to be names.We also made an array called @numbers, which consists o f integers between 1 and 19. We put two dots ".." betweenthe numbers 1 and 19, which filled in the o ther integers for us. (This would also work for letters. If we had entered (a ..z) then the array would include the entire lower-case alphabet.)

Next, we changed the fifth element, $names[4] , to jo sh. Finally, we printed out the fifth element in @names, and thefifth element in @numbers. Remember, the fifth element in the names array is $names[4], no t $names[5]. Take sometime and print out some other elements.

If you go on to study C or C++, you'll no tice a difference between Perl and C/C++ arrays. In C or C++, you must declarethe length o f your arrays before you use can them. You don't have to do this in Perl.

Perl can do a lo t o f work for us to minimize our typing. Above, when we wrote out the names to put into the @namesarray, we had to type a bunch o f quotation marks and commas in addition to the actual strings we wanted to put intothe array. Perl has a too l that allows us to do this without typing so much. It's called the qw operator, where "qw"stands for quo t e wo rd. The qw() operator creates a list from all the non-whitespace characters between theparentheses.

OBSERVE:

qw(scott kendell trish tony mike debra curt)

is the same as

OBSERVE:

("scott","kendell","trish","tony","mike","debra","curt")

TRY IT!

Operations with Arrays

Now that we can create and access arrays in Perl, let's learn more about array manipulation. It's possible toadd or remove elements at the beginning or the end o f an array. We can also reverse the order o f an array.

Suppose we want to add more names to our list o f names. Here's one way to do it:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

@numbers = (1 .. 19);

$names[4] = "josh";

$names[7] = "trent";

print "names[4] is $names[4] \n";

print "<br><br>"names[6] is $names[6] \n";

print "<br><br>"names[7] is $names[7] \n";

print "<br><br>"numbers[4] is $numbers[4] \n";

print "<br><br>"names is @names";@names = (@names, "chris");print "<br><br>"names is @names";

To add to the front o f the array, we do the fo llowing:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

print "<br><br>"names is @names";@names = (@names, "chris");print "<br><br>"names is @names";@names =("matt",@names);print "<br><br>"names is @names";

Of course, Perl has some functions to make this process a little shorter. The functions are push and po p andshif t and unshif t .

Try the fo llowing:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

print "<br><br>"names is @names";push(@names,"chris");print "<br><br>"names is @names";@names =("matt",@names);print "<br><br>"names is @names";

This gives the same result as the previous version o f the program.

We can also remove the last element o f an array with po p:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

print "<br><br>"names is @names";push(@names,"chris");print "<br><br>"names is @names";@names =("matt",@names);print "<br><br>"names is @names";pop(@names); print "<br><br>"names is @names";

As you see, push and po p change the array on the end (o r right side, or top) o f the array. Shif t and unshif tdo the same kind o f thing on the beginning (o r left side, or bottom) o f the array.

So, suppose we wanted to move "matt" from the beginning to the end o f the list. We can use shif t to removethe name and store it in a variable, and then push to put the name on the end o f the list using the samevariable:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

print "<br><br>"names is @names";push(@names,"chris");print "<br><br>"names is @names";@names =("matt",@names);print "<br><br>"names is @names";pop(@names); print "<br><br>"names is @names";$firstvalue = shift(@names);push(@names,$firstvalue);print "<br><br>"names is @names";

Now, suppose we want to add "tim" before "scott" in the list. The fo llowing does the same as @names=("tim",@names):

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

print "names is @names";@names =("matt",@names);print "<br><br>"names is @names";$firstvalue = shift(@names);push(@names,$firstvalue);print "<br><br>"names is @names";unshift(@names,"tim");print "<br><br>"names is @names";

Finally, suppose we want to print the contents o f the array backwards. Perl has a function called reverse:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

@names = ("scott","kendell","trish","tony","mike","debra","curt");

print "names is @names";@names =("matt",@names);print "<br><br>"names is @names";$firstvalue = shift(@names);push(@names,$firstvalue);print "<br><br>"names is @names";unshift(@names,"tim");print "<br><br>"names is @names";@newnames = reverse(@names);print "<br><br>newnames is @newnames";

@newnames is now ("matt","curt","debra","mike","tony","trish","kendell","scott", "tim"). (@names remainsunchanged.)

HashesA hash, sometimes called a hash table o r associative array, is an array that is indexed by strings instead o f integers.For example, we might want to add titles for the names in our array. If we put the names into a hash instead o f an array,our picture would look like this:

The hash is named %officers (note that the % sign is used for hashes like the $ for variables and the @ for arrays).Now if we want to access an elements o f this hash, we can do so by the title:

OBSERVE:

$officers{"title"}

$o f f icers{"secret ary"} will return the value t rish.

Okay, now try this on your own. Create a new Perl script like this:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

$officers{"president"} = "scott";

$officers{"CEO"} = "kendell";

$officers{"secretary"} = "trish";

$officers{"treasurer"} = "tony";

$officers{"VP"} = "mike";

$officers{"CFO"} = "debra";

$officers{"gopher"} = "curt";

print $officers{"VP"};

print "<br><br>"; print $officers{"president"};

Save this as hash.pl, then click Check Synt ax and Preview it from the Result s window.

Another way to fill a hash "array" is with a list. Every successive pair in the list becomes a key-value pair, so the listmust contain an even number o f elements. Change hash.pl to look like this:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

$officers{"president"} = "scott";

$officers{"CEO"} = "kendell";

$officers{"secretary"} = "trish";

$officers{"treasurer"} = "tony";

$officers{"VP"} = "mike";

$officers{"CFO"} = "debra";

$officers{"gopher"} = "curt";%officers = ("president","scott","CEO","kendell","secretary","trish","treasurer","tony", "VP","mike","CFO","debra","gopher","curt");

print $officers{"VP"};

print "<br><br>";

print $officers{"secretary"};

Operations with Hashes

Once we have a hash, we can list all o f the keys by using the keys function, and all o f the values using thevalues function. Let's try it. Change your hash.pl script as shown:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

%officers = ("president","scott","CEO","kendell","secretary","trish","treasurer","tony", "VP","mike","CFO","debra","gopher","curt");

print keys(%officers);

print "<br><br>";

print values(%officers);

Click Check Synt ax and save this to see how it works.

Finally, if you want to delete a key-value pair from a hash array, use the delet e statement. Change your scriptto look like this:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

%officers = ("president","scott","CEO","kendell","secretary","trish","treasurer","tony", "VP","mike","CFO","debra","gopher","curt");

delete $officers{"VP"};

print keys(%officers);

print <br><br>

print values(%officers);

Click Check Synt ax and save this script so you can see it in action!

You have quite an array o f new skills to show off now—see you in the next lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Control Structures

if, while, for, foreach, and more!Often in life, you need to make decisions about how to proceed in a given situation—if the light is red, stop; if the lightis green, go—and sometimes you might need to perform some activity more than once, fo r example when you "lather,rinse, and repeat" when washing your hair. Programming languages like Perl provide contro l structures that enableyou use these kinds o f logic in your programs. We'll discuss them in this lesson.

The if Statement

The if statement is one o f the most powerful too ls at your disposal. It allows you to test one or more things("is the light green?") and react to the results o f that test. Let's start by do ing a simple "if" test.

This example requires an HTML form. If the user enters a number that is greater than 21, it will print Yo u areT OO OLD t o drink; if the number is less than 21, it will print Yo u are T OO YOUNG t o drink; if the numberis 21 exactly, the program prints Yo u are OLD ENOUGH t o drink. (Note: Our examples may not alwayscorrelate to reality or state laws!)

Let's create the HTML file.

CODE TO TYPE:

<HEAD> <TITLE>Example using FORMS</TITLE></HEAD>

<BODY BGCOLOR=white>

<FORM NAME=picknumber ACTION="cgi/statements.pl" METHOD="post"> Pick a number between 1 and 100: <INPUT TYPE="text" size=4 NAME="thenumber" VALUE=""> <BR><BR>

<CENTER> <INPUT TYPE="submit" VALUE="SUBMIT"> </CENTER></FORM>

</BODY>

Save this file using the name st at ement s.ht ml.

Notice that this HTML form only has one input and that the name of the input is t henumber.

Now we need a Perl script to handle the input. Create a new file and set the syntax to Perl.

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

if ($FORM_DATA{"thenumber"} > 21) { $theword = "TOO OLD"; }elsif ($FORM_DATA{"thenumber"} == 21) { $theword = "OLD ENOUGH"; }else { $theword = "TOO YOUNG"; }

print "<font size=5>";print "You are $theword to drink";print "</font>";

Click Check Synt ax and save this script using the name st at ement s.pl. Then Preview the HTML file, typea number in the form, and submit it. Did you notice that we are accessing the value in the hash called%FORM_DAT A indexed by the key t henumber?

How does it work? Look at the fo llowing co lor-coded code for reference—it's made up o f the if, elsif, and elsestatements from our example:

OBSERVE:

if ($FORM_DATA{"thenumber"} > 21) { $theword = "TOO OLD"; } elsif ($FORM_DATA{"thenumber"} == 21) { $theword = "OLD ENOUGH"; } else { $theword = "TOO YOUNG"; }

The (co ndit io n) between the parentheses should evaluate to either t rue o r f alse . When a co ndit io nevaluates true, the co de bet ween t he braces {} (called the st at ement blo ck) executes.

If the first if condition is met, only the first st at ement blo ck executes, and the program continues after thelast clo sing brace , never testing the remaining conditions.

If the first if condition is false, the second (elsif ) condition is tested. If it is true (if t henumber is exactly 21),the block between its braces ($t hewo rd = "OLD ENOUGH";) executes, and the program continues after thelast clo sing brace , skipping the last condition.

If the if and elsif conditions are false, the statement block after the else condition ($t hewo rd = "T OOYOUNG";) executes.

Let's talk more about these co ndit io ns. Did you notice the comparison operators, like <, >, and ==? The firsttwo comparison operators you recognize as being less t han (<) and great er t han (>) . The one you maynot recognize is the do uble equals (==) sign, which tests fo r equality. We don't use a regular equals sign(=), because it is already reserved as the assignment operator. Here is a list o f commonly used comparison

operators:

Comparison Operators for Numbers

Co mpariso n Operat o r

Equal ==

Not Equal !=

Less than <

Greater than >

Less than or equal <=

Greater than or equal >=

Comparison Operators for Strings

When comparing two strings, "less than" means that one string comes bef o re the o ther onealphabet ically. For example, the word "animation" is less than "memory." Here are the comparisonoperators for strings:

comparison operator

Equal eq

Not Equal ne

Less than lt

Greater than gt

Less than or equal le

Greater than or equal ge

Try rewriting the HTML form and Perl script to test fo r strings instead o f numbers.

The while Statement

The while statement repeats the execution o f the statement block for as long as the co ndit io n is true. Sucha process is called a loop. Okay, let's do a while lo o p. Edit your Perl script as shown:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

$a = 0;while ($a < $FORM_DATA{"thenumber"}) {

print $a; print "<br>";

$a++;}

Click Check Synt ax to save it and check the syntax. Preview the HTML file and submit the form. It shouldprint every integer that is less than the number you typed.

Now let's talk about how it works:

OBSERVE:

$a = 0;while ($a < $FORM_DATA{"thenumber"}) {

print $a; print "<br>";

$a++; }

The while statement works a lo t like the if statement. It has a st at ement blo ck that executes when theco ndit io n is true. The difference is that after the statement block is executed, the condition is checked again.If it is true, it executes the block again until the condition is false.

Since you're rechecking the condition after every execution o f the statement block, something has to changeevery time the statement block executes. In the example above, that something is $a. We first gave an initialvalue to $a, $a = 0 , and then we incremented $a by one using $a++; every time the statement block executes.As long as the value o f $a is less than (<) t henumber entered by the user, the loop continues. When $a isequal to t henumber, the looping stops and the program continues at the first line after the last closing brace(} ).

You must be careful to increment and check the condition in a while loop correctly, o r else your program canend up in an infinite loop. This means that your program will execute the while statement fo rever, because itscondition never evaluates to false.

The for Statement

The f o r statement does the same thing as the while statement, it's just written a little bit differently.

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

for ($a = 0; $a < $FORM_DATA{"thenumber"}; $a++) {

print $a; print "<br>";

}

Click Check Synt ax to save this script and check the syntax, then Preview the HTML form. You should getthe same result as you did with the code using the while statement.

The difference between f o r and while statements is the co ndit io nal clause.

OBSERVE:

for ($a = 0; $a < $FORM_DATA{"thenumber"}; $a++) {

The conditional clause for the f o r statement has three parts—the init ial value fo r the index ($a = 0;) , aco mpariso n expressio n to tell where the loop should stop ($a < $FORM_DAT A, and an incrementamo unt ($a++).

The do Statement

The do statement is like the while statement except the condition is at the end. There are two kinds o f doloops—a "do ... while " and a "do ... unt il". The two types o f loops are below. Experiment with both o f themto see the differences.

Here is a do - while loop:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

$a = 0;do {

print $a; print "<br>";

$a++;

} while ($a < $FORM_DATA{"thenumber"});

Here is a do - unt il loop:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

$a=0;do {

print $a; print "<br>";

$a++;

} until ($a >= $FORM_DATA{"thenumber"});

The foreach Statement

The f o reach statement executes a statement block for each element of a list. This is very handy forprocessing an array! Create a new HTML form so we can submit a list to a new Perl script.

With the syntax set to HTML, type the fo llowing text into the Editor below:

<html><body>What are your favorite cities?:<br>

<form action="cgi/foreach.pl" method="POST"> first: <input type=text name=first><br>second: <input type=text name=second><br>third: <input type=text name=third><br>fourth: <input type=text name=fourth><br> fifth: <input type=text name=fifth><input type=submit value="Submit"></form></body></html>

Save this file using the name f o reach.ht ml.

Now we need a script to call when this fo rm is submitted. Create a new file and set the syntax to Perl. Thefo llowing script takes the values from the %FORM_DAT A hash and prints them back to the screen:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

print "Here are your answers:","<br>";print "<ol>";

foreach $element (values(%FORM_DATA)) {

print "<li> $element";

}

print "</ol>";

Click Check Synt ax and save this script using the name f o reach.pl. Then, Preview your HTML file, fill outthe form, and submit it.

Let's take a closer look:

OBSERVE:

foreach $element (values(%FORM_DATA)) {

print "<li> $element";

}

The above code uses the f o reach statement to execute the block o f code in the parentheses each time itgets an $element from the values o f the %FORM_DAT A array.

The (values(%FORM_DAT A)) gets the values from the %FORM_DATA. The $element variable in this caseho lds a single value from the list to be used in the block o f code (note that you can name this variablewhatever you want; I just happened to choose $element). The f o reach statement cycles through the list o fvalues one by one and sticks the single values into the variable for us and then executes the block o f code.

You probably noticed that the list is printed in what seems to be random order. We can change that by sortingthe values before running them through the f o reach loop:

CODE TO TYPE:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

print "Here are your answers:","<br>";print "<ol>";

foreach $element (sort(values(%FORM_DATA))){

print "<li> $element";

}

print "</ol>";

Notice the extra set o f parentheses. This concentric arrangement o f commands within parentheses is called"nesting." The command in the innermost set o f parentheses is executed first and then the interpreter worksits way outward. Click Check Synt ax and save your code, then Preview the HTML file again. This time youshould see the list printed out in alphabetical o rder.

We could also sort the %FORM_DATA hash by its keys instead o f its values.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html \n\n";

$forminfo = <STDIN>;

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value;}

print "Here are your answers:","<br>";print "<ol>";

foreach $elementkey (sort(keys(%FORM_DATA))){

$element = $FORM_DATA{"$elementkey"}; print "<li> $element";

}

print "</ol>";

Click Check Synt ax and save your code, then Preview the HTML file. Here, since we're using the keys, wehave an extra line to extract the values from the hash. When you test this new code with the HTML form, it mayseem like it's random again, but it's not. The keys have been alphabetized, so the fields are printed out in

alphabetical o rder o f fifth, first, fourth, second, and third.

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Functions

Using Functions in PerlSuppose you find yourself copying and pasting the same bit o f code over and over again in a program. At some po intyou'll say to yourself, "I'm do ing the same thing here I did earlier in the program. There has to be a way to reuse thecode from before." The answer? Functions, sometimes called subroutines, are a great way to save time and space inprograms. As an example o f using functions to modularize our code, we'll make a function to parse input data fromHTML forms. Since we learned the "if" statement in the last lesson, we'll make both the GET and POST methods workautomatically.

Create a new file and set the syntax to Perl.

CODE TO TYPE:

#!/usr/bin/perl

&parse_input;&print_header;

print "this should work";

sub parse_input{ $whichmethod = $ENV{'REQUEST_METHOD'}; if($whichmethod eq "GET"){ $forminfo = $ENV{"QUERY_STRING"}; }else{ $forminfo = <STDIN>; }

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value; }}

sub print_header { print "Content-type: text/html\n\n"; }

Click Check Synt ax and save this script using the name subt est .pl and Preview it from the Results window.

To declare functions, we use the keyword sub along with the function name. Then we put the code that the functionexecutes between braces as we did above. To call the function, we use & in front o f the function name:&print _header;

Creating and Using Libraries

Suppose you really do use some code over and over again in just about every program you write. You say toyourself, "Gosh, all this copying and pasting into my programs is getting tedious." We can so lve part o f thatproblem by making a Perl file called a library, then importing the library into new Perl programs. In this section,we'll put the code we've been using to parse input into a Perl library. Create a new file and set the syntax toPerl.

CODE TO TYPE:

#!/usr/bin/perl

sub parse_input { $whichmethod = $ENV{'REQUEST_METHOD'};

if($whichmethod eq "GET"){ $forminfo = $ENV{"QUERY_STRING"}; }else{ $forminfo = <STDIN>; }

@key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value; }}

sub print_header { print "Content-type: text/html\n\n"; }

return 1;

Click Check Synt ax and save this script using the name libcgi.pl.

Notice that the library is made up o f functions and that we put ret urn 1; at the end. This must be placed at thebottom of every library.

The coo l thing about a library is that we can use it to call the subroutines from any Perl script, provided wehave to ld our script to use the library.

Create a new Perl file so that we can see this in action!

CODE TO TYPE:

#!/usr/bin/perl

require "libcgi.pl";

&parse_input;&print_header;

print "this should work!";

Click Check Synt ax and save this script using the name t est lib.pl and Preview it from the Results window.How easy is that? You use require fo llowed by the name of the library in quotes. This tells the Perl script toimport the variables and functions from the library into the current program.

Passing Parameters

Suppose we make a function that prints things to the browser and we'd like to use it in all o f our CGI scripts.We can do that by adding that function to a library. Here's an example. Let's make a function that prints out theHTML body tag and sets a co lor. Go back to the libcgi.pl script and use Save As to create a file calledlibcgi2.pl so that we can add this function.

CODE TO TYPE:

#!/usr/local/bin/perl

sub print_body { print "<body bgcolor=black text=white>"; }

sub parse_input { $whichmethod = $ENV{'REQUEST_METHOD'};

if($whichmethod eq "GET"){ $forminfo = $ENV{"QUERY_STRING"}; }else{ $forminfo = <STDIN>; } @key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value; }}

sub print_header { print "Content-type: text/html \n\n"; }

return 1;

Click Check Synt ax to save this script and check the syntax. Now let's practice using it by making thefo llowing changes to the t est ing.pl Perl script:

CODE TO TYPE:

#!/usr/local/bin/perl

require "libcgi2.pl";

&parse_input;&print_header; &print_body; print "this should work!";

print "</body>";

Click Check Synt ax and save this script and Preview it from the Results window.

Now, suppose you don't always want white text on a black background? Then the library isn't very useful, is it?Fortunately, you can change the function to accept a value—a parameter—that is set when the function iscalled.

Go back to the script libcgi2.pl and make the fo llowing changes:

CODE TO TYPE:

#!/usr/local/bin/perl

sub print_body { print "<body bgcolor=$_[0] text=$_[1]>"; }

sub parse_input { $whichmethod = $ENV{'REQUEST_METHOD'}; if($whichmethod eq "GET"){ $forminfo = $ENV{"QUERY_STRING"}; }else{ $forminfo = <STDIN>; } @key_value_pairs = split(/&/,$forminfo);

foreach $pair (@key_value_pairs){ ($key,$value) = split(/=/,$pair); $value =~ s/\+/ /g; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $FORM_DATA{$key} = $value; }}

sub print_header { print "Content-type: text/html \n\n"; }

return true;

Click Check Synt ax to save this script and check the syntax.

Now, alter the t est lib.pl script that will call the function:

CODE TO TYPE:

#!/usr/local/bin/perl

require "libcgi2.pl";

&parse_input;&print_header; &print_body('blue','red'); print "this should work!";

print "</body>";

Click Check Synt ax and save this script and Preview it from the Results window.

Now isn't that better? You can change the co lors when you call &print _bo dy; by passing ( 'blue ','red') o rwhatever co lors you wish. This is an example o f passing parameters to a function.

When we called the function &print _bo dy, we gave it two arguments: the strings 'blue ' and ' red' . Thesestrings are passed to the &print _bo dy function. These parameters get stored in an array named @_ (well,the name of the array is actually _ (the underscore symbol), but remember arrays' names always begin with@ ). The values in the array are stored in the same order they appear in the parameter list when we call thefunction. Since we called $print _bo dy('blue ','red') , the first element o f the @_ array ($_[0]) is 'blue ' andthe second value ($_[1]) is ' red' .

This is one example o f using parameters. Of course, you you can use them in functions being called from thesame script too , not just in functions within libraries. Create some scripts on your own and practice passing

parameters.

We will pass you now, to the next lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Creating Files

Opening and Writing to FilesRemember in CGI/Perl Lab 4 when we started getting information from web users? We created an HTML form thatcould be used to submit a web survey. That web survey didn't do us much good since all it did was print theinformation back to the users. We need to store the information in a file where we can continue to access it.

Let's begin by creating the HTML file:

With the syntax set to HTML, type the fo llowing text into the Editor below:

<HEAD><TITLE>Example using FORMS</TITLE></HEAD><BODY BGCOLOR=white>

<FORM NAME="mysurvey" ACTION="cgi/writesurvey.pl" METHOD="POST">

What is the URL of your favorite website?<br>

<INPUT TYPE="text" size=40 NAME="favoriteurl" VALUE=""><BR><BR>

Tell me why this is your favorite web site:<BR>

<TEXTAREA COLS=40 ROWS=10 NAME="reason"></TEXTAREA><BR><br>

<CENTER><INPUT TYPE="submit" VALUE="SUBMIT"></CENTER>

</FORM></BODY>

Save this page using the name writ esurvey.ht ml. Then create the Perl script that will be called from the HTML file.

With the syntax set to Perl, type the fo llowing into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&parse_input;&print_header;

open(TOFILE,">infofile.txt");

print TOFILE $FORM_DATA{'favoriteurl'};

print TOFILE "\n\n\n";

print TOFILE "$FORM_DATA{'reason'} \n";

close(TOFILE);

print "File infofile.txt successfully saved";

Click on Check Synt ax and save this script using the name writ esurvey.pl, then Preview the HTML file and submitthe form. Do you think the file was really saved?

To see if it was saved, check out the files saved in your account. Look in your cgi fo lder fo r the file inf o f ile .t xt . Lo adthis file and view the contents.

Let's examine the script more closely. You should notice something new, a function called o pen. It o pens aconnection to a file so we can use it. T OFILE is the first parameter passed to the o pen function. T OFILE is the f ilehandle fo r the file we are opening. We will use the f ile handle whenever we want to access the file. Naming a filehandle is just like naming a variable - you can name it anything you want (within reason). The second parameterpassed to the function specifies both the name of the file to which we will be writing. In this case, the name isinf o f ile .t xt .

The > in front o f the filename tells Perl that we want to write to the file. The > sign looks like an arrow po inting to thefilename that we are using. When the arrow po ints to the filename, we are able to put content into that file.

Note We can put data int o a file using > o r read data o ut o f a file using < . You can open a file fo r bothreading and writ ing by using +< .

Now that we've defined a file handle and declared the file into which we will write, all we have to do is put informationinto the file. We can do this using print , but before we tell Perl what to print, we tell it to print it into f ile handle namedT OFILE. After that, we can print the contents o f $FORM_DAT A{"f avo rit eurl"} and $FORM_DAT A{"reaso n"} intoour file.

Now that we've written to a file, we can read from the file in a new script. We are go ing to make a new Perl script calledreadsurvey.pl. This script doesn't need an HTML form, since we are just go ing to read from the file, process it, andthen print it to the screen.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&print_header;open(FROMFILE,"<infofile.txt");

print "<b><font color=purple>";print "<pre>";

while (<FROMFILE>) {print $_;}

print "</pre>";print "</font></b>";

close(FROMFILE);

Click on Check Synt ax and save this script using the name readsurvey.pl. Then Preview it from the Result swindow.

We use a while lo o p to read data in from the file line by line . That's what while (<FROMFILE>) does; it reads ineach line while there is a line to read. Where does it store what it's read? In this case, it stores it in the "scratchvariable" $_ , which we then print in the statement block. We could have written it like this:

while ($st uf f = <FROMFILE>) {print $st uf f ;}

or even like this:

while (<FROMFILE>) {print ;}

In green we have that same o pen function that we used earlier to write to a file. But this time we read from a fileinstead o f writing to a file. The first thing we changed was the name of the f ile handle to reflect this change. This timewe called our file handle FROMFILE. We could have called it TOFILE, but since we're only reading from the file,FROMFILE is a more accurate name. The last change we made in this code was that instead o f using > before the filename, we used < . Think o f < as being an arrow po inting out o f the file--we're reading information out o f the file now.

Next, we put <pre> tags around the file output (that comes next), so we can see all characters the file contains--including all spaces and newlines.

Now let's combine our two scripts so we can read from and write to the same file in a single Perl script. Go back to thewrit esurvey.pl script and edit it as fo llows:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&parse_input;&print_header;

open(TOFILE, ">infofile.txt");

print TOFILE $FORM_DATA{'favoriteurl'};

print TOFILE "\n\n\n";

print TOFILE "$FORM_DATA{'reason'} \n";

close(TOFILE);

open(FROMFILE, "<infofile.txt");

print "<b><font color=purple>";print "<pre>";

while (<FROMFILE>) {print $_;}

print "</pre>";print "</font></b>";

close(FROMFILE);

Click on Check Synt ax to save this script and check the syntax. Now GO BACK to the HTML page we made at thebeginning o f this lesson and submit the form.

Open a file handle to write to , and write some stuff into that file. Then open another file handle to read into the same fileand output it to a web page.

You're now saving information to files, go ing back and using it again! Let's take it a step further. Your CGI does theexact same thing and gives the exact same result every time it's run. What if instead o f writing and reading the sameline to and from a file every time, you wanted to add more information to that file? Our current Perl script replaces thetext in our file everytime it is run. We really want to keep the o ld information and append our new information to theend. Here's how we do it:

To open a file fo r appending, use >> instead o f > . Make the fo llowing change in blue:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&parse_input;&print_header;

open(TOFILE, ">>infofile.txt");

print TOFILE $FORM_DATA{'favoriteurl'};

print TOFILE "\n\n\n";

print TOFILE "$FORM_DATA{'reason'} \n";

close(TOFILE);

open(FROMFILE, "<infofile.txt");

print "<b><font color=purple>";print "<pre>";

while (<FROMFILE>) {print $_;}

print "</pre>";print "</font></b>";

close(FROMFILE);

Click on Check Synt ax to save this script and check the syntax. Go back and submit the the HTML form - severaltimes this time. Does it append?

Now, you're able to append to your existing information instead o f replacing it. This is how most guestbooks work -new entries do not erase existing entries.

See you in the next learning lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Guestbook

Making a GuestbookIn the previous lesson we learned how to create, write to , and read from a file on the server. We can use thisknowledge to create a guestbook. Our next task is to make it useful and visually appealing.

Let's get started making our very first application in Perl. An application is a program you make that has a usefulpurpose. Before we start writing ANY code, we need to plan how we want our guestbook to work.

T hings we'll need:

1. An HT ML f o rm that takes input from the user. An input fo r the visito r's name, email address, and a bigtextarea for the visito r to write some comments. Since we could get a lo t o f info in our textarea, we'd betteruse the POST method. We'll call it guest f o rm.ht ml.2. A CGI Script to parse out that information, and to put it into a file. Let's go ahead and format thatinformation into HTML before we put it into a file so that we can just print out that file's information later to aweb page. Let's make the email address a link so people looking at our Guestbook can send emailmessages to any person that's signed our guestbook. Also, let's provide a link to see the guestbook entriesright after they fill in the form. We'll call it guest in.pl.3. A place to store the messages. At first we'll simply keep them in an HTML file. Later we'll make a data fileand another CGI script to read in the data and process it.

NoteSomething to look out fo r--a potential problem with files that many people have access to at any time, isthat several people may try to make changes at the same time, causing one or more o f the changes tooverride the o thers. There is a special Perl function called f lo ck that will fix this problem for us. Watch forit later in this lab.

Sounds easy enough, right? Well it should, because we've already practiced do ing almost everything that we're go ingto do now to make our guestbook; we just have to put it all together. Let's get started with the HTML form.

With the syntax set to HTML, type the fo llowing text into the Editor below:

<head><title>Guestbook Sign In Form</title></head>

<body bgcolor=#ffffff>Please fill in this form to sign my guestbook:<br><form name="guestform" action="cgi/guestin.pl" method="POST">Name: <input type=text size=30 name="name"><br>Email: <input type=text size=30 name="email"><br>Comment:<br><textarea cols=50 rows=5 name='comments'></textarea><input type=submit></form></body></html>

Save this HTML form in the top fo lder o f your directory using the name guest f o rm.ht ml. Preview this fo rm so youcan see what the inputs do. Also, take note o f the input variable names. Don't bother submitting the form since wehaven't created the script that will be called yet.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson10

&parse_input;&print_header;

open(TOFILE,">>guestbook.html");

print TOFILE "<pre> \n";print TOFILE "Name: $FORM_DATA{'name'} \n";print TOFILE "Email: $FORM_DATA{'email'} \n\n";print TOFILE "Comments: \n";print TOFILE "$FORM_DATA{'comments'} \n\n";print TOFILE "</pre> <hr>";close(TOFILE);

print "Thanks for signing my guestbook!<br>>";print "<a href=guestbook.html>Click here to see all of the Guestbook Entries</a>";

Click on Check Synt ax and save this script using the name guest in.pl, then Preview the HTML file and submit amessage to the guestbook.

NoteIf you test the form more than once, it may seem like it's not working when it really is. This is becauseyour browser caches the guest bo o k.ht ml file. If you are experiencing this problem, try reloading thepage.

You now have a simple guestbook, but it has some problems both functionally and aesthetically. The rest o f thislesson is devoted to making it more functional, beautiful, and easy to use.

Improving the Guestbook

One problem you might run into occurs when two or more people try to write to the guestbook at the sametime. It may cause messages to be lost. This happens because while each person has the file open andsaves it, only the last one saved will show up; the one saved earlier will be overwritten. Luckily, Perl providesus with a so lution to this problem. There is a Perl function called f lo ck which means file lock. File lockingallows one person (or process) to work safely on a file one at a time. If some other process tries to work onthe file it has to wait until the current process is done. In o ther words, it's first come first serve and the o therswait in line.

Let's fix this problem right now by using f lo ck. Add the blue code to the guest in.pl script:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson10

&parse_input;&print_header;

open(TOFILE,">>guestbook.html");flock("guestbook.html", 2);

print TOFILE "<pre> \n";print TOFILE "Name: $FORM_DATA{'name'} \n";print TOFILE "Email: $FORM_DATA{'email'} \n\n";print TOFILE "Comments: \n";print TOFILE "$FORM_DATA{'comments'} \n\n";print TOFILE "</pre> <hr>";flock("guestbook.html",8);close(TOFILE);

print "Thanks for signing my guestbook!<br>";print "<a href=guestbook.html>Click here to see all of the Guestbook Entries</a>";

This will pro tect the file from interference between different people writing to it. To use f lo ck we call t woparamet ers. The first parameter is the file name you are using to open the file. The second parameter istelling the flock function whether to lock o r unlock the file. 2 means to lo ck t he f ile and 8 means to unlo ckt he f ile .

Another problem we have is that since your web site is go ing to become very popular, your guestbook entrieswill become very large. Even 100 entries on one page is too many to expect our visito rs to download on oneweb page. We need to set some sort o f maximum number o f entries to be saved on this page. For now wewill discard o lder entries as newer ones come along. Later, I will leave it to you to figure out how to save andarchive the o lder entries.

Another thing I like to see on guestbooks is fo r the newest entries to be diplayed at the top o f the page ratherthan the bottom. That way we don't have to scro ll to see the new entries. Also, I think we need to put a link onthe page with the entries so people can respond to o ther entries quickly.

To gain more contro l over the display, we are go ing to have a data file called guest dat a.t xt to ho ld theguestbook entries and we will display t he messages wit h a Perl script rather than simply keeping themon a web page.

Here is a list o f the files we'll need for our guestbook program to help us keep things straight:

guest f o rm.ht ml -- This is the HTML page that contains the form inputs and calls guestin.plguest in.pl -- This is the Perl script that writes to guestdata.txt. Then it calls guestout.pl to displaythe guestbook entries.guest dat a.t xt -- This is the data file that ho lds the guestbook entries. It is written to by guestin.pland read from by guestout.plguest o ut .pl -- This is the Perl script that will read guestdata.txt fo r our guestbook entries and printthem out to the browser.

First, we'll want to change guest in.pl to write to guest dat a.t xt . Let's be clever this time and format the datafile to do what we want. We should read from guest dat a.t xt first so we can keep count o f the number o fentries. This will enable us to write any new entries at the beginning o f the file. Let's go ahead and make thechanges, and we'll talk some more afterwards:

Here is our guest in.pl. Make the appropriate changes in yours.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perlrequire "libcgi.pl"; #library from lesson10

&parse_input;&print_header;

$MAXSAVE = 20; # Create the guestdata.txt file if it does not existif (! -e "guestdata.txt") { open(DATAFILE,">guestdata.txt"); close(DATAFILE);}

open(DATAFILE,"+<guestdata.txt");flock(DATAFILE,2);while(<DATAFILE>){ push(@everyline, $_);}

$longstring = join("",@everyline);@oldentries = split(/<!--NEWENTRY-->/,$longstring);if(@oldentries > $MAXSAVE){pop(@oldentries);}

seek(DATAFILE,0,0);

print DATAFILE "\n";print DATAFILE "<!--NEWENTRY-->\n";print DATAFILE "<pre> \n";print DATAFILE "<b>Name:</b> $FORM_DATA{'name'} \n";print DATAFILE "<b>E-mail:</b> $FORM_DATA{'email'} \n\n";print DATAFILE "<b>Comments:</b> \n";print DATAFILE "$FORM_DATA{'comments'} \n\n";print DATAFILE "</pre> <hr>";

shift(@oldentries);foreach $entry (@oldentries) {print DATAFILE "<!--NEWENTRY-->\n";print DATAFILE $entry;}

truncate(DATAFILE, tell(DATAFILE));

flock(DATAFILE,8); close(DATAFILE);

print "Thanks for signing my guestbook!<br>";print "<a href=guestout.pl>Click here to see all of the Guestbook Entries</a>";

Click on Check Synt ax to save this script and check the syntax.

Before we go through and analyze this script, Preview guest f o rm.ht ml and submit a test message to yourscript. Don't bother clicking the link to see the message because we haven't made guest o ut .pl yet. Click onthe Lo ad button and select guest dat a.t xt from the cgi fo lder.

The file guestdata.txt should like similar to this:

<!--NEWENTRY--><pre> <b>Name:</b> Scott Gray <b>E-mail:</b> [email protected] <b>Comments:</b> This is a test message. Pay attention to the way the messages are seperated. </pre> <hr>

Do not edit this file. After you have looked at it, close it by clicking on the X on the right side o f theguest dat a.t xt tab.

Understanding the new guestin.pl

Let's start with the line that says:

$MAXSAVE = 20;

Here we are setting this variable which we'll use later as the number o f entries want to save and display forpeople to read. You can change this number to whatever you think is appropriate for your purposes.

The next couple o f lines:

o pen(DAT AFILE,"+<guest dat a.t xt ");

f lo ck(DAT AFILE,2);

We are opening data file guest dat a.t xt and then locking it. Notice the use o f the +< operator used to openthe file. This operator opens the file fo r both reading and writing. This will allow us to read the o ld data out o fthe file, and then write the file without having to close then reopen the file. We can also maintain the lock onthe file during the entire process.

Next, read the file line by line and stick each line into the array @everyline using the push function. (The $_is the temp variable Perl reads the lines into).

while(<DAT AFILE>){push(@everyline, $_);}

The next thing we do is:

$lo ngst ring = jo in("" ,@everyline);@o ldent ries = split (/<!--NEWENT RY-->/,$ lo ngst ring);

The jo in function takes the entries o f an array (in this case @everyline ) and forms a single string. The firstparameter the jo in function takes is character. Decide which character(s) you want to use to separate thearray entries in the string. In this case, since we don't want to add any additional data, we don't put anythinginside the quotes. We put this string into the variable $lo ngst ring.

Then we take this string and split it at the occurences o f the <!--NEWENT RY--> substring and put the entriesinto the array @o ldent ries. We are using this weird substring as a delimit er to separate our individualentries in the data file. (You'll see in a little while that we are printing this delimiter string in between each entryin the datafile). When you pick a string as a delimiter, you should choose a string that isn't likely to occur in theentry itself. We are also using HTML comments to hide the delimeter string in the HTML file.

Note Since each entry, including the first, will have <!--NEWENT RY--> at the top o f it, there is a blankentry at the front o f @o ldent ries.

In the fo llowing if statement, we are seeing if the array size is greater than $MAXSAVE. If it is, then we po poff the last entry. In our case, this removes the o ldest entry. We want to remove the o ldest entry because we'llbe adding a new entry soon.

if (@o ldent ries > $MAXSAVE){po p(@o ldent ries);}

The next line is something new:

seek(DAT AFILE,0,0)

Now that we have all o f the o ld entries we want to keep in an array (@oldentries) we are ready to print the newentry at the top o f the file fo llowed by the entries in our @oldentries array. To print something at the beginningof a file that already has data in it, we use the Perl function seek to position the file po inter at the beginning o fthe file. seek takes three parameters: the file handle and the o ffset in bytes relative to where the thirdparameter. The third parameter is where to begin; it can have one o f three values 0 -- the beginning o f the file,1 -- the current po inter position, or 2 -- the end o f the file. (For instance, to set the po inter 24 bytes from theend o f the file we would use seek(DAT AFILE, -24, 2);) . So, we use seek(DAT AFILE,0,0) to start writing atthe beginning o f the file.

The next 8 print statements are exactly the print statements we used in our first verion o f the guestbook withthe addition o f a line printing <!--NEWENT RY--> . We are printing the new guestbook entry at the top o f thefile. The next few lines print the entries we want from @oldentries.

shif t (@o ldent ries);f o reach $ent ry (@o ldent ries) {print DAT AFILE "<!--NEWENT RY-->";print DAT AFILE $ent ry;}

Remember that blank entry we talked about ealier? We want to get rid o f that so it's not added into ourguestbook every time. The shif t statement works exactly like po p except we remove the first item in@oldentries instead o f the last. The rest is just printing the o ld guestbook entries to the file again. Notice weare putting the <!--NEWENTRY--> back in.

Since we are writing to a file that has possibly been written to before, there might be o ld entries in the filebeyond our current po inter position. To get rid o f all o f the extra baggage from where we last printed to the endof the file, we use the t runcat e function. It "truncates" or erases all the data from an o ffset to the end o f thefile.

t runcat e(DAT AFILE, t e ll(DAT AFILE));

The first parameter is obviously the file handle for the file. The second parameter is the file position you wantto truncate from. In our case, we are using the function t e ll to "tell" us the location o f the po inter o f the currentfile position.

That's it fo r guest in.pl. Now that we've got that handled, let's...

Make guestout.pl to Read the Data

All we have to do is make a CGI script to read in the data file and print out the Guestbook so we can read itfrom a webpage. This program will be called guest o ut .pl:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

open(FROMFILE,"<guestdata.txt");

print <<ENDHEADER;

<head><title>My Guestbook</title></head><body bgcolor=dcdcdc><center><h1>My Guestbook</h1>

<a href=../guestform.html>[Post a message]</a> <a href=guestout.pl>[Refresh]</a> </center><hr><h2>Prior Messages</h2>

ENDHEADER

while (<FROMFILE>) {print;}

close(FROMFILE);

Click on Check Synt ax and save this script using the name guest o ut .pl.

This script should be fairly straight fo rward. The only thing new we put in here is something called a heredo cument . After the print statement insert << ENDHEADER; which is called an end t o ken. This is thebeginning o f the here document. End tokens begin with two "less than" signs and a string o f your cho ice. Theprint statement will print out everything between << ENDHEADER; and ENDHEADER;. This is so we don'thave to write all o f those print statements on every line. Make sure ENDHEADER; is all the way to the left on aline, o therwise Perl won't recognize it correctly.

Now the guestbook should be complete. You should test it and customize as you need. Later on, when wego through the SQL lessons, we'll find a much easier and more powerful too l fo r do ing things likeguestbooks.

You're do ing great! See you at the next learning lab!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Chat

Make a Web ChatIn the previous lesson we learned how to create a web guestbook. A web chat is merely a guestbook that refreshesmore o ften and is easier to use. Thankfully, we did all o f the hard work in the last lesson. In this lesson, all we have todo is change some HTML and rearrange some things to make this into a useful web chat.

Let's get right to it then shall we? I am assuming that you've already been through lesson 12. If you haven't, please doit now because everything we are do ing here will depend on the things you learned in that lesson.

Create the fo llowing frameset:

With the syntax set to HTML, type the fo llowing text into the Editor below:

<frameset rows=*,200>

<frame src=guestout.pl name=messages><frame src=guestform.html name=userinput></frameset>

Save this page in your top directory as chat set .ht ml, then Preview the file. You'll see the beginnings o f what we aretrying to accomplish. Notice it doesn't work much like a web chat. We need to make a few changes before it takesshape.

What do we want it to do? Here is a list o f things we want to include to make it act like a chat:

When we write our message in the bottom frame, we only want the top frame to change.When we submit our message, we want it to change the messages in the top frame.We need some mechanism for REFRESHING the chat so we can see the new messages.We should enable the user to contro l the refresh rate.

I'll leave it up to you to make it look nice.

WARNINGI'm go ing to be asking you to change the same files you made in the last lesson. If you want tokeep the work you've already done, then you should make copies o f guest o ut .pl, guest in.pl,guest f o rm.ht ml, and guest dat a.t xt . OR you should choose names for your files that aredifferent from the ones used in this lesson.

The first and easiest change we can make is to guest f o rm.ht ml. We can add the target attribute so that the output o fthe guest o ut .pl script is in the top frame. Open up your copy o f guest f o rm.ht ml and make the fo llowing changes:

With the syntax set to HTML, type the fo llowing text into the Editor below:

<head><title>Chat Form</title></head>

<body bgcolor=#ffffff>Please fill in this form to chat:<br><form name="guestform" action="cgi/guestin.pl" target="messages" method="POST">Name: <input type=text size=30 name="name"><br>Email: <input type=text size=30 name="email"><br>Comment:<br><textarea cols=50 rows=5 name='comments'></textarea><input type=submit></form></body>

Save this file using the name guest f o rm.ht ml in your top directory. Once you've done that, Preview chat set .ht ml

and try it out (you should notice something slightly annoying with it).

When we chat, we don't want to have to click the link that comes up do we? We can fix that by making changes to yourguest in.pl so it prints out the messages. In o ther words, fo r chatting purposes we don't need guest o ut .pl. We'll justmove the printing that guest o ut .pl did into guest in.pl. Open up your copy o f guest in.pl from the last lesson andchange it to look like the fo llowing (The stuff in blue represents the printing statements from guest o ut .pl. Make sureyou erase the printing that guest in.pl used to do.):

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perlrequire "libcgi.pl"; #library from lesson10

&parse_input;&print_header;

$MAXSAVE = 20;flock("guestdata.txt",2);open(FROMFILE,"<guestdata.txt");while(<FROMFILE>){ push(@everyline, $_); }

$longstring = join("",@everyline); @oldentries = split(/<!--NEWENTRY-->/,$longstring);

if(@oldentries + 1 >= $MAXSAVE){ pop(@oldentries); }

close(FROMFILE);open(TOFILE,">guestdata.txt");

seek(TOFILE,0,0);

print TOFILE "\n"; print TOFILE "<!--NEWENTRY-->"; print TOFILE "<pre> \n"; print TOFILE "<b>Name:</b> $FORM_DATA{'name'} \n"; print TOFILE "<b>E-mail:</b> $FORM_DATA{'email'} \n\n"; print TOFILE "<b>Comments:</b> \n"; print TOFILE "$FORM_DATA{'comments'} \n\n"; print TOFILE "</pre> <hr>";

shift(@oldentries);foreach $entry (@oldentries) { print TOFILE "<!--NEWENTRY-->"; print TOFILE $entry;

}

truncate(TOFILE, tell(TOFILE));

close(TOFILE); flock("guestdata.txt",8);

open(FROMFILE,"<guestdata.txt");

print <<ENDHEADER;

<head> <title> My Chat </title> </head> <body bgcolor=dcdcdc> <center> <h1>My CHAT</h1>

<a href=../guestform.html>[Post a message]</a> <a href=guestout.pl>[Refresh]</a> </center> <hr> <h2>Prior Messages</h2>

ENDHEADER

while (<FROMFILE>) { print; }

close(FROMFILE);

Click on Check Synt ax to save this script and check the syntax.

When you're ready, go back to chat set .ht ml and use your chat. I think you'll find that we're really close to having agood chat. You should be able to reformat the output so it's more like a chat than a guestbook. I'm go ing to leave thatto you to work on at the end o f this lesson.

Auto Refresh

Now we need a way to make the chat refresh so we can see the new messages, and for our users'convenience, we should make it refresh automatically and even better, maybe we should let each userdetermine how often it refreshes.

We can make our chat refresh using javascript. We'll need to make a function with a set T imeo ut to callguest o ut .pl (not guest in.pl). We need to add the javascript to the guest in.pl script. The javascript is inred and blue below:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perlrequire "libcgi.pl"; #library from lesson10

&parse_input;&print_header;

$MAXSAVE = 20;flock("guestdata.txt",2);open(FROMFILE,"<guestdata.txt");while(<FROMFILE>){ push(@everyline, $_); }

$longstring = join("",@everyline); @oldentries = split(/<!--NEWENTRY-->/,$longstring);

if(@oldentries + 1 >= $MAXSAVE){ pop(@oldentries); }

close(FROMFILE);open(TOFILE,">guestdata.txt");

seek(TOFILE,0,0);

print TOFILE "\n"; print TOFILE "<!--NEWENTRY-->"; print TOFILE "<pre> \n"; print TOFILE "<b>Name:</b> $FORM_DATA{'name'} \n"; print TOFILE "<b>E-mail:</b> $FORM_DATA{'email'} \n\n"; print TOFILE "<b>Comments:</b> \n"; print TOFILE "$FORM_DATA{'comments'} \n\n"; print TOFILE "</pre> <hr>";

shift(@oldentries);foreach $entry (@oldentries) { print TOFILE "<!--NEWENTRY-->"; print TOFILE $entry;

}

truncate(TOFILE, tell(TOFILE));

close(TOFILE); flock("guestdata.txt",8);

open(FROMFILE,"<guestdata.txt");

print <<ENDHEADER;

<head><title>My Chat</title><br><br>

<script>

function callrefresh(){

time = 15; millisec = parseInt(time*1000);

setTimeout('refresh()',millisec);

}

function refresh(){

this.location.href = "guestout.pl";

}

</script>

</head><body bgcolor=dcdcdc onload=callrefresh();><center><h1>My CHAT</h1>

<a href=../guestform.html>[Post a message]</a><a href=guestout.pl>[Refresh]</a></center><hr><h2>Prior Messages</h2>

ENDHEADER

while (<FROMFILE>) { print; }

close(FROMFILE);

Click on Check Synt ax to save this script and check the syntax.

We need to add the same JavaScript to guest o ut .pl. Open your version o f guest o ut .pl from lesson 12,and make the fo llowing changes:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

open(FROMFILE,"<guestdata.txt");

print <<ENDHEADER;<br><br><head><title>My Chat</title><br><br>

<script>

function callrefresh(){

time = 15; millisec = parseInt(time*1000);

setTimeout('refresh()',millisec);

}

function refresh(){

this.location.href = "guestout.pl";

}

</script>

</head>

<body bgcolor=dcdcdc onload=callrefresh();>

<center> <h1>My CHAT</h1>

<a href=../guestform.html>[Post a message]</a> <a href=guestout.pl>[Refresh]</a> </center> <hr> <h2>Prior Messages</h2>

ENDHEADER

while (<FROMFILE>) { print; }

close(FROMFILE);

Click on Check Synt ax to save this script and check the syntax.

The Javascript will refresh that chat every 15 seco nds. Investigate for yourself how to change this value.

Now open chat set .ht ml and make sure that your chat works.

Hints for making it better

For instructional reasons we used code and formatting left over from the previous lesson. As I said before, Iwill leave it to you to make your chat better, but I'm not opposed to giving you some suggestions. Behold, myideas to make the chat better:

Improve the display by eliminating the large space and <hr> between the messages. Also, you cansave room by putting the name and the message content on the same line and leaving o ff e-mailaddresses.Add an input in the bottom frame (guest f o rm.ht ml) so users can set their own refresh rates. Youcan use javascript to access this value from guest in.pl and guest o ut .pl.Make the code easier to change and more concise by putting the code that opens and prints to thescreen in a Perl library. Then call a function from guest in.pl and guest o ut .pl.Change the co lors o f the background, text, etc.Use Perl to ensure that HTML cannot be used by chatters. This is important as chatters can ruinchat sessions by hogging the output with HTML. To do this, simply search the document fo r < and> and replace them with &lt; and &gt;.

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

Running External Processes on the Server

How to Send E-mail with CGIOne good thing about Perl is that we can use it on the server to execute external programs. External programs existoutside o f your Perl program and are programs that can run indepently o f CGI. One thing most people want to do issend e-mail fo r notification, or get the dat e from the machine. Perl provides several different mechanisms foraccessing and using such programs and commands. In this lesson, we'll see how to execute these commands andmost importantly you'll see how to send mail with a CGI script using Perl. We'll use the most useful o f these methods—backquotes and opening processes as file handles.

Using Backquotes

If we place a command name between backquotes (`), we can get the output o f an external program. Let'swork on an example where we access the dat e program usually installed on Unix systems. Notice that weare using backquotes and NOT single quotes. The backquote key is usually on the upper left side o f yourkeyboard, right above the tab key. Below you'll see `dat e`; those are backquotes before and after the datecommand.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&print_header;

$the_date=`date`;

print $the_date;

Click Check Synt ax and save this script using the name dat e.pl, and Preview it from the Result s window.

The script will print the date on the server where your account is stored. (If the date or time is not hat youexpect, remember that our servers are in the central time zone.)

Backquotes can be useful when you need to co llect output from an external program. It takes Perl some effortto co llect this output though, so don't use the backquotes unless you definitely need that output. Most outputfrom external programs has newline characters that don't look right in HTML. For example, the ls command inUnix gives a directory listing (like the dir command in DOS (don't panic)). Here is an example where you mightwant to use Perl to make it look better. The output fo r the ls command can look like this when using thecommand line in Unix (you can learn more about the ls command in the Unix course if you like):

It will look something like this

total 94drwxr-xr-x 2 tour webusers 1024 May 9 12:13 .drwxr-xr-x 8 tour webusers 2048 May 9 11:37 ..-rw-r--r-- 1 tour webusers 39 May 9 12:13 .errlog-rwxr-xr-x 1 tour webusers 364 Jun 29 2000 array.pl-rwxr-xr-x 1 tour webusers 4433 Jan 20 2000 cgi-lib.pl-rwxr-xr-x 1 tour webusers 2765 Jan 20 2000 counter.pl-rwxr-xr-x 1 tour webusers 641 May 9 10:55 foreach.pl-rwxr-xr-x 1 tour webusers 3182 Jan 20 2000 guest.pl-rw-r--r-- 1 tour webusers 505 May 9 11:56 guestbook.html-rwxr-xr-x 1 tour webusers 686 May 9 11:55 guestin.pl-rw-r--r-- 1 tour webusers 40 Mar 22 12:58 infofile.txt-rwxr-xr-x 1 tour webusers 680 May 9 11:12 libcgi.pl-rwxr-xr-x 1 tour webusers 590 Mar 22 11:43 myscript.pl-rwxr-xr-x 1 tour webusers 611 Mar 22 12:25 officers.pl-rwxr-xr-x 1 tour webusers 19 Jan 12 11:44 quick.html-rwxr-xr-x 1 tour webusers 19 Jan 12 11:45 quick2.html-rwxr-xr-x 1 tour webusers 355 Mar 22 12:53 readsurvey.pl-rwxr-xr-x 1 tour webusers 468 May 9 09:39 statement.pl-rwxr-xr-x 1 tour webusers 473 May 9 10:29 statements.pl-rwxr-xr-x 1 tour webusers 737 Mar 22 12:31 subtest.pl-rwxr-xr-x 1 tour webusers 184 May 9 12:13 test.pl-rwxr-xr-x 1 tour webusers 9 Jan 12 12:13 testing.html-rwxr-xr-x 1 tour webusers 590 Mar 22 11:44 variables.pl-rwxr-xr-x 1 tour webusers 137 Mar 22 11:46 websurvey.pl-rwxr-xr-x 1 tour webusers 539 May 8 15:47 websurvey2.pl-rwxr-xr-x 1 tour webusers 628 Mar 22 12:57 writesurvey.pl

Don't worry if you don't understand what this output means. The important part is the filename, which isalways listed in the rightmost co lumn.

When we print this information to the browser from a CGI script, it looks bad. Here, try it fo r yourself:

In PERL MODE, Type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&print_header;

$output = `ls -la`;

print $output;

Click Check Synt ax and save script using the name dir.pl and Preview it from the Result s window.

That's too hard to read! We can fix that, using a <pre> tag, like so:

With the syntax set to Perl, Type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&print_header;

$output=`ls -la`;

print "<pre>";

print $output;

print "</pre>";

Click Check Synt ax and save this script and Preview it from the Result s window..

Using Processes as Filehandles

Using backquotes to run a process is fine if we need to gather the output o f a program, but what if we need tosend information to a program? One such program is sendmail. When we send e-mail, we have to send allo f this to the sendmail program: the message, the recipient address, the address o f the sender, the subject o fthe message, and maybe even some cc (carbon copy) recipient addresses. We'll have to use a file handle tosend information to the sendmail program.

You may wonder why we would use a file handle to send information to a program. This is because in Unix,programs usually accept input from a standard file handle called STDIN, or standard input. Unix programsalso usually output information on a file handle called STDOUT, or standard out. We can open a file handle inPerl to write data to a program's standard input file handle or read data from a program's standard output filehandle.

Let's use the file handle method to do the exact same thing we did above with dat e.pl. Create a new file andset the syntax to Perl. This is an example o f opening the file handle to read in the output o f a process.

The vertical bar (|) is usually located at the upper right side o f your keyboard, below the Backspace key.

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perl

require "libcgi.pl"; #library from lesson 10

&print_header;

print "<pre>";

open(DATE,"date|");

$date = <DATE>;

print $date;

close(DATE);

print "</pre>";

Click Check Synt ax and save this script using the name dat e2.pl. The output o f this Perl program should beexactly like the output o f dat e.pl.

Notice the | follows the process name. This indicates the process is open for reading. The vertical bar is calleda pipe. If we want to open the process for writing then we'll put the pipe before the process name. The pipe isthe connection between the Perl file handle and the program's standard output (or standard input) file handle.

Now let's make a script to send e-mail. First we will make a web page with a form that will take the visito r'sname and e-mail address. Then we'll make a Perl cgi script to send the visito r a thank you message.

Note If you don't already have a gmail account, you'll need to get one to complete this example. Toget one, go to mail.google.com.

First the html fo rm:

With the syntax set to HTML, type the fo llowing text into the Editor below:

<HTML><title>The form </title> <body>

<form name="info" action="cgi/thankyou.pl" method="POST">

Your name: <input type=text name='name' size=14>

Your e-mail address: <input type=text name='address'>

<input type=submit value=submit>

</form>

Save this file as t hankyo u.ht ml.

Now for the Perl cgi program:

With the syntax set to Perl, type the fo llowing text into the Editor below:

#!/usr/bin/perlprint "Content-type: text/html\n\n";

use Net::SMTP::SSL;sub send_mail {my $to = $_[0];my $subject = $_[1];my $body = $_[2];

my $from = '[email protected]';my $password = 'your_password';

my $smtp;

if (not $smtp = Net::SMTP::SSL->new('smtp.gmail.com', Port => 465, Debug => 0)) { die "Could not connect to server\n";}

$smtp->auth($from, $password) || die "Authentication failed!\n";

$smtp->mail($from . "\n");my @recipients = split(/,/, $to);foreach my $recp (@recipients) { $smtp->to($recp . "\n");}$smtp->data();$smtp->datasend("From: " . $from . "\n");$smtp->datasend("To: " . $to . "\n");$smtp->datasend("Subject: " . $subject . "\n");$smtp->datasend("\n");$smtp->datasend($body . "\n");$smtp->dataend();$smtp->quit;}

# Send away!&send_mail('$to', 'CGI/Perl email test ', '"Thank you for visiting my website!"');

print("Message sent\n");

Make sure to put your email address in place o f [email protected] and your password in place o fyour_password.

Click on Check Synt ax and save this script using the name t hankyo u.pl

Try this script out—Preview t hankyo u.ht ml to send an email to yourself! If you don't see an email in yourinbox, be sure to check your junk email/spam fo lder; it might've been redirected there.

...and good luck on your final pro ject, coming up next!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.