New Users: Quick Perl CGI

Revision as of 21:33, 17 September 2008 by Ric (talk | contribs)

Quick Perl (CGI) 3.5-Apollo

So you have installed Uniform Server, performed all tests and it’s working. Where is the on off switch for PERL? The answer is straightforward, it’s already running, any page with a .pl extension placed in folder *\Uniform Server\udrive\cgi-bin is routed to the Perl compiler and executed. I have written this page purely for orientation with reference to Uniform Server, it is not intended in any way to teach you Perl you can find better material on the Internet. Its sole purpose to get you up and running with Perl on Uniform Server 3.5-Apollo.

There are two faces of Perl, CGI for dynamic web pages and CLI for batch programming. This page covers CGI, if you are interested in CLI check out the link.

Introduction

The Perl engine installed on Uniform Server is version v5.8.8 provided by ActiveState it is not only very powerful but extremely compact. If you have read Quick PHP CGI I have tried to make quick Perl's content similar.

Top

Perl Syntax

The following are very basic HTML pages producing identical output. They show how to use Perl, save the pages as test1.pl and test2.pl place both in folder *\Uniform Server\udrive\cgi-bin. All your Perl pages are placed in this (cgi-bin) folder.

Type the following into your browser address bar:

  • http://localhost/cgi-bin/test1.pl -- Displays test1.pl
  • http://localhost/cgi-bin/test2.pl -- Displays test2.pl
  test1.pl
#!/usr/bin/perl

print "Content-type: text/html\r\n\r\n";
print "<HTML>\n";
print "<HEAD><TITLE>Hello World!</TITLE></HEAD>\n";
print "<BODY>\n";
print "<H2>Hello World!</H2>\n";
print "</BODY>\n";
print "</HTML>\n";
exit (0);

Every Perl page must have the first line as shown it is referred to as the shebang #!/usr/bin/perl informs Apache where to find Perl. Make sure there are no spaces before # otherwise the path will not be found.
The difference between the two programs is in terms of style. Test1.pl uses the print function and prints every line individually. It encloses each line in quotes and each line requires terminating with a semi column.

 

  test2.pl
#!/usr/bin/perl

print "Content-type: text/html\r\n\r\n";
print <<END_long_text;</nowiki'''><br> <nowiki><HTML>
<HEAD><TITLE>Hello World!</TITLE></HEAD>
<BODY>
<H2>Hello World!</H2>
</BODY>
</HTML>
END_long_text
exit (0);

Every web page must have a Content-type of text/html of great importance are the next characters \r\n\r\n they terminate the header.
Test2.pl uses a different style that allows you to print a block of text retaining its format. This is referred to as “here document” starts with two less-than characters and a word; this word is also used to delimit the block and must not have a semicolon after it.

Note: Older versions of Perl use \n\n instead of \r\n\r\n for Windows \n\n is the correct one to use it is more compliant.

Top

Page building

With Perl's print command you are building a page from scratch the resulting page is passed onto the server. Looking at the above script in more detail:

Line Comments
#!/usr/bin/perl shebang First line of every Perl script. Make sure there are no spaces before #
print "Content-type: text/html\r\n\r\n"; Every HTML document requires a mime type Content- type: text/html<CRLF><CRLF>

This tells the client's browser (and web server) how to interpret the information that follows it.
In Perl the <CRLF> code is described by the escape sequence \r\n\r\n, hence the line:
Content-type: text/html\r\n\r\n (Windows use \n\n)

print "<HTML>\n"; <HTML> Start tag for an html page
print "<HEAD><TITLE>Hello World!</TITLE></HEAD>\n"; Header and page title tags
print "<BODY>\n"; Page body tag start of page content
print "<H2>Hello World!</H2>\n"; Page content in this case an h2 header displaying Hello World
print "</BODY>\n"; Closing body tag
print "</HTML>\n"; Closing html page tag
exit (0); After the Perl script ends, Apache collects the "return value" of the program it then knows if there was an error or not. If the return value is zero, everything is okay. If the return value is not zero, Apache will display an error and log the error to the log files.

In Perl, you can specify what the return value of a CGI program with the exit keyword:

exit (0); - normal exit code
exit (1): - something serious happened

Top

Include external files -1

Perl has so many ways of doing this as to what method you choose depends on your application. Coming from PHP you most likely to want to include headers, footers, functions and configuration data. My preferred method is to use require "some_path/file_name.pl" each of these files set functions and or variables, nothing cleaver just means I have one file structure. To give you an idea what I am talking about lets look at an example.

Suppose I want to use this master page as a template with header, content and footer. The first thing to do is chop it up into the appropriate parts:

<html>

<head>
<title>Test 1</title>
</head>
<body>

Main Page
<table width="100%" border="1" cellpadding="0" cellspacing="0">

<tr><td bgcolor="#000000"> </td></tr>
<tr><td align="center" bgcolor="#CCCCCC"><h2>HEADER</h2></td></tr>
<tr><td bgcolor="#000000"> </td></tr>
</table>

Header
<table width="100%" border="1" cellspacing="0" cellpadding="0">

<tr><td bgcolor="#96FE9D"><p><strong>Some content</strong></p>
<p><strong>More Content</strong></p></td></tr>
</table>

Content
<table width="100%" border="1" cellpadding="0" cellspacing="0">

<tr><td bgcolor="#000000"> </td></tr>
<tr><td align="center" bgcolor="#CCCCCC"><h3><font color="#FF0000">Footer</font></h3></td></tr>
<tr><td bgcolor="#000000"> </td></tr>
</table>

Footer
</body>

</html>

Main Page

Convert the above into four files as follows: (Save the pages as as test3.pl , inc_header.pl , inc_content.pl and inc_footer.pl

I have highlighted the additional content required to create each file. The main page uses require to load each file these statements are place just below the shebang. The advantage of this method, I can use a file names that are different to the functions they contain. Once all three files are loaded I have three functions that can be used any where in my script.

I call each function in turn using its name and a pair of brackets, for example header() will print the header content.


</table>
END_long_text
}
1; # return TRUE statement

#!/usr/bin/perl

require "inc_header.pl";
require "inc_content.pl";
require "inc_footer.pl";
print "Content-type: text/html\r\n\r\n";
print "<HTML>\n";
print "<HEAD><TITLE>Test 1</TITLE></HEAD>\n";
print "<BODY>\n";
header();
content();
footer();
print "</BODY>\n";
print "</HTML>\n";
exit (0);

Main Page
test3.pl
sub header {

print <<END_long_text;
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr><td bgcolor="#000000"> </td></tr>
<tr><td align="center" bgcolor="#CCCCCC"><h2>HEADER</h2></td></tr>
<tr><td bgcolor="#000000"> </td></tr>
</table>
END_long_text
}
1; # return TRUE statement

Header
inc_header.pl
sub content {

print <<END_long_text;
<table width="100%" border="1" cellspacing="0" cellpadding="0">
<tr><td bgcolor="#96FE9D"><p><strong>Some content</strong></p>
<p><strong>More Content</strong></p></td></tr>
</table>
END_long_text
}
1; # return TRUE statement

Content
inc_content.pl
sub footer {

print <<END_long_text;
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr><td bgcolor="#000000"> </td></tr>
<tr><td align="center" bgcolor="#CCCCCC"><h3><font color="#FF0000">Footer</font></h3></td></tr>

 
Footer
inc_footer.pl

Each of the included files can be named anything you like so long as they have the .pl extension. Contents of each file in this example is one function. Each function (sub) has a unique name, and use the short-cut print command to print the HTML we require. At the end of each file you must include 1; this keeps Perl happy, it indicates the content is valid.

Type the following into your browser address bar:

http://localhost/cgi-bin/test3.pl -- Displays test3.pl

Top

Include external files -2

Looking at the above you can see our template page is modular, uses three files, each containing a small package of information to create the final page. Perl modules and packages allow you to directly use a file name without the extension in a require statement. What is really neat you can then use that require name in any location and the code is inserted, similar to PHP's include. The above example requires minor modifications, each include file has an extension of .pm indicating a Perl module its content are defined as a module.

The following shows how to convert the above into module files: Save the pages as as test4.pl , header.pm , content.pm and footer.pm

#!/usr/bin/perl

print "Content-type: text/html\n\n";
print "<HTML>\n";
print "<HEAD><TITLE>Test 1</TITLE></HEAD>\n";
print "<BODY>\n";
require header;
require content;
require footer;
print "</BODY>\n";
print "</HTML>\n";
exit (0);

Main Page
test4.pl
package header;

print <<END_long_text;
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr><td bgcolor="#000000"> </td></tr>
<tr><td align="center" bgcolor="#CCCCCC"><h2>HEADER</h2></td></tr>
<tr><td bgcolor="#000000"> </td></tr>
</table>
END_long_text

Header
header.pm
package content;

print <<END_long_text;
<table width="100%" border="1" cellspacing="0" cellpadding="0">
<tr><td bgcolor="#96FE9D"><p><strong>Some content</strong></p>
<p><strong>More Content</strong></p></td></tr>
</table>
END_long_text

Content
content.pm
package footer;

print <<END_long_text;
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr><td bgcolor="#000000"> </td></tr>
<tr><td align="center" bgcolor="#CCCCCC"><h3><font color="#FF0000">Footer</font></h3></td></tr>
<tr><td bgcolor="#000000"> </td></tr>
</table>
END_long_text

Footer
footer.pm

There are restrictions, package name must match the file name and the file must have an extension of .pm for this example all files are placed in the cgi-bin folder.

Type the following into your browser address bar:

http://localhost/cgi-bin/test4.pl -- Displays test4.pl

Top

Perl Modules

Where are Modules Installed? On Uniform Server Perl looks in the folder *\Uniform Server\udrive\usr\lib in this folder you will find common pms such as warnings.pm, strict.pm more importantly lib.pm

lib.pm Allows you to define a location for your own Perl modules. For example create a folder my_pms in the library folder *\Uniform Server\udrive\usr\lib and copy the above three pms (header.pm, content.pm and footer.pm) into it. Make the following changes to test.4.pl and save as test5.pl

Note: Delete the three pm's in cgi-bin to make sure they are picked up from only your my_pms folder.

#!/usr/bin/perl

use lib '/usr/lib/my_pms';
print "Content-type: text/html\n\n";
print "<HTML>\n";
print "<HEAD><TITLE>Test 1</TITLE></HEAD>\n";
print "<BODY>\n";
require header;
require content;
require footer;
print "</BODY>\n";
print "</HTML>\n";
exit (0);

Main Page
test5.pl

The highlighted line uses the lib.pm module which adds the path /user/link/my_pms to @INC array. This array stores the default paths set at run time by the configuration file and user defined paths.

Type the following into your browser address bar:

http://localhost/cgi-bin/test5.pl -- Displays test5.pl

There should be no differences in the displayed result between test 4.pl and test 5.pl all that has changed is the location of the three pms. Note: Test.4.pl will fail because of the deleted pms.

Top

Problems

The chances are the above test will fail, I am no expert with Perl but I do know if a module does not match the executable things fail. There are such a vast number of Perl modules on the Internet keeping these up to date is a nightmare. To show you what I mean run Perl from a command prompt using perl -V this is what you may see displayed:

G:\B1_server\Uniform Server\udrive\usr\bin>perl -V
Perl lib version (v5.8.7) doesn't match executable version (v5.8.8) at G:/B1_server/Uniform Server/udrive/usr/lib/Config.pm line 46.
Compilation failed in require.
BEGIN failed--compilation aborted.
G:\B1_server\Uniform Server\udrive\usr\bin>

My solution to this download AS package from Activate State look for Column ActivePerl 5.8.8.820 Section Windows (x86) file AS Package it is big zip file 15.7M once unzipped you can then manually install Perl. Not recommended so do not do it. Locate the folder perl/lib and copy every file that matches ones in Uniserver's usr/lib about nine files are updated.

Run perl -V again you will receive a message similar to this:

G:\B1_server\Uniform Server\udrive\usr\bin>perl -V
Can't locate Config_heavy.pl in @INC (@INC contains: G:/B1_server/Uniform Server/udrive/usr/lib .) at G:/B1_server/Uniform Server/udrive/usr/lib/Config.pm line 70.
G:\B1_server\Uniform Server\udrive\usr\bin>

It cannot find the file Config_heavy.pl hence copy that across as well.

OK point taken why not copy all the files across! Well you could but size 2M as opposed to 0.5M keep it small.

Run perl -V again this time the script will run, a vast amount of information is displayed you can ignore all the lines please-run... of real importance is this line:

@INC: G:/B1_server/Uniform Server/udrive/usr/lib

It shows all the default paths to the pms, note the ones you add are dynamically created and removed hence will not show up here.

I very rarely use pms because I am more than happy with the core Perl module, however if you do need a specific pm just install that one, this method will save you a lot of space.

Top

Download

If all you use are the core pms in /usr/lib no need to go to the trouble of the above check put this page to download the updates. You may be interested in the combined updates page for 3.5-Apollo.

If you are using any other pm's you now know where to find updated versions always check for correct matching versions.

Note: The following page may be of interest, its part of a mini server series dedicated to running a single aspect of a server. This mini server runs Perl 5.10 again a very limited number of modules, download size 1MB, extracted size 3M well I did say mini server, however it is running the Apache 2.2.8 core.

What next

I mentioned the two faces of Perl, lets press on to the second, CLI or batch file replacement.

This for me! Is the real power of Perl, I hope you find it of some use.

Quick Perl CLI


  Ric