Introduction

Mason is a Perl module which works with apache's mod_perl to present web pages with embedded Perl. It's a nice alternative to PHP if you know and love Perl. To use mason with this tutorial, you need to do three or four things:

  1. install HTML::Mason from CPAN. Be warned, HTML::Mason requires quite a few other modules, so you may want to use CPAN.pm to auto-install.
  2. install mod_perl. How you do this is system dependent, and you do need to be running apache.
  3. read the first two or three chapters of The Mason Book, which is published by O'Reilly but also free on-line and easily downloadable. You could try and do it "concurrently" if you want. They are short chapters and the book is nicely written IMO (much thanks to Dave Rolsky and Ken Williams for making it available!) There are very few mason resources for beginners on the net, which is why I decided to write this tutorial; to that end, I will not re-iterate the basics of mason as described in "the book" but instead present some complementary material. The tutorial presumes you at least understand the component based structure of a mason site, which is detailed in chapter 1 of "the book".
  4. we're also going to use an SQLite3 database, managed via Perl's DBI and DBD::SQLite modules, so you need those too.

There is a widely used Perl web application framework, Catalyst, akin to Ruby on Rails, Django, or ASP.NET, which uses mason. While the tutorial demo resembles a simple MVC web framework app in so far as it is based around an SQL database, it does not involve Catalyst, and I don't use the MVC vocabulary to describe it. One of the goals of the tutorial is to demonstrate how SQL and AJAX can be used in conjunction with mason; while the examples are quite simple, I do presume some familiarity with both. However, you don't don't have to know anything about MVC or web-app frameworks.

The .htaccess file, and related concerns

The Mason Book includes instructions for how to configure apache properly, either using mod_perl, or with plain cgi. Mod_perl is preferable, and the ideal is to do the configuration in httpd.conf. However, in keeping with my intention to "present alternatives", the demo used in the tutorial instead uses an .htaccess file like this:

PerlRequire /var/www/html/zoodemo/apache-perl.pl
SetHandler perl-script
PerlHandler HTML::Mason::ApacheHandler
AddType text/html mhtml
AddType text/html comp
AddHandler perl-script mhtml comp
<Files *>
Header set Cache-Control: "private, pre-check=0, post-check=0, max-age=0"
Header set Expires: 0
Header set Pragma: no-cache
</Files> 

The "Files" section is just a standard no-cache bit for use in development so that you can modify the files and not have to deal with apache cached versions. The most important part consists of the PerlHandler, AddType, and AddHandler commands. You can call your files whatever you want, but (one) convention is to use the prefixes .mhtml and .comp. There is some further discussion in the Mason FAQ at "Mason HQ".

In addition, mod_perl has to load the required modules; those are listed in apache-perl.pl:

use HTML::Mason::ApacheHandler;
use CGI;
 
1;

You can actually call this file whatever you like as long as it's correctly referenced with PerlRequire in the .htaccess file. Notice the true return ("1;") at the end. This is a list of modules for the mason/apache mod_perl process; modules used within actual pages (such as DBI) have to be included in those pages (and nb. -- use "use" and not "require"), and should not be included here.

Site Structure

The tutorial involves a simple site, The Mason Internet Zoo. This site is contained in the following directory structure:

db/
   newDB.pl
   zoodemo.db
js/
   .htaccess
   prototype.js
   site_specific.js
log/ 
   DBI_trace.log*
   perl.log*
.htaccess
INSTALL
ZooAnimal.pm
ZooDemo.pm
animal.comp
animals.mhtml
apache-perl.pl
cage.comp
cages.mhtml 
class.comp 
classes.mhtml
create_animal.comp
db_error.mhtml
header.comp
index.html    
new_animal.comp  
style.css
            
*do not exist initially and can be erased later

You will have to search thru this and change references to the path /var/www/html/zoodemo as appropriate if you cannot use it in that directory. INSTALL contains some brief instructions.

I should soon have an online host for The Mason Internet Zoo, but for the time being, if you want to see the demo you will have to install it yourself, which should be fairly easy and might get you familiar with a few basic things.

index.html

That's the first document we see. As long as you have the .htaccess file correct and mod_perl installed, apache will process index.html with mason, so:

<& header.comp, title=>"Zoo Demo", heading=>"Mason Internet Zoo"&>
<ul>
<li><a href="animals.mhtml">Animals</a>
<li><a href="cages.mhtml">Cages</a>
<li><a href="classes.mhtml">Classes</a>
</ul>
</body></html>

The big line here is in red, but since you've read chapter one of "the book" you understand that that means to include another file here, in this case, header.comp, and to pass it two variables -- title and heading. So here's header.comp:

<html><head>
<title><% $ARGS{title} |h %></title>
<link rel="stylesheet" type="text/css" href="style.css"></style>
<script type="text/javascript" src="js/site_specific.js"></script>
<script type="text/javascript" src="js/prototype.js"></script>
</head>
 
<body text="#cccccc" bgcolor="#222222">
<div id="utildiv" class="utility"></div>
<h1><% $ARGS{heading} |h %></h1>
 

header.comp is a sort of pre-wrap I'm using with all the .mhtml pages. Again, if you read chapter 2 of "the book" you will recognize the use of the %ARGS hash which is passed to the component. Notice the "|h"; this is a mason function to qualify HTML reserved characters that may be present in a variable since the real value will appear in the actual page source passed to the browser. As is, I have hardcoded control over all the instances at the Zoo for this particular component and don't have to worry about problem characters, but on the premonition that I may soon want to include individual pages for individual animals based on user input, they are included here.

There is a special mason file, the autohandler, which allows you to write a universal wrapper for all mason components, but since some of the Zoo components are actually innerHTML content for use with AJAX (in fact, all of the .comp files except header.comp are such), I do not use an autohandler.

Also included in header.comp are "site_specific.js" and the freely distributable prototype.js. Prototype gives us access to simplified AJAX functions like Ajax.Request. I'm gonna use those mostly with $('utildiv'), created in the other line in red (above). Note CSS class "utility" is set display: none in style.css, also included in header.comp. Utildiv is a popup we reuse with Ajax.Updater for various things in all the .mhtml pages. For example:

<& header.comp, title=>"Mason Internet Zoo", heading=>"Cages List"&>
 
<%init># cages.mhtml
BEGIN { push @INC,"/var/www/html/zoodemo"; }
use ZooDemo;
$m->interp->set_escape("j"=>\&js_esc); 
my $db = db_handle();
my $sql = $db->prepare("select * from cages");
$sql->execute;
</%init>
 
<center>
% while (my @data=$sql->fetchrow_array()) {
        <p class="link" onclick="new Ajax.Updater($('utildiv'),'cage.comp', { method: 'post', 
                parameters: { name: '<%$data[1]|j,h%>', id: '<%$data[0]%>' } });
                $('utildiv').style.display='inline';"><%$data[1]|h%> (<%$data[2]%> species)
% }
</center>
</body></html>
 

Yes, some obtrusive inline JavaScript, presented this way in the demo for ease of illustration (since we can see the Perl/HTML context without having to site multiple files). If you prefer, it can easily be hidden away in the site_specific.js file. The actual source here is cages.mhtml, where all the cages at the zoo are listed. By clicking on a cage, you get a pop-up containing a list of the animals in the cage.

List of animals in the cage screenshot

The <%init> block, wherever located in the page, is Perl code executed before anything else is done. In this case, we are making use of ZooDemo.pm, which contains some basic functions, db_handle(), js_esc(), and log_msg().

package ZooDemo;
use strict;
 
use DBI;
use base ("Exporter");
our @EXPORT = qw(db_handle js_esc log_msg); 
 
our $path = "/var/www/html/zoodemo";

ZooDemo takes care of loading DBI and connecting to the SQLite DB by providing db_handle() for error handling, et. al (which might also make switching databases, etc, much simpler). js_esc() is a custom handler for escaping single quotes in variables that are passed to JavaScript functions:

sub js_esc {
        my $ref = shift;
        $$ref =~ s/\*'/\'/g;
}

This is registered with mason via the $m->interp->set_escape(), highlighted above, and then used like the "|h" function mentioned earlier. Nice! It is important to use the "j" before the "h" flag. Take a close look at some possible "page source" output:

<p class="link" onclick="new Ajax.Updater($('utildiv'),'animal.comp', { method: 'post', 
    parameters: 'name=heap\'s moose &data=Rotunda&data=unknown'}); 
    $('utildiv').style.display='inline';">heap's moose

Since this is embedded in HTML source, the ' can be rendered ' (by the |h flag) in both places; altho it is not necessary for the js tag since it would be preceded by a '\' because of the |j flag. However, the variable could still have had unescaped < or > in it also, so we should stay safe and use both the |h and the |j flag with variables for javascript. When passed to Ajax.Updater, this ends up as "heap\'s moose", fortunately, not "heap\'s moose". The example in purple appears on the page and is not part of any JavaScript, so it used only the |h flag -- hence no '\' there.

Again, just to be clear: there is no default |j flag, so you can use your own ideas here. There are other characters that can cause a js error, but the single-quote/apostrophe will be the most common one used legitimately and is also the most dangerous one for malicious purposes. You can override the default |h handler as well, which the FAQ notes:

...will not work with non-ISO-8559-1 encodings. If you are using such an encoding and want to switch the 'h' flag to escape just the minimal set of characters (<, >, &, "), put this in your Apache configuration:

PerlSetVar MasonEscapeFlags "h => \&HTML::Mason::Escapes::basic_html_escape"

Database Integration

cages.mhtml and cage.comp both interact with a database db/zoodemo.db. I'm using DBI with SQLite3. The database was created and pre-populated with db/newDB.pl, which if you modify the db you can delete it and replace it using that script to restore the original state of the zoo. All the SQL commands that created the tables are in newDB.pl. Because apache must write to zoodemo.db, remember that on a Unix style filesystem, the ownership of it and the containing directory must be "apache.apache" (or whatever the runtime uid of apache is).

zoodemo.db contains three tables (cages, classes, and animals), each using an autoincrementing integer primary key "id" so that we can try and keep the database working by the rules of 3rd normal form (3NF).

A mason component will accept arguments from another mason component, as in the case of index.html & header.comp (<& header.comp, title=>"Zoo Demo", heading=>"Mason Internet Zoo"&>), or as "form" parameters passed via POST. At The Mason Internet Zoo, posting is done with Ajax.Updater (as above). There is a detailed explanation of this (sans AJAX) in chapter 2 of "the book"; in any case, mason and apache do the work, so there is no difference within the component as to how the parameters are passed. Clicking on a cage listed in cages.mhtml will pop up the utildiv window containing an instance of cage.comp, that is, a per cage-specific list of the animals in that particular cage. So this will be the innerHTML for utildiv when so invoked:

<%init># cage.comp
#called from cages.mhtml with args "name" "id"
BEGIN { push @INC,"/var/www/html/zoodemo" }
use ZooDemo ("db_handle");
my $db = db_handle();
my $sql = $db->prepare("select * from animals where cage_id=?;");
$sql->execute($ARGS{id});
</%init>
 
<h3><%$ARGS{name}|h%></h3>
<p>Contains:
<ul>
% while (my @data = $sql->fetchrow_array()) {
        <li><%$data[1]|h%>
% }
% $db->disconnect;
</ul>
 
<p class="mini" align="center" onclick="$('utildiv').style.display='none';">[close]

There's the $ARGS hash again, with the |h flag; note we don't actually need to examine table cages, since we already have the name of the cage. Something to notice here is the use of a placeholder (?) in the SQL select call where cage_id=?. This placeholder is filled in the ->execute() with $ARGS{id}. This could have been written:

my $sql = $db->prepare("select * from animals where cage_id='$ARGS{id}'");
$sql->execute();

The point of using a placeholder is to prevent abuse of the single quote (again) in SQL injection attacks on the database.

"classes.mhtml" & "class.comp" work exactly the same way as cages.mhtml & cages.comp do. This snippet also contains the three means of "embedding" the Perl within what is ostensibly an HTML page:

  • Perl-only sections between <%Perl></%Perl> or <%init></%init> tags (there are others, but those are the two most common).
  • Mixed into HTML with <%.....%>
  • Alternating with HTML using % at the beginning of a line.

It might be worth mentioning at this point that the %ARGS hash can be preprocessed, placing the key/value pairs into individual variables (using the key name) for simplification. This is especially handy if you want to pass an array or hash using a reference in the caller. The mechanism for this in the callee is an <%args> block. There is a complete explanation in chapter 2 of "the book"; the Internet Zoo demo contains one example of how to use an <%args> block:

<%args># animal.comp
#called from animals.mhtml with args "name" and "data" (x2)
$name
@data
</%args>
 
<h3><%$name|h%></h3>
<p>Cage: <%$data[0]|h%><br/>Class: <%$data[1]|h%>
 
<p class="mini" align="center" onclick="$('utildiv').style.display='none';">[close]

Notice the args block is not normative Perl code and should not contain any. It might have been simpler here to just use the %ARGS hash again, or to use three scalars. But hey, what's a demo if it doesn't demonstrate? Passing an array from another component is as simple as passing a reference, but using form POST data is slightly more complicated. The explanation from "the book" describes how fields with the same name in a query string will be placed into an array of the same name in the component. However, you cannot pass such a string using the normative js object notation with Ajax.Updater (eg, parameters: {name: 'bob', id: 666 }). Instead, you must use string notation like this, which is the actual call used to animal.comp, above, from animals.mhtml, below:

<p class="link" onclick="new Ajax.Updater($('utildiv'),'animal.comp', { method: 'post', 
       parameters: 'name=<%$_->{name}|j,h%>&data=<%$_->{cage}|j,h%>&data=<%$_->{class}|j,h%>' }); 
                $('utildiv').style.display='inline';"> 

Witness, "data" is used twice, which is why you can't use the js object notation. You might notice there is some perl->object syntax in there as well. Using objects with mason is slightly limited because variables including object references do not persist between page calls. However, we do have one example from ZooAnimal.pm, the other module, which is used to contain the Perl routines for animals.mhtml and new_animal.comp. Those are discussed in the next section.

Forms

I've included an example form submission so you can add more animals to the zoo. This option appears in the "titlebar" of animals.comp:

Animals List Form Screenshot

<div class="menu">
<p class="menulink" onclick="new Ajax.Updater($('utildiv'),'create_animal.comp');
        $('utildiv').style.display='inline';">Add New Animal
</div>

create_animal.comp is just a normal form with id ="newadmin" and action = "JavaScript: processform ($('newamin'), 'new_animal.comp')". processform() is in site_specific.js`:

function processform(form,comp) {
    new Ajax.Updater(document.body, comp, { method: 'post', parameters: form.serialize(true) });
} 

You can see how nicely mason and AJAX work together here, taking care of the form submission and passing the input along to new_animal.comp, which adds to the database and doesn't output any HTML -- instead, it just includes <& animals.mhtml &> at the end, which should display the updated list. Actually, if the ZooAnimal.pm create() routine throws an SQL or other error, new_animal.comp will respond to that by including something instead of animals.mhtml:

<%init># new_animal.comp
#called from create_animal.comp with args "name" "class" "cage"
BEGIN { push @INC,"/var/www/html/zoodemo"; }
use ZooAnimal ("create");
my $check = create ZooAnimal($ARGS{name},$ARGS{cage},$ARGS{class});
</%init>
% if ($check) {
    <& animals.mhtml &>
% } else {
    <& db_error.mhtml &>
% }

This method of error handling occurs in a few other places as well. So this is somewhat like a normal CGI routine, only much nicer to work with IMO. If your animal belongs to a new class, the class is also created.

But couldn't you just do all of this with CGI anyway?

You're welcome to try!

Debugging/Logging

db_handle() in ZooDemo.pm turns on DBI's tracing mechanism when the handle is created:

DBI->trace(1,"$path/log/DBI_trace.log");

Trace output is quite copious.

Additionally, many Perl and SQL errors, as well as anything you print to STDERR, will appear in apache's error.log. log_msg(), from ZooDemo.pm, will print to a file log/perl.log; the only place this is actually used is when you create a new animal. As with the db directory, apache mod_perl writes files to the log directory and so it must be chown'd apache.apache.

Miscellaneous Issues

For one reason or another, css :hover attributes will not work unless you use the entire tag in the definition. So if you are used to using:

.link { color: #fffff; }
.link:hover { background: #ffff00; color: #000088; font-weight: bold;}

And having that affect a variety of tags, there is a slight inconvenience: .link will apply to anything class="link", but link:hover will not. To make it work you need to do this:

.link { color: #fffff; }
p.link:hover { background: #ffff00; color: #000088; font-weight: bold;}
h2.link:hover { background: #ffff00; color: #000088; font-weight: bold;}
[etc]

I have not found an explanation for this (if you have one, let us know!) so I cannot say whether this behavior is consistent everywhere or what part of mason/apache/mod_perl is responsible, but it is worth mentioning.

That's All Folks! If you have any comments or criticisms please post and I will do my best to incorporate (sane) suggestions! And thanks to members of the mason-user list for their input -- much appreciated.

This page was published on It was last revised on

Contributing Authors

0

1 Comment

  • Votes
  • Oldest
  • Latest
Commented
Updated

Thanks a lot for this tutorial! Unfortunately, in Ubuntu 10.04, the zoodemo won't work correctly when used locally.

There are Mason examples included in Ubuntu (libhtml-mason-perl-examples), which get copied into /var/www/mason_examples. Those work w/out any problems, but the zoodemo.mhtml files don't seem to get interpreted.

As I'm new to Mason, I'd greatly appreciate any hints on a possible solution to this problem!

Update:

What I was trying to achieve was meant to be achieved by the delivered .htaccess files. If your .htaccess file does not seem to be making any difference, you will need to ensure that using .htaccess are enabled. Just these little modifications for Ubuntu 10.04 (for others who face the same problem). Put a file into /etc/apache2/conf.d:

# Enable .htaccess server side includes
<Directory /var/www/zoodemo>
    AllowOverride Options
    AllowOverride FileInfo
</Directory>
  1. Reload apache2
  2. In the zoodemo-.htaccess files (there's more than one!) remove the "Files *" part as the current Ubuntu apache doesn't seem to like the "Header" directive

And of course - as already stated in the tutorial's README, replace the base location (default: /var/www/html/zoodemo, for me it is /var/www/zoodemo).

Enjoy.

add a comment
0