Intro(3pm)

πŸ“¦
version 2.5.0 Β· 2 versions
, in ubuntu jammy

πŸ¦‹ Intro(3pm) πŸ¦‹

User Contributed Perl Documentation

okay so bestie, welcome to the Embperl intro. This is the vibe check. πŸ’–

πŸ’– NAME πŸ’–

Embperl::Intro β€” Introduction to Embperl

πŸ—‚οΈ Content πŸ—‚οΈ

Here's the whole menu, no skips:

  • What is Embperl?
  • Embed Perl Code in HTML Documents
  • Meta-Commands
  • Dynamic Tables
  • Form Processing
  • Maintaining persistent (session) data
  • Breaking up your code in components
  • Debugging
  • Database Access
  • Security
  • Escaping/Unescaping

✨ What is Embperl? ✨

Embperl started out as a Perl module for just... embedding Perl into HTML, and then it grew up and became a full-featured system for building dynamic content (not only) under mod_perl. Version 1.x focuses on HTML documents, and lowkey it could be used for any sort of ascii files, and it brings a lot of features that are especially useful in a web-environment. Those features include handling of form data and dynamic HTML tables/lists, session management, and context sensitive escaping and unescaping. Moreover, you can break up your documents into small reusable components/objects and build an object-oriented website out of such objects, by using inheritance and specifically overriding parts of the page. Also Embperl can cope with pages that are screwed up by high-level HTML editors, so your designer can still use their favorite tool. periodt.

Embperl 2.0, which is a complete rewrite of the Embperl core, is not only much faster than 1.x, but adds new possibilities. You can extend or define your own syntax, which gives you the chance to trigger actions on certain tags or invent your own tags (creating a taglib). It is much more modularized, so specific steps could be replaced by a custom processor and more than one processor can act on a document before it goes to the browser (just like a Unix pipe). To enhance performance, 2.0 introduces caching of the output or intermediate steps. iconic.

Due to this modularization, it is now possible to replace the Embperl parser by an XML parser and to do XML processing, for example by plugging in an XSLT processer in the processing pipeline. Embperl 2.0 can utilize libxml2 and libxslt for XML and XSLT processing.

All versions of Embperl can be used offline (as a normal CGI script or as a module from other Perl code), but its real power comes when running under mod_perl and Apache. It's directly integrated with Apache and mod_perl to achieve the best performance by directly using Apache functions and precompiling your code to avoid a recompile on every request.

🧚 How does it compare to other templating solutions ? 🧚

Embperl is not the only processor for embedded Perl code. I guess every second webprogrammer builds his own templating engine. Most of them are very similar and easy, but do a good job in a certain environment. Often after a while these programmer discover they need more features and that other people in the same situation has already build a soltuion for their problems. At the moment there are five widely used Perl modules for generating dynamic web content (Embperl, Apache::ASP, HTML::Mason, Template::Toolkit and AxKit). All of these have their special strength. So why to use Embperl? We believe that Embperl, especialy the version 2.0, covers all of the aspects of these modules and integrates them in one module with addtionaly benefits that are unique to Embperl. Additionally Embperl is the fastest of these solutions, because it's engine is totaly written in C and is optimized for delivering dynamic content online. ate.

Another competitor for Embperl is PHP. PHP is developing a strong user base, because it is rumored to be easy to learn, and was designed specifically for HTML. Also PHP is probably one of the strongest open source alternatives to using Perl in your HTML, it's target is very webcentric and you may discover at a certain point that is has its limitations when you try to realize great projects. Also it's not true, like some anecdotal stories on the Web might want to make you believe, that PHP is faster than Perl. Perl, and therefore Embperl also, scales and performs very well for high end solution.

🎯 Focus of this document 🎯

This tries to be an introduction to the basics of Embperl. "perldoc IntroEmbperlObject" gives you an tutorial about how to build an object-oriented website.


πŸͺ„ How to Embed Perl Code in HTML Documents πŸͺ„

Perl code can be embedded in three ways:

  1. [- ... -] β€” Execute code
[- $a = 5 -]  [- $b = 6 if ($a == 5) -]

The code between the [- and the -] is executed. No output will be generated in the HTML. This is mainly for assignments, function calls, database queries, etc.

  1. [+ ... +] β€” Output the result
[+ $a +]  [+ $array[$b] +] [+ "A is $a" +]

The code between the [+ and the +] is executed and the return value (the value of the last expression evaluated) is output (sent to the browser in the HTML stream).

  1. [! ... !] β€” Execute code once
[! sub foo { my ($a, $b) = @_ ; $a * $b + 7 } !]

Same as [- ... -], but the code is only executed for the first request. This is mainly for function definitions and one-time initialization.

πŸͺ„ Meta-Commands πŸͺ„

Embperl support some meta commands to control the "program flow" within the Embperl document. This can be compared to preprocessor commands in C. The meta commands take the following form:

[$ <cmd> <arg> $]
  • if, elsif, else, endif β€” The if command is just the same as in Perl. It is used to conditionally output/process parts of the document. Example:
[$ if $ENV{REQUEST_METHOD} eq 'GET' $]
   This is a GET request
[$ elsif $ENV{REQUEST_METHOD} eq 'POST' $]
   This is a POST request
[$ else $]
   This is not GET and not POST
[$ endif $]

This will output one of the three lines depending on the setting of $ENV{REQUEST_METHOD}.

  • while, endwhile β€” The while command can be used to create a loop in the HTML document. For example:
[$ while ($k, $v) = each (%ENV) $]
   [+ $k +] = [+ $v +] <BR>
[$ endwhile $]

The above example will display all environment variables, each terminated with a line break.

  • do, until β€” The do until also create a loop, but with a condition at the end. For example:
[- @arr = (3, 5, 7); $i = 0 -]
[$ do $]
   [+ $arr[ $i++ ] +]
[$ until $i > $#arr $]
  • foreach, endforeach β€” Create a loop iterating over every element of an array/list. Example:
[$ foreach $v (1..10) $]
   [+ $v +]
[$ endforeach $]
  • var <var1> <var2> ... β€” By default, you do not need to declare any variables you use within an Embperl page. Embperl takes care of deleting them at the end of each request. Sometimes, though, you want to declare them explicitly. You can do this by using var:
[$ var $a @b %c $]

Has the same effect as the Perl code:

use strict ;use vars qw {$a @b %c} ;
  • hidden β€” hidden is used for creating hidden form fields and is described in the form field section below.

🌈 Dynamic Tables 🌈

A very powerful feature of Embperl is the processing of dynamic tables. This feature was designed mainly to display Perl arrays (one or two dimensional, regular and irregular), but can also be used in other ways.

πŸ“ Display a Perl Array πŸ“

[- @a = ( 'A', 'B', 'C') ; -]
<TABLE BORDER=1>
  <TR>
       <TD> [+ $a[$row] +] </TD>
  </TR>
</TABLE>

The above example simply displays a table with three rows containing A, B and C.

The trick is done by using the magical variable $row which contains the row count and is incremented for every row. The table ends if the expression which contains $row returns <undef>. The same can be done with $col for columns and $cnt can be used if you need a table which wraps after a certain number of elements.

This works with table/select/menu/ol/dl/dir

πŸ’Ύ Simple DBI Example πŸ’Ύ

Here is a simple DBI example that displays the result of a query as a two dimension table, with field names as headings in the first row:

[-
# connect to database
 $dbh = DBI->connect($DSN) ;

# prepare the sql select
$sth = $dbh -> prepare ("SELECT * from $table") ;

# execute the query
$sth -> execute ;

# get the fieldnames for the heading in $head
$head = $sth -> {NAME} ;

#continues on the next page...
# get the result in $dat
$dat = $sth -> fetchall_arrayref ;
-]

<table>
   <tr><th>[+ $head->[$col] +]</th></tr>
   <tr><td>[+ $dat -> [$row][$col] +]</td></tr>
</table>

πŸ’– Form fields πŸ’–

πŸ“₯ Posted form data available in %fdat/@ffld

okay so bestie, the hash %fdat is holding every single value of every form field that got submitted. and the array @ffld? it's got all the names, in the exact order they were submitted. order matters, iykyk πŸ’…

✨ Input/Textarea/Select tags take values from %fdat ✨

here's the magic: if you don't give an input tag a default value, and there's a value for that tag sitting in %fdat, Embperl just goes ahead and inserts it for you and sends it off to the browser. it's giving very much CGI.pm behavior 🫢

which means: post a form to itself, and the browser shows you the values you literally just typed. iconic, honestly.

πŸ™ˆ [$ hidden $] πŸ™ˆ

[$ hidden $] builds hidden form fields for all the fields that aren't in another input field. perfect for hauling data through confirmation forms β€” a wizard, for example 🌈

πŸ“ A simple Text input / Confirmation form

this next example? it's showing off basically everything Embperl can do. it's a simple form where you type in your name, your email address and a message. hit send and you see the data you just entered, and you can confirm it by hitting the "send via mail" button β€” or go back to the input form and change stuff. if you confirm, the data gets sent to a predefined e-mail address. and it also shows you how to do error checking: miss your name or your e-mail address and you get a corresponding error message and the input form shows up again 😭

here's the layout, bestie:

  1. the error checking
  2. the confirmation form
  3. sends the mail, if the input was ok and confirmed
  4. the input form itself

depending on the values of $fdat{check}, $fdat{send} and whether $fdat{name} and $fdat{email} contain data, the document decides which part to show πŸ‘‘

[-  $MailTo = 'richter\@ecos.de' ;

 @errors = () ;
 if (defined($fdat{check}) || defined($fdat{send}))
   {
   push @errors, "**Please enter your name" if (!$fdat{name}) ;
   push @errors, "**Please enter your e-mail address" if (!$fdat{email}) ;
   }
-]

[$if (defined($fdat{check}) and $#errors == -1)$]
[-
 delete $fdat{input} ;
 delete $fdat{check} ;
 delete $fdat{send}
-]

<hr><h3> You have entered the following data:</h3>
<table>
 <tr><td><b>Name</b></td><td>[+$fdat{name}+]</td></tr>
 <tr><td><b>E-Mail</b></td><td>[+$fdat{email}+]</td></tr>
 <tr><td><b>Message</b></td><td>[+$fdat{msg}+]</td></tr>
 <tr><td align="center" colspan="2">
    <form action="input.htm" method="GET">
      <input type="submit" name="send"
             value="Send to [+ $MailTo +]">
      <input type="submit" name="input" value="Change your data">
      [$hidden$]
   </form>
   </td></tr>
</table>

[$elsif defined($fdat{send}) and $#errors == -1$]

[- MailFormTo ($MailTo,'Formdata','email') -]
<hr><h3>Your input has been sent</h3>

[$else$]

<hr><h3>Please enter your data</h3>

<form action="input.htm" method="GET">
 <table>
   [$if $#errors != -1 $]
     <tr><td colspan="2">
     <table>
   <tr><td>[+$errors[$row]+]</td></tr>
     </table>
     </td></tr>
   [$endif$]
   <tr><td><b>Name</b></td> <td><input type="text"
                                       name="name"></td></tr>
   <tr><td><b>E-Mail</b></td> <td><input type="text"
                                         name="email"></td></tr>
   <tr><td><b>Message</b></td> <td><input type="text"
                                          name="msg"></td></tr>
   <tr><td colspan=2><input type="submit"
                            name="check" value="Send"></td></tr>  </table>
</form>

[$endif$]

πŸ” Maintaining persistent (session) data πŸ”

(Embperl 1.2 or above)

so hidden fields are cute and all when you're working with forms, but sometimes you need to keep persistent data around in a more general way. Embperl uses Apache::Session for this πŸ’œ and Apache::Session can store that persistent data in memory, in a textfile, or in a database. more storage methods may be supported in the future, bestie.

you could just call Apache::Session from an Embperl page yourself β€” but Embperl will do it for you 😌 all you have to do is drop your data into the hash %udat. next time the same user requests any Embperl page, %udat will have the same data in it. use it to keep state information for the user, simple as that. depending on your expire settings, the state can also be kept between multiple sessions ✨

and there's a second hash: %mdat. that one keeps state for one page, but for multiple users. classic example? a page hit counter πŸŽ€

 The page is requested [+ $mdat{counter}++ +] times
 since [+ $mdat{date} ||= localtime +]

that little guy counts the page hits and shows the date when the page was first requested. and ngl, don't stress about performance β€” as long as you don't touch %udat or %mdat, no action is taken. no cap 🫢


🧩 Breaking your code up into components 🧩

(Embperl 1.2 or above)

🎁 Subroutines

writing subroutines is so much better than pasting the same chunk of code over and over again. and yes, you can do it with Embperl too. like, if you've got text input fields with labels, this might just hit different for you:

[$ sub textinput $]
   [- ($label, $name) = @_ -]
   [+ $label +]<input type=text name=[+ $name +]>
[$ endsub $]

<form>
   [- textinput ('Last Name', 'lname')  -]<p>
   [- textinput ('First Name', 'fname') -]<p>
</form>

the sub metacommand starts the subroutine, and the parameters get passed in the array @_. you can do literally anything in the subroutine that you'd normally be able to do inside normal Embperl pages. and then Embperl lets you call it just like any other Perl subroutine: write its name, add the parameter list if you need it. slay πŸ’…

πŸ“Ž Execute

if you're working on an entire site instead of just a few pages, you already know there are always elements that show up in every page, or across a bunch of pages. instead of copying the source code onto every single page, you can include other Embperl pages in your page β€” so you only ever write the source once πŸŽ‰ such an included page could be a header, a footer, a navigation bar, whatever.

and Embperl doesn't just include those partial pages β€” you can pass arguments too. for example, to tell the navigation bar which of its own elements to highlight:

Example for a simple navigation bar

[- @buttons = ('Index', 'Infos', 'Search') -]
<table><tr><td>
    [$if $buttons[$col] eq $param[0]$] <bold> [$endif$]
    <a href="[+ $buttons[$col] +].html"> [+ $buttons[$col] +] </a>
    [$if $buttons[$col] eq $param[0]$] </bold> [$endif$]
</td></tr></table>
<hr>

now, if you're on the "Info" page, you include the navigation bar like this:

[- Execute ('navbar.html', 'Infos') -]

that includes the navigation bar stored in the file navbar.html, and passes the string 'Infos' as its first parameter. the navigation bar module itself uses a dynamic table to display one column β€” text plus a link β€” for every item in the array @buttons. and whichever text matches what got passed as the first parameter gets shown in bold 🫢

there's also a long form of the Execute call, which lets you control all the details of how the called page is executed. iykyk ✨

πŸ“š Creating Component Libraries

instead of making a separate file for every single piece of HTML-code you want to include, you can pack them all into just one library. to do that: split up every piece of code you want to include separately into one Embperl subroutine (the sub metacommand) πŸ“¦

then you use the import parameter of the Execute function to import all the subroutines defined in that one file into the namespace of the current page. after that, you can call them just like any other Perl subroutine 😌

and even better β€” if you want some systemwide Embperl subroutines, you can put all that Embperl code in a normal Perl module (a foo.pm file), install it into your Perl system (or a private library path), and use it like any other Perl module. just by saying:

 use mymodule;

πŸ› Debugging πŸ›

πŸ“œ Embperl log file

the log file is the main source for debugging. it shows you what Embperl is doing while it processes your page. depending on your debug flag settings, Embperl logs the following things:

  • Source
  • Parsing
  • Compiling
  • Environment
  • Form data
  • Evals (Source + Result)
  • Table processing
  • Input tag processing
  • HTTP headers
  • and more

and on top of all that? you can write your own debug information into the Embperl logfile by writing to the special filehandle LOG, which is opened by Embperl πŸ’–

πŸ’Ύ Database access

πŸ—„οΈ Plain DBI

Okay bestie, here's another example of using plain DBI inside Embperl. And ngl, unlike the one I showed you back in the dynamic tables chapter, this one works with explicit loops. πŸ‘€

[-
# connect to database
$dbh = DBI->connect($DSN) ;
# prepare the sql select
$sth = $dbh -> prepare ("SELECT * from $table") ;

# execute the query
$sth -> execute ;

# get the fieldnames for the heading in $head
$head = $sth -> {NAME} ;
-]

<table>
   <tr>
   [$ foreach $h (@$head) $]
       <th>[+ $h +]</th>
   [$ endforeach $]
   </tr>
   [$ while $dat = $sth -> fetchrow_arrayref $]
       <tr>
           [$ foreach $v (@$dat) $]
               <td>[+ $v +]</td>
           [$ endforeach $]
       </tr>
   [$ endwhile $]
</table>

πŸ¦‹ DBIx::Recordset

DBIx::Recordset is a module for easy database access. It's giving "let me handle the messy parts for you". πŸ’…

πŸ” Search Example

[-*set = DBIx::Recordset -> Search ({%fdat,
                                    ('!DataSource'   => $DSN,
                                     '!Table' => $table,
                                     '$max'   => 5,)}) ; -]
<table>
 <tr><th>ID</th><th>NAME</th></tr>
 <tr>
   <td>[+ $set[$row]{id} +]</td>
   <td>[+ $set[$row]{name} +]</td>
 </tr>
</table>
[+ $set -> PrevNextForm ('Previous Records',
                         'Next Records',
                         \%fdat) +]

πŸͺ„ Search sets up a Recordset object

So Search grabs the values out of %fdat and uses them to build a SQL WHERE expression. Which means what you actually search for depends on what gets posted to the document. Fr fr.

Like, if you request the document with http://host/mydoc.html?id=5, the example above will display every database record where the field 'id' contains the value 5. Iconic.

πŸ“¦ Data can accessed as array or via the current record

The result of the query can be accessed as an array β€” and lowkey important, this does not mean the whole array is actually fetched from the database. ✨

Alternatively, you can directly access the current record just by accessing the fields.

set[5]{id}   access the field 'id' of the sixth found record
set{id}      access the field 'id' of the current record

🏷️ Fields can be accessed by name

Normal DBI lets you access your data by column numbers. DBIx::Recordset says no ma'am, we use the field names instead. This makes your program easier to write, more verbose, and independent of database changes. Obsessed. πŸ’–

πŸ”€ PrevNextForm generates no/one/two buttons depending if there are more records to display

The PrevNextButtons function can be used to generate buttons for showing the previous record or the next records. PrevNextButton generates a small form and includes all the necessary data as hidden fields. To get it to work, it's enough to feed this data to the next request to Search. Periodt.

✍️ As for Search there are methods for Insert/Update/Delete

Example for Insert:

If %fdat contains the data for the new record, the following code will insert a new record into the database.

[-*set = DBIx::Recordset -> Insert ({%fdat,
                                     ('!DataSource'   => $DSN,
                                      '!Table' => $table)}) ; -]

πŸ”— Database table can also tied to a hash

DBIx::Recordset can also tie a database table to a hash. You need to specify a primary key for the table, which is used as key in the hash.

$set{5}{name}    access the name with the id=5
                 (id is primary key)

πŸ”’ Security

Okay so when you're running under mod_perl, all Perl code shares the same interpreter. Which means 😭 every application can access data from every other application. Embperl maintains a separate namespace for every document, which is enough to avoid accidentally overwriting other applications' data β€” but bestie, there is no real security here.

You can access any data from any other application that runs on the same server process under mod_perl if you explicitly specify a package name. πŸ’€ This is not a problem of Embperl itself, but caused by the design of Apache and mod_perl.

🌈 Escaping/Unescaping

πŸ“₯ Input: unescaping

Embperl is able to unescape the source it reads. That's useful when you use a high level HTML editor, which might add unwanted html tags like <BR> into your Perl code. Rude of it, honestly.

This feature is off by default in Embperl 2.0 and can be turned on with the configuration directive EMBPERL_INPUT_ESCMODE.

When turned on it does:

  • convert HTML escapes to characters (e.g. &lt; to <)
  • remove HTML tags from Perl code (e.g. <br> inserted by high level editor)

πŸ“€ Output: escaping

It's very important to do a correct escaping of your HTML output, to avoid security problems like cross-site-scripting. Therefor Embperl escapes all output that comes from Perl. 🫢

This escaping is context sensitive and uses HTML or URL escaping, depending on the context. It's also possible to use XML escaping.

The output escaping can be configured by the configuration directive EMBPERL_ESCMODE or changed anytime inside any page by setting $escmode.


🧭 How to continue

There are two addtionaly introduction documents:

  • perldoc IntroEmbperlObject gives you a tutorial about how to build an object-oriented website. πŸŽ€
  • perldoc IntroEmbperl2 describes the advanced features of Embperl 2. ✨

For a full documentation read perldoc Embperl and perldoc Config. πŸ“š

You can find additional information on http://perl.apache.org/embperl


And that's a wrap on part 3, bestie! 🫢 This little saga was written by the perl folks β€” perl v5.34.0, dated 2022-02-06, and the page you just finished is Intro(3pm). Go forth and embed, you absolute main character. πŸ’…πŸ‘‘

πŸ“¦ where this page comes from