Embperl: Modern Templates

Mr. Lerner introduces us to a template system for Perl: what it is, how it works and how to use it.
Configuring Apache to Allow Embperl

Now that Embperl is part of your copy of Apache, what can you do with it? Not much at this point, since we have not yet defined the handler for our Embperl files. Now we will have to modify Apache's configuration files, which might be in a number of possible places. When I installed Apache, I accepted the default installation locations (under /usr/local/apache), and my path names will reflect that.

In order to get Embperl working, we will need to modify two of Apache's configuration files. (Each of the three files can actually contain any of the configuration directives, but certain items are traditionally put in certain files.) I told the server to redirect URLs beginning with /embperl to /usr/local/apache/share/embperl by adding the following lines to the srm.conf file:

Alias /embperl /usr/local/apache/share/embperl

Next, I told Apache to install Embperl as the handler for that directory. As I mentioned above, this means that HTML::Embperl will be called each time Apache is asked to retrieve a document from /embperl. The file will be read from disk, handled by Embperl, and finally given to Apache, which returns it to the user's computer. I added the following to the access.conf file:

<Location /embperl>
 SetHandler perl-script
 PerlHandler HTML::Embperl
 Options ExecCGI
Once we have installed these changes, we restart Apache with:
/usr/local/apache/sbin/apachectl restart

Embperl Syntax

Embperl files look just like HTML files, with a minor difference: square brackets signify special sections of code, which are interpreted separately. In other words, you can put stock HTML files in an Embperl directory, although I would tend to advise against doing so, because of the additional overhead involved. Why force Embperl to look at a file unnecessarily? For that reason, some sites have decided to use a special suffix—.htmpl, perhaps—and then to configure Apache so that all files with that suffix, regardless of directory, are interpreted. That allows HTML files to be mixed in with their Embperl counterparts.

The following file, when retrieved from within a directory defined for Embperl, will print the current time:

<Head><Title>Current time</Title></Head>
<P>This is Embperl</P>
<!-- Below are the square brackets -->
<P>[+ localtime(time) +]</P>

Retrieving this file from an Embperl directory will produce the same output as the following short CGI program:

#!/usr/bin/perl -w
 use strict;
 use diagnostics;
 use CGI;
 # Create a new instance of CGI
 my $query = new CGI;
 # Send a MIME header
 print $query->header("text/html");
 # Send the HTML
 print $query->start_html(-title =>
        "This is Embperl");
 print scalar localtime(time);
 print $query->end_html;
However, Embperl has several advantages over a CGI program. For one, running it under mod_perl gives it a distinct speed advantage. Of course, we could modify our CGI program and/or Apache configuration so that the program would run under Apache::Registry, the mod_perl module that handles CGI-like programs.

The biggest advantage, though, is the clean separation between static and dynamic content. No longer does the programmer become the bottleneck, slowing down design and content changes—now the site's designers and editors can modify the HTML, so long as they stay away from the Perl inside square brackets. There will obviously be times when the embedded Perl code will affect the design, and the programmer can be included in such cases. But for the most part, such a separation allows everyone to do what they do best.

We have already seen one form of the Embperl brackets, namely [+ and +]. Anything in square-plus brackets is evaluated as Perl code, with the results inserted into the HTML document and passed to the browser. Remember that the result of evaluating a Perl variable or string is the value of that variable or string. It's very common for square-plus brackets to contain a single variable name, whose contents are inserted into the document at the indicated point. Don't use the print function to insert things into the Embperl document, because print sends output to STDOUT, and then returns a result indicating whether it was successful. Each set of square-plus brackets can contain as much or as little Perl as you might like, although most Embperl programmers seem to prefer keeping the lines short.

Output from square-plus brackets is placed directly into the file without any additional formatting. If you want something to be in paragraph tags, boldface, italics or a different font, it is your responsibility to make sure that happens. Most often, you will want to surround the square-plus brackets with the appropriate HTML tags, so that the resulting output will be correctly formatted. That is, you could make a variable's value italic by saying

[+ "<i>$variable</i>" +]

but, for the sake of maintenance and separating static and dynamic content, it's better to say:

<i>[+ $variable +]</i>
What if you don't want the results of your code to be inserted into the document? You could end each set of Perl expressions with the empty string, as in:
[+ $counter++; &get_user_info($id); "" +]
which will insert the empty string into the document, since it was the last element to be evaluated. But a better solution would be square-minus brackets ([- and -]), which do that for you automatically. For example:
<Head><Title>Current time</Title></Head>
<P>This is Embperl</P>
<!-- Square-plus brackets -->
<P>[+ localtime(time) +]</P>
<!-- Square-minus brackets -->
<P>[- localtime(time) -]</P>
Output from the above Embperl will look the same as the one without square-minus brackets, since the output from operations performed in square-minus brackets aren't inserted into the HTML. This is useful when making variable assignments, as well as when importing other Perl modules. For example:
<Head><Title>Print user information</Title></Head>
[- $user = $ENV{"REMOTE_USER"}; -]
<P>This is Embperl</P>
<P>[+ &print_user_profile($user) +]</P>