# -*- perl -*-
#
#   HTML::EP	- A Perl based HTML extension.
#
#
#   Copyright (C) 1998    Jochen Wiedmann
#                         Am Eisteich 9
#                         72555 Metzingen
#                         Germany
#
#                         Phone: +49 7123 14887
#                         Email: joe@ispsoft.de
#
#   All rights reserved.
#
#   You may distribute this module under the terms of either
#   the GNU General Public License or the Artistic License, as
#   specified in the Perl README file.
#
############################################################################


=head1 NAME

    HTML::EP - a system for embedding Perl into HTML

=head1 SYNOPSIS

    <html><head><title>CGI-Env</title></head>
    <ep-comment>
	This is an HTML document. You see. Perhaps you wonder about
	the unknown HTML tags like ep-comment above? They are part
	of the EP system. For example, this comment section will
	be removed and you won't see it in your browser.
    </ep-comment>
    <ep-perl>
	# This is an example of embedding Perl into the page.
	# We create a variable called env, containing our environment
	# variables. This variable will be used below.
        my $self = $_;
	my $env = [];
	my($var, $val);
	while (($var, $val) = each %ENV) {
	    push(@$env, { var => $var, val => $val });
	}
	$self->{env} = {%ENV};
	'';
    </ep-perl>
    <body><h1>Your CGI environment</h1>
	Your CGI environment looks as follows:
	<table><tr><th>Variable</th><th>Value</th>
	    <ep-list items="env" item="e">
	       <tr><td>$e->var$</td><td>$e->val$</td>
	    </ep-list>
	</table>
    </body>
    </html>


=head1 WARNING

THIS IS ALPHA SOFTWARE. It is *only* 'Alpha' because the interface (API) is
not finalised. The Alpha status does not reflect code quality or stability.
In particular the following things might change without further notice:

=over 8

=item

The way of passing variables as attributes. For example, currently one
can use

    <ep-mail epparse-from="$cgi->email$" to="joe"
             subject="Test mail">

to pass the form variable I<email> into method calls. I consider
changing this to

    <ep-mail from="$cgi->email$" to="joe" subject="Test mail"
             parse=1>

or whatever. The decision mainly depends on performance considerations
and readability. See L<"Variables"> below.

=item

The C interface of introducing own methods. This depends on whether I
need changes for inserting the module into mod_perl. See L<"TODO">
below.

=back


=head1 DESCRIPTION

Have you ever written a CGI binary? Easy thing, isn't it? Was just fun!

Have you written two CGI binaries? Even easier, but not so much fun.

How about the third, fourth or fifth tool? Sometimes you notice that
you are always doing the same:

=over 4

=item

Reading and parsing variables

=item

Formatting output, in particular building tables

=item

Sending mail out from the page

=item

Building a database connection, passing CGI input to the database and
vice versa

=item

Talking to HTML designers about realizing their wishes

=back

You see, it's soon to become a pain. Of course there are lots of little
helpers around, for example the CGI module, the mod_perl suite and
lots of it more. Using them make live a lot easier, but not so much as
you like. L<CGI(3)>. L<mod_perl(3)>.

On the other hand, there are tools like PHP/FI or WebHTML. Incredibly
easy to use, but not as powerfull as Perl. Why not get the best from
both worlds? This is what EP wants to give you, similar to ePerl or
HTML::EmbPerl. I personally believe that EP is simpler and better
extendible than the latter two. L<ePerl(1)>. L<HTML::EmbPerm(3)>.

In short, it's a single, but extensible program, that scans an HTML
document for certain special HTML tags. These tags are replaced by
appropriate output generated by the EP. What remains is passed to the
browser. Its just like writing HTML for an enhanced browser!


=head2 Prerequisites

As far as I know EP depends on no system dependent features. However,
it relies on some other Perl modules:

=over 12

=item CGI

The CGI module should be a part of your Perl core's installation. If
not, you should definitely upgrade to Perl 5.004. :-) My thanks to
Lincoln D. Stein <lstein@genome.wi.mit.edu>.

=item HTML::Parser

This module is used for parsing the HTML templates. My thanks to Gisle
Aas <aas@sn.no>.

=item libwww

The LWP library contains a lot of utility functions, for example HTML
and URL encoding and decoding. Again, my thanks to Gisle Aas <aas@sn.no>. :-)

=back

Perl itself and the above modules are available from any CPAN mirror,
for example

       ftp://ftp.funet.fi/pub/languages/perl/CPAN/modules/by-module


=head2 Installation

Installing this module (and the prerequisites from above) is quite simple.
You just fetch the archive, extract it with

    gzip -cd HTML-EP-0.1000.tar.gz | tar xf -

(this is for Unix users, Windows users would prefer WinZip or something
similar) and then enter the following:

    cd HTML-EP-0.1000
    perl Makefile.PL
    make
    make test

If any tests fail, let me know. Otherwise go on with

    make install

This will put the required Perl modules into a destination where
Perl finds it by default. Additionally it will install a single CGI
binary, called C<ep.cgi>.

The docs are available online with

    perldoc HTML::EP

If you prefer an HTML version of the docs, try

    pod2html lib/HTML/EP.pm

in the source directory.


=head2 Using the CGI binary

I suggest that you choose an extension and configure your WWW server for
feeding files with this extension into C<ep.cgi>. For example, with
Apache, you can add the following lines to your C<srm.conf>:

    ScriptAlias /cgi-bin/ep.cgi	/usr/bin/ep.cgi
    AddHandler x-ep-script .ep
    Action x-ep-script /cgi-bin/ep.cgi

This tells Apache that files with extension ep.cgi are handled by the
CGI binary C</usr/bin/ep.cgi>. Make sure, that the ScriptAlias line is
entered *before* any other ScriptAlias instruction!

From now on your server will never return files with extension .ep
directly! Verify your installation by creating the following file:

    <ep-perl>
    print "content-type: text/plain\n\n";
    print "It worked! Your EP system is up and running.\n";
    </ep-perl>

Store it as C</test.ep> on your web server and retrieve the file via
your Web server. You should neither see the C<ep-perl> not the C<print>
instructions.


=head2 Available methods

All EP tags are starting with the prefix I<ep->. Some available tags are:


=over 4

=item ep-comment

This is a multi-line tag for embedding comments into your HTML page. But
why use this tag, instead of the usual HTML comment, C<E<lt>!-->? The
difference is, that the user will never see the former.

Example:

    <html>
        <!-- This is a comment. I like comments. --!>
        <ep-comment>
	    This is another comment, but you won't see it
	    in your browser. The HTML editor will show it
	    to you, however!
	</ep-comment>
    </html>

Do not try to embed EP instructions into the comment section! They
won't produce output, but they will be executed anyways.


=item ep-perl

This is for embedding Perl into your script. There are two versions of
it: A multiline version is for embedding the Perl code immediately into
your script. Example:

    <html>
	<head><title>The Date</title></head>
        <body>
	    <h1>The Date</h1>
	    <p>Hello, today its the</p>
	    <p align=center>
	    <ep-perl>
		# This little piece of Perl code will be executed
		# while scanning the page.
		#
		# Let's calculate the date!
		#
		my($sec,$min,$hour,$mday,$mon,$year)
                    = localtime(time);
		# Leave a string with the date as result. Will be
                # inserted into the HTML stream:
		sprintf("%02d.%02d.%04d", $mday, $mon+1, $year+1900);
	    </ep-perl> 
	    </p>
        </body>
    </html>

If you don't like to embed Perl code, you may store it into a different
file. That's what the single-line version of ep-perl is for:

    <html>
	<head><title>The Date</title></head>
        <body>
	    <h1>The Date</h1>
	    <p>Hello, today its the</p>
	    <p align=center>
	    <ep-perl src="date.pl">
	    </p>
        </body>
    </html>


You have noticed, that the little script's result was inserted into the
HTML page, did you? It did return a date, in other words a string consisting
of letters, digits and dots. There's no problem with inserting such a string
into an HTML stream.

But that's not always the case! Say you have a string like

    Use </html> for terminating the HTML page.

This cannot be inserted as a raw string, for obvious reasons. Thus the
ep-perl command has an attribute I<output>. Use it like this:

    <ep-perl output=html>
        'Use </html> for terminating the HTML page.';
    </ep-perl>

Possible values of the I<output> attribute are C<raw> (default), C<html>
(HTML encoded) and C<url> (URL encoded).

It's a common mistake, to use the Perl command C<return> in embedded Perl.
Never do that! If you need return (there are of course situations where
returning can help), do it like this:

    <ep-perl>
	sub eval_me {
	    if ($this) {
		return 'foo';
	    } elsif ($that) {
		return 'bar';
	    }
	    '';
	}
	eval_me();
    </ep-perl>

See L<"Variables"> below for interactions between Perl variables and
EP variables.


=item ep-mail

This command will send an e-mail. The attributes will be used for creating
the email header, in particular the C<subject>, C<from> and C<to> attribute
should be used. Example:

    <ep-mail subject="Howdy!" from="joe@ispsoft.de"
             to="bill@whitehouse.gov">
	Hello, Bill, old chap. How are you?

	Yours sincerely,
	Jochen
    </ep-mail>

Note, that you can still use EP variables in the E-mail body, for example
the following works:

    <ep-mail subject="Test" epparse-from="$cgi->email$"
             to="joe@ispsoft.de">
        Hello, Joe,
        this e-mail was sent to you by $@cgi->name$.
    </ep-mail>

Note that we suppress conversion into HTML format in the mail body!
See L<"Variables"> below for details.


=item ep-errhandler

This command advices EP, what to do in case of errors. See L<"Error handling">
below. Example:

    <ep-comment>
	Set the template being used for system errors.
    </ep-comment>
    <ep-errhandler type=system src=/templates/syserr.html>
    <ep-comment>
	Likewise, set the template for user errors.
    </ep-comment>
    <ep-errhandler type=user src=/templates/usererr.html>

If an error occurs, the given scripts are loaded and used as templates
instead of the current one. You don't need external files! Instead
you can use

    <ep-errhandler type=user>
        <HTML><HEAD><TITLE>User error</TITLE></HEAD>
        <BODY><H1>User error</H1>
        <P>Replace user and continue. :-)</P>
        <P>To be serious, the following problem happened:</P>
        <PRE>$errmsg$</PRE>
        <P>Please return to the calling page, fix the problem
        and retry.</P>
        </BODY></HTML>
    </ep-errhandler>

However, you might prefer to use a single error template and of course
it's faster to use external error templates than parsing builtin
templates. (At least, if no error occurs. :-)


=item ep-error

This command forces an error message. See L<"Error handling"> below.
You can trigger user or system errors by setting the I<type> attribute
to the values C<system> (default) or C<user>. The I<msg> attribute is
for setting the error message.

Example:

    <ep-comment>
	If no email address was entered, force a user error.
    </ep-comment>
    <ep-if epparse-eval="$cgi->email$" type=user>
	<ep-error msg="Missing email address">
    </ep-if>


=item ep-database

This command connects to a database. Its attributes are C<dsn>, C<user>
and C<password> corresponding to the same attributes of the DBI connect
method. See L<DBI(3)> for details on DBI.

Example:

    <ep-database dsn="DBI:mysql:test" user="joe"
	         password="Authorized?Me?">

You can use different database connections by using the I<dbh> attribute:

    <ep-database dbh="dbh2" dsn="DBI:mSQL:test">

The I<dbh> attribute advices EP to store the DBI handle in the given
variable. (Default: C<dbh>) See L<"Variables"> below.


=item ep-query

This command executes an SQL statement. The C<query> attribute will
be used for passing the SQL statement. Of course a multiline version
is available, thus

    <ep-query query="INSERT INTO foo VALUES (1, 'bar')">

is the same as

    <ep-query>
	INSERT INTO foo VALUES (1, 'bar')
    </ep-query>

If your query retrieves a result, use the C<result> attribute to store it
in a variable, for example like this:

    <ep-query query="SELECT * FROM employees" result="employees">

This will create a variable C<employees>, an array ref of hash refs.
You can use the ep-list command for displaying the output. See
L<"Variables"> below.

When using multiple database connections, use the I<dbh> attribute for
choosing the connection. (See the I<ep-database> method above.)


=item ep-list

This command is used to display an array of refs. Lets assume, that
the variable C<employees> contains a an array ref of refs with the attributes
I<name> and I<department>. Then you could create a table of employees as
follows:

    <table><tr><th>Name</th><th>Department</th>
    <ep-list items="employees" item="e">
	   <tr><td>$e->name$</td><td>$e->department$</td>
    </ep-list>
    </table>

This will be processed as follows: For any item in the array,
retrieved from the variable C<employees>, create a variable C<e> and
display the text between ep-list and /ep-list for it by replacing
the patterns $e->name$ and $e->department$ with the corresponding
values.


=item ep-input

This is usefull for reading an objects data out of CGI variables.
Say you have a form with input fields describing an address, the
field names being address_t_name, address_t_street, address_n_zip and
address_t_city. By using the command

    <ep-input prefix="address_" dest="address">

the EP program will create a variable "address" for you which is an
hash ref as follows:

    $cgi = $_->{cgi};
    $_->{address} = {
	name =>   { col => 'name',
		    val => $cgi->param("address_name"),
		    type => 't',
		  },
	street => { col => 'street',
		    val => $cgi->param("address_street"),
		    type => 't',
		  },
	zip =>    { col => 'zip',
		    val => $cgi->param("address_zip"),
		    type => 'n',
		  },
	city =>   { col => 'city',
		    val => $cgi->param("address_city"),
		    type => 't'
		    }
    };

In general column names beginning with I<address> will be splitted into
C<prefix_type_suffix>, the type being either 't' for text or 'n' for
number. The idea is generating SQL queries automatically out of the
C<address> variable.

=back


=head2 Error handling

Error handling with EP is quite simple: All you do in case of errors is
throwing a Perl exception. For example, DBI handles are created with
the RaiseError attribute set to 1, so that SQL errors trigger a Perl
exception. You never care for errors!

However, what happens in case of errors? In that case, EP will use the
template that you have set with ep-errhandler and treat it like an
ordinary EP document, by setting the variables C<errmsg> and C<admin>.

If you don't set an error handler, the following template will be used,
which is well suited for creating an own error template:

    <html><head><title>Internal error</title></head>
    <body><h1>Internal error</h1>
    <p>An internal error occurred. The server has not been able to
    fullfill your request. The error message is:</p>
    <pre>
	$errmsg$
    </pre>
    <p>Please contact the Webmaster,
    <a href="mailto:$admin$">$admin$</a>,
    tell him the URL, the time and error message.
    </p>
    <p>We apologize for any inconvenience, please try again later!</p>
    <br><br><br><p>Yours sincerely,</p><p>The Webmaster</p>
    </body>
    </html>


=head2 Variables

It is important to understand, how EP variables work, in particular when
working with ep-perl.

You always have an object $_, which is an instance of the HTML::EP
class (a subclass of HTML::Parser). This object has certain attributes,
in particular C<$_->{cgi}>, a CGI object and C<$_->{dbh}>, the DBI
handle. (Of course valid after C<ep-database> only.) If you want to set
or modify a variable, you have to set C<$_->{varname}>. If you want to
retrieve the value, use the same. Note that you cannot use C<$_> for
a long time, as it will be changed by Perl loops and the like, thus
your Perl code typically starts with

    $_ = $self;

But how do you access the variable from within EP documents? You just
write

	$varname$

This will be replaced automatically by the parser with the value of
C<$_-E<gt>{varname}>. Even more, the value will be converted
into HTML source!

If C<varname> is a structured variable, for example a hash or array ref,
you may as well use

	$varname->attrname$

or

	$varname->0$

to access C<$_-E<gt>{varname}-E<gt>{attrname}> or
C<$_-E<gt>{varname}-E<gt>[0]>, respectively. A special
value of I<varname> is C<cgi>: This will access the CGI variable of
the same name, thus the following are equivalent:

	$cgi->email$

and

	$_->{cgi}->param('email');

But what, if you don't want your variable to be HTML encoded? You
may as well use

	$@varname$	(Raw)
	$#varname$	(URL encoded)
	$~varname$	(SQL encoded)

The latter uses the $_->{dbh}->quote() method. In particular this
implies that you have to be connected to a database, before using
this tag!

You can even use these symbols in attributes of EP commands. For
example, the following will be usefull when sending a mail:

    <ep-mail subject="Howdy!" epparse-from="$@cgi->email$"
	     to="bill@whitehouse.gov">

By prefixing the attribute name with C<epparse-> you tell the EP module that
the attribute must be parsed before processing it. (Note, that one doesn't
use an HTML encoded value in that case!) Another prefix is C<epperl->: In
this case the attribute will be evaluated by the Perl interpreter, much
similar to the ep-perl method. The perl code's result will be used as
final attribute value.

WARNING: As already said, use of C<epparse-> and C<epperl-> is dangerous,
as these things are likely to be changed in the future.


=head1 EXTENSIONS

It is quite easy to write own methods.


=head2 Single-line extensions

For example, suggest you want a method for accessing environment
variables:

    <ep-env var="e">

The idea is to create a variable C<e>, which is a hash ref of the
current environment variables, so that you can use

    $e->REMOTE_AGENT$

for accessing the name of the users browser.

This can be done like this:

    <ep-perl package="HTML::EP">
    my $self = $_;

    # Write a handler for ep-env:
    sub env ($$) {
        my($self, $attr) = @_;
        my $var = $attr->{var};
	$self->{$var} = {%ENV};
	'';
    }

    # Register the handler in the list of handlers:
    $self->{_ep_funcs}->{'ep-env'} = { method => 'env' };
    # Return an empty string:
    '';
    </ep-perl>

The I<method> attribute of the handler tells the EP module to call

    $_->env($attr);

if the C<ep-env> tag is used. The argument C<$attr> is a hash ref of
the tags attributes. Note the use of the I<package> attribute: By
default the C<ep-perl> code is executed in a I<Safe> compartment.
See L<Safe(3)>.


=head2 Multi-line extensions

But how to write methods, that use a C<E<lt>tagE<gt>> .. C<E<lt>/tagE<gt>>
syntax? As an example, we write a method for creating external files.
The method receives two attributes, a I<file> attribute for the files
name and a I<contents> attribute for the files contents. The method
can be used in two ways:

    <ep-file file="test.dat" contents="Hi!">

or like this, in multiline mode:

    <ep-file file="test.dat">
        Hi!
    </ep-file>

Here it is:

    <ep-perl package="HTML::EP">
    # Write a handler for ep-file:
    sub file ($$) {
        my($self, $attr) = @_;
	my $contents = $attr->{contents};
	if (!defined($contents)) { # Multiline method, no "contents"
	    return undef;          # attribute given; return undef
	}                          # until we are called again.
        my $file = $attr->{file};
	require Symbol;
	my $fh = Symbol::gensym();
	if (!open($fh, ">$file)  ||  !(print $fh ($contents))  ||
            !close($fh)) {
            die "Error while creating $file: $!";
        }
	'';
    }
    # Register the handler in the list of handlers
    # Note the use of the "default" attribute:
    $self->{_ep_funcs}->{'ep-env'} = { method => 'env',
                                       default => 'contents' };
    # Return an empty string:
    '';
    </ep-perl>

In other words: The method gets called twice, once for C<E<lt>ep-fileE<gt>>
and once for C<E<lt>/ep-fileE</gt>>. If it thinks, it should enter multi-line
mode (if the I<contents> attribute is not set, it returns C<undef>. In that
case EP is looking at the I<default> attribute of the handler which is
telling, that the lines between C<E<lt>ep-fileE<gt>> and C<E<lt>/ep-fileE<gt>>
ought to be written into the I<contents> attribute. Thus this attribute
exists, if the method is called a second time.

Note the use of the I<Symbol> package when accessing files: *Never* use
global handles like

    open(FILE, ...)

as this might break future multithreading code!


=head2 Selfloaded methods

In the above examples the extension methods have been compiled immediately.
This is not always a good idea: For example the C<ep-mail> method is
loading big external packages like I<Mail::Internet> for sending the
mail. In such cases you might wish to use HTML::EP's builtin self loader,
which is quite similar to that of CGI. We choose C<ep-mail> as an
example:

    <ep-perl package="HTML::EP">
    my $self = $_;
    # Create a string that can be compiled for loading the method:
    $AUTOLOADED_SUBS{_ep_mail} = <<'end_of__ep_mail';
        require Mail::Internet;
        sub _ep_mail ($$) {
	    my($self, $attr) = @_;
            ...
        }
    end_of__ep_mail

    $self->{_ep_funcs}->{ep-mail} = { method => '_ep_mail',
                                      default => 'body' };
    </ep-perl>

The advantage is that you have the method available, but the performance
penalty of loading it is almost omitted, if the method is not used.


=head2 Namespace pollution

So far extensions are inserted at run time only, usually by loading them
from external files. For example you might create extensions for building
a WWW shop and put them in, say, C<shop.lib>.

As soon as it is possible to make extensions permanent (with mod_perl or
an HTML::EP server) and extensions will be loaded at startup, there will
be more and more of such extension files. Experience shows, that namespace
pollution will finally become a problem. For example, any virtual Web
server might have a completely different method C<ep-buttons> for
inserting an automatically generated button frame.

Thus I propose to use a package model inherited from Perl's package
model, and start using it now:

If you create a shop extension, put it into a separate package,
C<HTML::EP::Shop>, say. When working with the extension, use

    <ep-package name="HTML::EP::Shop">

as the very first line, so that your Parser object becomes blessed into
the Shop package. And let your shop extension file look like this:

    use vars qw(@ISA);
    @ISA = qw(HTML::EP);

    # Define first extension method
    ...

    # Define second extension method
    ...

Note that this allows inheritage! Currently the extension file has to
be loaded with

    <ep-perl package="HTML::EP::Shop" src="shop.lib">

but this will change in the future.


=head1 TODO

=over 8

=item

mod_perl support

=item

Create an EP server that is accessible via a small C wrapper

=back


=head1 AUTHOR AND COPYRIGHT

This module is

    Copyright (C) 1998    Jochen Wiedmann
                          Am Eisteich 9
                          72555 Metzingen
                          Germany

                          Phone: +49 7123 14887
                          Email: joe@ispsoft.de

All rights reserved.

You may distribute this module under the terms of either
the GNU General Public License or the Artistic License, as
specified in the Perl README file.


=head1 SEE ALSO

L<DBI(3)>, L<CGI(3)>, L<HTML::Parser(3)>

=cut
