Introduction: Just What is Molly?

HTML, XML, XHTML & MAML

When Tim Berners-Lee created HTML (HyperText Markup Language) in the early 1990s he based it on the concept of tag markup used by SGML (Standard Generalized Markup Language) and so we all became familiar with the practice of structuring (and formatting in the pre-CSS days) text with tags like <h1> and <p>. HTML was rather loosely defined and the various browsers' developers each created their own versions of it and added their own tags, so HTML evolved, though somewhat haphazardly. Before long two things became clear; one, that HTML was inconsistent and difficult for software to parse and interpret correctly, and two, it was neither extensible, nor sufficient for all of the tasks web developers wished to do. To address these two deficiencies the W3C (World Wide Web Consortium), headed by Berners-Lee, created XML and XHTML. XML stands for eXtensible Markup Language. XML is basically a set of rules for creating markup languages that use tags like HTML. By following these rules any software developer can create a markup language to serve whatever purposes they might have. XHTML is a reformulation of HTML that follows the rules of XML. This slightly stricter version of HTML has supplanted HTML as of version 4.01, and provides web developers several benefits including a cleaner separation of structure and presentation than HTML and the ability to be used and parsed together with other XML-based markup languages.

Molly uses an XML-based markup language named MAML (Molly Active Markup Language) mixed together with XHTML to allow web site developers to easily add sophisticated server-side functionality to their sites without having to learn complex programming languages like PHP, Perl, Java, ASP, or .NET. Instead, web developers use the XHTML tags they already know together with new MAML tags that Molly uses to generate more XHTML dynamically based on things such as database lookups which would normally require a fair amount of custom programming.

History of Molly

In the mid 1990s one of us (Vullo) began building web-based applications for dental education. These included online learning and electronic dental records. Even then, it was clear that web sites needed pages which were dynamically generated from information stored in databases. At the time the database he used was Apple's FileMaker Pro and the tool for embedding that information into a web page was Blue World's Lasso.

Several years later Vullo was called upon to create a new distance education and medical record system. This was to be a more ambitious project and after prototyping with Lasso it became clear that a more robust and flexible system would be required. Fortune smiled and PHP 4 was released about this time and with its maturity was rapidly developing a reputation as an outstanding server-side web development language. PHP also supported access to multiple database systems including the then up-and-coming MySQL.

While the typical PHP approach to building web applications at the time was to simply build HTML pages and embed snippets of stand-alone PHP code wherever dynamic content was required, Vullo decided to take a different approach. He recognized that such a development style quickly becomes difficult to support and scales poorly with large sites. Instead he decided to build an organized code library, encapsulating oft-needed functionality into generic functions. Then, instead of embedding chunks of code into a web page, a single line function call would be used instead, much more like an HTML tag than an embedded program. Thus was born (the as-of-yet unnamed) Molly version 1. Soon after this one of us (Hoey) gave birth to a daughter and named her Molly. Vullo named the software after Molly as a gift to her mother.

Soon thereafter the W3C released XML and XHTML and it became clear that the next logical step was to eliminate the PHP entirely from the web pages and replace the function calls with XML tags designed to be usable by HTML authors without any need of programming or understanding PHP. This change necessitated a new architecture for Molly, and so Molly II was developed.

How Molly is different from other Systems

Over the years Molly has been compared with various other systems such as ColdFusion, Mambo, Joomla, and Ruby on Rails. While each of these systems has its strengths, and share some abilities with Molly, they are also different enough in design, philosophy, architecture, and implementation for us to confidently continue to develop and use Molly. Here then is a brief comparison of Molly's similarities and differences to these other tools:

ColdFusion

Adobe's ColdFusion is perhaps most like Molly in that it uses a tag syntax. There are a number of notable differences however, not the least of which is that ColdFusion is expensive ($1,299 - $7,499 as this was written) and proprietary, whereas Molly is free and open source. While ColdFusion uses tags as its syntax (CFML - ColdFusion Markup Language) it is not XML compliant and so would break any standards-based XML parser. ColdFusion is also, despite its tag syntax, considered a programming language and in fact has an ECMAScript-like (but not compatible) syntax as well.

Mambo & Joomla

Mambo & Joomla are two versions of the same content management system which forked in the midst of considerable controversy and angst among its developers. While there are a lot of devoted users of the products, it is perhaps because they have invested so much energy in building sites with the products and choosing sides in the split. Both products are built with PHP, are ostensibly open source, and take the same approach as Molly I (which we abandoned for the simpler to use XML syntax and cleaner architecture of Molly II and beyond). Mambo and Joomla support only MySQL whereas Molly supports MySQL, Oracle, PostgreSQL, ODBC, SQLite, LDAP and many others.

Ruby on Rails

Perhaps the single most backward-named computer software, Ruby on Rails is actually an object framework (Rails) built in a programming language named Ruby. It has the advantage of being free and open source and was hailed for a while as "the next big thing" in web development. But in the authors' opinion Ruby on Rails has two fatal flaws: First is a rather steep learning curve and the necessity to adopt the Rails system whereby structure happening automatically based on a naming scheme. Second, and perhaps more important, is that many developers have experienced scalability issues for large or busy sites.

How Molly Works

Molly is a web server-side technology, which is to say that all of the work that Molly does happens on the web server. The user never sees any of Molly's MAML tags or underlying programming. Contrast this with client-side technologies like JavaScript where all the user needs to do is "View Source" in their browser and they can see all of the code. When a user does that on a page processed by Molly, all they see is the XHTML that Molly generates.

So, being a server-side technology, Molly has to be installed on a web server. How to do that is explained in Appendix I: Installing Molly.

Molly uses special new tags to add server-side functionality to your web pages. Because XHTML is a language built in XML it allows us to add other XML languages' tags to our code. Molly implements one such language — Molly Active Markup Language, or MAML. MAML tags look and are written just like XHTML tags with one difference; they include the "maml:" prefix that tells Molly (and other XML processors) that those tags are not XHTML. That way MAML can have tags with the same name as XHTML tags and there is no problem. For example, XHTML has the <form> tag and Molly has the <maml:form> tag. These can both be used in the same document without any problem. At this point you may be wondering why Molly would have her own form tag and not just call it something else. Well, Molly's forms look and act just like XHTML's forms, except that Molly's automatically connect to the database and process the data when the user clicks the submit button. With an XHTML form the webmaster would have to write all of the necessary server-side programs necessary to do that.

So Molly is at her heart an XML parser, but she's really much more. She's what we call an "abstraction layer." Molly's MAML tags are abstractions that hide all the underlying programming from you so that you can focus on building your web site and not on the details of programming the functionality that makes your site dynamic. Just like XHTML and CSS together form an abstraction layer that hides the complexity of delivering content over the internet and rendering it into the pixels you see on your computer screen.

Molly is written in a programming language called PHP. (Programming languages themselves are abstraction layers above the binary code that computer processors actually read and write.) Molly is designed to be extensible and so if you know PHP and wish to add new functionality that is not only possible, but fairly easy to do thanks to over a decade of experience in designing and building her architecture. Part III: Under the Hood explains that architecture and the rules we follow when programming Molly.

How Molly Helps

Makes building sites rapid and easy. :o)


Part I: Learning Molly & MAML

If you already know how to build web pages in XHTML, then you are well on your way to learning how to use MAML, since MAML uses simple tags very much like those with which you are already familiar. The first thing we will cover is the basic structure of a MAML page. We will demonstrate how MAML is translated by Molly into XHTML. After that we will explain how to to use a few MAML tags, and how they are transformed by Molly into XHTML.

A Basic MAML page's boilerplate code is virtually identical to a normal XHTML page. So to see the difference, let's build "Hello World" in XHTML and in MAML.

(Why "Hello World?" Well this is a computer book, and it's the law. ;o)

Basic HTML Document:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Hello World HTML</title>
</head>
<body>
    <p>Hello World!</p>
</body>
</html>

Basic MAML Document:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:maml="http://interpersonalnet.com/maml/">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Hello World MAML</title>
</head>
<body>
    <p>Hello World!</p>
</body>
</html>
 

See the difference? Yeah, it's hard. The only difference is on the third line. Here, this time I'll highlight it so you can see it easier:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:maml="http://interpersonalnet.com/maml/">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Hello World MAML</title>
</head>
<body>
    <p>Hello World!</p>
</body>
</html>
 

It's not much, but it's very important. What does that snippet of extra code do? Well, it does a little bit of XML magic and adds the "maml" namespace to the document so that Molly's XML parser can process the file and do all the cool things that make Molly what she is. That namespace declaration is why Molly's tags all begin with "maml:" like this:

<maml:box>Some text with a box around it.</maml:box>

This use of namespaces also makes the MAML XML syntax compliant with XML and XHTML standards, so any XML editor or processing software should have no problem with Molly's MAML code.

OK, so let's take our simple example a little further. We'll add the <maml:box> tag to our Hello World MAML file like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:maml="http://interpersonalnet.com/maml/">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Hello World MAML</title>
</head>
<body>
    <p>Hello World!</p>
    <maml:box>Some text with a box around it.</maml:box>
</body>
</html>

Now if we save this as a file with a .maml extension like hello_world.maml and view it in a browser from a Molly Server it will look something like this:

Hello World!

Some text with a box around it.

(Remember, Molly is a "server-side" technology and so MAML pages have to be viewed in a web browser via HTTP from a server where Molly is installed. If you view the page from your local hard drive via the browser's file:// URL the browser will not understand the MAML code.)

Molly processes the MAML file and generates the following XHTML in its place:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 
<head>
    <meta http-equiv = "content-type" content = "text/html; charset=utf-8">
    <title>Hello World MAML</title>
    <link rel="stylesheet" type="text/css" href="/~rvullo/m9/decor/default.css" />
    <style type="text/css">
 
    </style>
 
    <script type="text/javascript">
 
    </script>
</head>
<body>
    <p>Hello World!</p>
    <div class="box">
    <p class="title"></p>
    <p class="contents">
        <span class="boxbottom">
Some text with a box around it.        </span>
    </p>
</div>
 
</body>
</html>

Now at this point you don't really have to worry about the specific code that Molly generated, this is simply to illustrate the point that Molly translates the MAML tags into XHTML and automates a lot of things like adding CSS and JavaScript when necessary.

Getting Started with Database Access

Molly makes it very easy to fetch information from a database and put it on a web page formatted however you want. Here is a simple example of that:

Notice that clicking the column titles sorts the results.

Here is the MAML and HTML source code to generate the above list (line numbers added for explanation reference):

  1. <maml:fetch table="molly_test" key="name" criteria="true" sort = "name" order = "ascending">
  2. <table style="width:22em; background-color: #f4f5fb;padding:1em;">
  3. <tr>
  4. <th><maml:sort sort="name">Name</maml:sort></th>
  5. <th><maml:sort sort="eyecolor">Eye Color</maml:sort></th>
  6. <th><maml:sort sort="age">Age</maml:sort></th>
  7. </tr>
  8. <maml:row>
  9. <tr>
  10. <td><maml:field name="name"/></td>
  11. <td><maml:field name="eyecolor"/></td>
  12. <td><maml:field name="age"/></td>
  13. </tr>
  14. </maml:row>
  15. <tr>
  16. <th colspan="3" style="text-align:right;">Total Records: <maml:numrows/></th>
  17. </tr>
  18. </table>
  19. </maml:fetch>
  1. The <maml:fetch> tag is used to set up a query to retrieve information from the database. The table attribute specifies which table to search. The key attribute specifies the key field for the table. The criteria attribute specifies the search. In this case we set criteria="true" so Molly fetches all of the records in the table. You could be more specific with something like criteria="age > 10" and fewer records would be found. Finally sort = "name" and order = "ascending" tell Molly to return the results sorted by the name field.
  2. This is an ordinary <table> tag. Because you mix MAML tags freely with HTML you can format your output however you wish. You could use an ordered list instead of a table if you like.
  3. Our first table row will have the column headers.
  4. This is a simple HTML <th>Name</th> one would normally use to create a table header with the addition of a <maml:sort sort="name"> tag. This simple tag tells Molly to create all the necessary code to allow users to click on the column head and retrieve a sorted list based on the field name specified in the sort attribute.
  5. As above we've added sorting, by eye color in this case.
  6. And here we're sorting by age.
  7. End of the header row of the table.
  8. Everything between the <maml:row> and </maml:row> tag pair will be repeated for every record found by the query specified in the <maml:fetch> tag.
  9. Because we're building an HTML table we'll repeat a <tr> table row.
  10. This HTML <td> contains the <maml:field name="name"/> tag which will be replaced by the results of the search for each row. The name attribute specifies the database field name.
  11. Likewise this table data cell will be filled with eye color.
  12. And this with data from the table's age field.
  13. End of the table row.
  14. And end of the record (and the portion of the code which will repeat for every record found).
  15. We're adding one last row to our table…
  16. Which will display the number of rows Molly found in the database (and rendered above).
  17. And we have to close all of our open tags.

Tokens

Tokens are place holders for values which Molly will substitute before sending the page to the browser. (Programmers can think of these as variables.) Some tokens are pre-defined as part of Molly's configuration to make it easy, for example, to create a path to an image which will work from any of the site's pages:

<img src="*[HTMLRoot]*decor/icons/gradcap-7.png" />

Other tokens can be set by the webmaster using the <maml:token> and <maml:persist> tags.

Pre-Defined Tokens

Configuration Tokens (Set in the site's .ini file and molly_config database table)

*[HTMLRoot]* —> HTML Path to the root of the site
*[SkinDirectory]* —> Path to skins directory, relative to *[HTMLRoot]*
*[Skin]* —> Current Skin
*[SystemRoot]* —> HTML Path to Molly's system directory
*[FileRoot]* —> Unix path to the root of the site
*[QueryString]* —> Query String (if any) sent by browser when requesting this page†
*[SkinScripts]* —> JavaScripts Molly will be inserted into the page's head†
*[ConfigTable]* —> The name of the table from which the site's configuration settings have been read.

†In general webmasters should not access these, they are for internal system use only

Tag-Specific Tokens

Some tags as part of their functionality create pre-defined tokens as well. For example, the <maml:login> tag will create tokens when a user logs into the site:

Molly Page Tokens relevant to login

*[LoggedIn]* —> Set to 1 (true) if the user is logged in, 0 (false) if not
*[LastName]* —> logged in user's last name
*[FirstName]* —> logged in user's first name
*[Salutation]* —> logged in user's salutation (i.e. Miss, Mrs, Mr, Dr, etc.)
*[UserID]* —> logged in user's unique user id (integer)
*[LoginName]* —> logged in user's unique username/alias

Currently Defined Tokens

The following is a dynamically generated list of all the currently defined tokens for this page view in the Molly installation you are using to read this page:


If you wish to see the current values for all of the tokens on your site, you can use the following code on a .maml page:

<div>
   ActiveLinkColor: *[ActiveLinkColor]*<br />
   AttachmentsDirectory: *[AttachmentsDirectory]*<br />
   BackgroundColor: *[BackgroundColor]*<br />
   BoxFrameColor: *[BoxFrameColor]*<br />
   ConfigTable: *[ConfigTable]*<br />
   FileRoot: *[FileRoot]*<br />
   FirstName: *[FirstName]*<br />
   FormDark: *[FormDark]*<br />
   FormLight: *[FormLight]*<br />
   FormMedium: *[FormMedium]*<br />
   HTMLRoot: *[HTMLRoot]*<br />
   HoverLinkColor: *[HoverLinkColor]*<br />
   LastName: *[LastName]*<br />
   LinkColor: *[LinkColor]*<br />
   LoggedIn: *[LoggedIn]*<br />
   LoginName: *[LoginName]*<br />
   MenuColor: *[MenuColor]*<br />
   MenuLinkColor: *[MenuLinkColor]*<br />
   MenuRolloverBackgroundColor: *[MenuRolloverBackgroundColor]*<br />
   MenuRolloverTextColor: *[MenuRolloverTextColor]*<br />
   MenuSelectedBackgroundColor: *[MenuSelectedBackgroundColor]*<br />
   MenuSelectedTextColor: *[MenuSelectedTextColor]*<br />
   MenuTextColor: *[MenuTextColor]*<br />
   PageColor: *[PageColor]*<br />
   QueryString: *[QueryString]*<br />
   Salutation: *[Salutation]*<br />
   SelectedTabColor: *[SelectedTabColor]*<br />
   SidebarHeadingBackgroundColor: *[SidebarHeadingBackgroundColor]*<br />
   SidebarHeadingTextColor: *[SidebarHeadingTextColor]*<br />
   SidebarLinkColor: *[SidebarLinkColor]*<br />
   SiteName: *[SiteName]*<br />
   Skin: *[Skin]*<br />
   SkinDirectory: *[SkinDirectory]*<br />
   SkinScripts: *[SkinScripts]*<br />
   SystemRoot: *[SystemRoot]*<br />
   TabColorHover: *[TabColorHover]*<br />
   TextColor: *[TextColor]*<br />
   UnselectedTabColor: *[UnselectedTabColor]*<br />
   UserID: *[UserID]*<br />
   VisitedLinkColor: *[VisitedLinkColor]*<br />
   WindoidFieldColor: *[WindoidFieldColor]*<br />
   WindoidFrameColor: *[WindoidFrameColor]*<br />
   copyright: *[copyright]*<br />
   javascript: *[javascript]*<br />
   stylesheet: *[stylesheet]*<br />
   tagline: *[tagline]*<br />
</div>

Skins

Molly uses a "skins" system to facilitate changing the look and feel of your web site, as well as allowing you to change the way many MAML tags render their output. All of the presentation code and images for Molly are contained in the decor directory in the root of your Molly site. Skins are contained within this decor directory (though the path to skins may be changed in your molly.ini file).

Anatomy of a Skin

Within the skins directory can be one or more directories, the name of which is the name of the skin. The name of the skin currently being used by this particular Molly installation is "mx." Skin directories have a specific structure and set of files. There are two required files:

And three required directories:

main.css File

This is the stylesheet that will be linked to every .maml page on your site. The file will be processed to replace tokens with their appropriate values. Most of these (the presentational ones) are set in the molly_config table of the database. Tokens which provide appropriate paths are set in the molly.ini file.

main.js.htmf File

This is a snippet of HTML (.htmf stands for hypertext markup fragment) which will be inserted into the <head></head> section of each page. This is where you should insert any JavaScript code which you would like to have on every page of your site.

images Directory

This directory contains any images used in the design of your site, such as background images, logos, etc. Images which are content (i.e. photos of your business, etc.) do not belong here. They should be outside of the decor directory which is reserved for presentational aspects of the site. Images in this directory may be templates for Molly's colorizing code and if so should be named with ".tplt" before the ".jpg" or ".png" file extension to make this clear.

scripts Directory

This directory contains all JavaScripts required by the skin. At a minimum it should have a main.js file which will be included in every page.

templates Directory

This directory contains all of the template files used by Molly to generate the resulting HTML of most of the MAML tags. In general when creating your own skins you can just copy the default templates directory with all of its template files and you will be fine. Most of the changes you are likely to want to maje can be accomplished by editing the main.js.htmf file. If, however, you wish to actually change the HTML (structure) that Molly generates, then these are the files you would edit.

Template files follow a naming convention and it is important that you understand and respect this convention if you are editing them or creating new ones for new MAML tags you might be creating (in a module, for example, or if you are working on extending Molly). Template files must have a ".tplt" file extension. Template files are named for the tag they are used by and in general since most tags have a begin tag and an end tag there is a separate file for each of these. So, for example, the <maml:windoid> tag uses the windoid.begin.tplt template file and the </maml:windoid> tag uses the windoid.end.tplt template file.

This system provides quite a bit of flexibility in modifying how Molly renders a page without editing the underlying PHP code. If you wish to do this, it is best that you create your own skin to do so. The easiest way to do that is to duplicate an existing skin, give it a new name, then edit your molly.ini file to use the new skin.

Skins and the molly_config Database Table

Skins will usually provide one or more SQL files for populating the molly_config table with appropriate values for tokens in the main.css file.

Other Stuff I need to write about:

Users and Permissions

In your database, there should be a molly_login table and a molly_username table. This is where the information for each user who can log into your Molly site gets stored. The user_id number in the molly_login table must match with the user_id number of the corresponding user in the molly_username table.

The molly_permissions table is where you can set the editing permissions for each user. Again, the user_id number in this table must match with the corresponding user's user_id number. The group_name column lists the permissions each user has. The options are admin, editor, and config. These are the values that can be entered into the permitted attribute in the <maml:block> tag so that only certain users can edit that block. The permitted column shows whether or not the user has that permission; "1" means permitted, "0" means not permitted. The group_type column has three options: shared, independent, and exclusive. Shared means that users in that group can grant and revoke permissions for each other. Independent means that there are also multiple users in that group but they cannot grant or revoke permissions for each other. Exclusive means that there can only be one user in that group.


Part II: Building Sites with Molly

Page Approach vs. Wiki Approach

When building a site with Molly, there are two ways to approach it. The first way is to create multiple pages by creating multiple maml files and linking between the pages. The <maml:block> tag can be used to fill in the content of each page so that it can be edited dynamically from the web. The second approach is to use one maml file with multiple wiki pages from the database. Again, the <maml:block> tag can be used to set which wiki page will be displayed on each page, but only one wiki block can be placed on each maml page.

Creating a New Skin

Files for skins can be found in the decor directory. When building your website with Molly, you may want to create some of your own skins in addition to the default skins. If you already have an HTML webpage with a stylesheet that you would like to make into a skin, here are the steps to do so.

  1. Test your HTML template with the W3C Validator.
  2. Once it checks out, save the template as a .maml file.
  3. Replace the doctype and HTML tags with Molly versions (XHTML 1.1).
  4. Test your template in Molly to make sure the XHTML is well formatted.
  5. Create a new skin by duplicating an existing skin.
  6. Delete the existing CSS file in the skin directory and the images in the images folder.
  7. Copy your stylesheet into the skin directory and rename it “main.css”.
  8. Copy your images into the images folder.
  9. Change the skin in the molly.ini file.
  10. Fix any image paths in your HTML file or stylesheet.

Now that you’ve created your new skin, you can make the style more intelligent by replacing hard coded colors in your stylesheet with Molly tokens, which come from the molly_config table in your database. You can also colorize your images.

To make your pages more intelligent, you can change your template to a .htmf file and move it into the snippets folder. Use the maml:include tag to include snippets in your webpages. You can also use maml:block tags optionally surrounded by maml:windoid tags to make content editable via the web.


Part III: Under the Hood

Main Directory Structure

The default directory structure of a Molly installation is as follows:

folder open
Molly Distribution
vertical line
node
.htaccess
node
folder closed
system
node
folder closed
modules
node
folder closed
decor
vertical line
node
folder closedskins
node
folder closed
docs
node
folder closed
error
node
index.maml
vertical line
etc.
.htaccess
The .htaccess file is Apache's way of setting configurations on a per-directory basis. If your web server does not support .htaccess you will need to enable these configurations in other ways (i.e. via httpd.conf and php.ini). Here is a typical .htaccess file (line numbers added for documentation):
  1. AddType application/x-httpd-php .maml .html .php .tplt .ini .inc .txt .css .mss .php4 .php3 .phtml
  2. DirectoryIndex index.maml index.html index.php
  3.  
  4. php_flag register_globals off
  5.  
  6. SetEnv MOLLY_INI molly.ini
  7.  
  8. php_value short_open_tag off
  9.  
  10. php_value auto_prepend_file /Users/rvullo/Sites/mx/system/loader.php
  11. php_value auto_append_file /Users/rvullo/Sites/mx/system/parser.php
  12.  
  13. # 404: Not Found
  14. ErrorDocument 404 /~rvullo/mx/error/404.maml
  15.  
  16. IndexIgnore .htaccess
  17.  
  18. Options -Indexes
  19.  
  20. php_value upload_max_filesize 30M
Line-by-line Explanation:
  1. Tells Apache to process .maml, .html, .css, etc. files with PHP so that Molly can parse them.
  2. Tells Apache that files named "index.maml" should be loaded instead of listing the contents of a directory.
  3. #
  4. Tells PHP to turn off automatic global generation. This is the default configuration for most PHP installations now. It is included in Molly's .htaccess file just to be sure for security reasons.
  5. #
  6. This is where you tell Molly which .ini file to read for configuration information. By default this is simply molly.ini but if you have multiple Molly installations it is helpful to name each site's .ini file such that you can keep track of them.
  7. #
  8. Some PHP installations have short open tags enabled such that blocks of PHP code can begin with <? instead of <?php. This, however, breaks when you have an <?xml declaration.
  9. #
  10. Tells PHP to automatically include Molly's loader code at the beginning of every processed file.
  11. Tells PHP to automatically include Molly's parser code at the end of every processed file.
  12. #
  13. #
  14. Tells Apache to send Molly's not found page instead of the default apache message. This can be used to automatically redirect users or simply to customize the look of the error page.
  15. #
  16. Tells Apache not to serve .htaccess files.
  17. #
  18. Turns off Apache's automatic directory listings.
  19. #
  20. If your site allows file uploading this directive tells PHP how large of a file to allow.
system
This directory contains the bulk of the code that makes Molly work. See the next section for details.
modules
This is where add-on modules for Molly are located. For details on configuring and using modules see the Modules Reference appendix.
decor
The decor directory is where all files related to the site's look are kept, primarily in the skins subdirectory.
skins
Molly supports the notion of skins for easily varying the look and feel of your site. See the Skins section for details on how they work.
docs
Molly's documentation, primarily this page that you are reading right now. The docs directory is not required on a production site and may be safely removed.
error
Directory for error pages, notably the 404 Not Found page specified in Molly's .htaccess file (above).
index.maml
Default Molly site home page.

System Folder Directory Structure

folder open
system
vertical line
node
molly.ini
node
loader.php
node
parser.php
node
folder closed
core
vertical line
node
folder closed05_utility.inc
vertical line
node
folder closed10_date_time.inc
vertical line
node
folder closed15_file.inc
vertical line
node
folder closed20_database.inc
vertical line
node
folder closed25_sessions.inc
vertical line
node
folder closed27_security.inc
vertical line
node
folder closed30_XML.inc
vertical line
node
folder closed40_tags.inc
vertical line
node
folder closed70_modules.inc
vertical line
node
folder closed80_environment.inc
vertical line
node
folder closed90_parser.inc
vertical line
node
folder closedtags
vertical line
vertical line
last node
folder closedhtml.override.inc
vertical line
vertical line
last node
folder closedmaml.ajax.inc
vertical line
vertical line
last node
folder closedmaml.constructs.inc
vertical line
vertical line
last node
folder closedmaml.database.inc
vertical line
vertical line
last node
folder closedmaml.format.inc
vertical line
vertical line
last node
folder closedmaml.security.inc
vertical line
vertical line
last node
folder closedmaml.tokens.inc
vertical line
vertical line
last node
folder closedmaml.xml.inc
vertical line
node
folder closeddatabase
node
folder closed
scripts
vertical line
etc.
molly.ini
This file contains Molly's configuration settings including paths, database usernames and passwords, etc. May be named anything.ini to make multiple Molly installations more manageable.
loader.php
This script is automatically run at the beginning of a page load (because of the PHP auto_prepend_file directive in Molly's .htaccess file. It reads the molly.ini file (above) and sets up everything for Molly.
parser.php
This script is automatically run at the end of a page load (because of the PHP auto_append_file directive in Molly's .htaccess file. It does the actual parsing of Molly's MAML tags and substitution of tokens.
core
This directory contains all of the include (.inc) files that provide the bulk of Molly's functionality. All .inc files within this directory (and the tags directory with in it) are automatically included by loader.php (and 40_tags.inc). The include files directly inside the core are named with numerical prefixes because they must be loaded in order due to dependencies.
05_utility.inc
Utility functions for Molly programmers.
10_date_time.inc
Code for converting and manipulating dates, time, time zones, etc.
15_file.inc
File reading functions.
20_database.inc
Database abstraction functionality.
25_sessions.inc
Callback functions for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers.
27_security.inc
Molly's user login system.
30_XML.inc
XML, DOM, and XSLT processing (no functionality yet).
40_tags.inc
Contains prototype tag and template classes, page building utility functions, and loads all of the tag class definitions from the tags directory.
70_modules.inc
Loads code for modules. Modules are optional add-ons to Molly. Over time some modules may migrate into Molly's core.

Modules to be loaded are specified in the molly.ini file for the site in the [Modules] section. This file automatically includes any .inc files found within each module's directory.

Each modules directory contains a documentation file named docs.htmf which is automatically be included into the Modules appendix of this document.
80_environment.inc
Utility code that Molly uses to determine the current environment - for example if a tag has been implemented.
90_parser.inc
The actual parser code called by parser.php.
tags
This directory contains the include files with all of Molly's MAML tag class definitions. They are in separate files based on functionality for easier coding and support.
html.override.inc
Molly processes a few HTML tags in order to simplify developing MAML pages. These include the <html>, <head>, and <style> tags.
maml.ajax.inc
Under development: hopefully simple way to implement AJAX.
maml.constructs.inc
Under development: rudimentary branching functionality.
maml.database.inc
Database access tags such as <maml:fetch> and <maml:form> and all of their associated tags.
maml.format.inc
Tags which implement user interface components such as menus and windoids.
maml.security.inc
Tags for implementing user login and user/group specific viewing permissions.
maml.tokens.inc
Tags which allow webmasters to create tokens either on a per-page-view basis or a per-session basis.
maml.xml.inc
Contains the class definition for the <maml:nothing> tag. This tag acts as a root XML element for MAML files which generate non-web-page results for use in AJAX and web services. If we re-implement Molly's SOAP functionality, that would go here.
database
Contains the ADODB database abstraction code employed by Molly. (Longtime Molly developers should note that this open source solution replaces Molly's original database abstraction code which had been developed specifically for Molly.)
scripts
Javascript code used by Molly.

Files to be parsed by Molly

Extension Action
.php Process as normal php, no Molly functionality
.inc PHP include files
.html Process similarly to Molly 1, that is, set all the globals and include basic function and object libraries and module libraries, then procede to pass the file through the php parser. (Note that for normal HTML files this does essentially nothing, but that it allows you to minimally incorporate some of Molly's functionality if you understand the underlying architecture.)
.maml Set all the globals and include all the libraries and modules, then parse the file through Molly's MAML XML parser.
.tplt template files
.ini prevent being served to the web
.txt (Maybe turn into a nice formatted web page?)
.mss & .css Treated like a template file - that is, all *[tokens]* are replaced with config values

Molly's Parsing Engine

Previous versions of molly used the SAX (Simple API for XML) parser using xml_parser_create(). SAX was available in PHP 4 and compatible with PHP 5. It functions as a stream parser with an event-driven API. It is a push parser; the user defines a number of callback methods that will be called when the parsing events occur. The SAX interface does not deal in elements, but in events that correspond to tags. SAX parsing is unidirectional, which means that previously parsed data cannot be reread without restarting the parsing operation. Molly's new engine uses the new XMLReader object. This is a wrapper on Libxml2, which is a widely used XML C parser. Like SAX, XMLReader is also a stream based parser. But unlike SAX, XMLReader is a pull parser, meaning it only parses what is asked for by the application. It acts as a cursor moving forward on the document stream and stopping at each node on the way. XMLReader has a very small memory footprint and is faster than SAX because there is no need for it to process callbacks you do not care about.

Embedded JavaScript

Molly is an XML Parser, so whenever she sees a < she thinks a tag is beginning. Now obviously this isn't the case in a block of JavaScript. Browsers have learned to ignore code inside <script></script> tags, but technically that's not correct. The solution is to place the JavaScript code inside a CDATA block which tells the XML parser not to parse that text.

<script language="javascript" type="text/javascript">
<![CDATA[
 
    // JavaScript code goes here
 
]]>
</script>

Appendix I: Installing Molly

Might be helpful: http://shapeshed.com/journal/setting_up_local_websites_on_snow_leopard/

Environment

Molly is designed to be deployed on a Unix or Linux system running the Apache web server and PHP 5. Molly users have successfully installed and used Molly on Windows servers running Apache, however the core developers do not currently test or support that environment. For the curious, the main development platform for core development is currently Mac OS X (version 10.6.2 - Snow Leopard), PHP 5 (version 5.3.0), Apache 2 (version 2.2.13), and MySQL Server (version 5.1.43). The main Molly site (molly.rit.edu) is deployed on production server running Linux (version), Apache 2 (version) PHP 5 (version), and MySQL (version). Molly should run fine on any recent version of the above software as we try to avoid specific late version dependencies.

Downloading and Uploading Molly

The latest version of Molly can always be downloaded from molly.rit.edu. Molly is distributed as a GZipped Tar file. Upload the Molly archive to your server's web directory. On many Unix and Linux systems this directory will be named "public_html" or "www" and on most Macintosh servers it is named "Sites."

  1. Using SSH connect to your server and log in. Change directories to your web directory.
  2. If you do an ls you should see the .tar.gz file that you just uploaded.
  3. Uncompress the molly archive file into a tar (Unix "tape archive") file, then untar the resulting .tar file.:
    gunzip molly.tar.gz
    tar -xf molly.tar

At this point you should have a directory named molly inside your web directory. (The Unix tar program preserves all of the directories' and files' privileges, so they are all set for you.)

Configuration

Once you have Molly's files installed on your server there are a few things you need to do to configure Molly:

Configure Apache

Modifying /private/etc/apache2/httpd.conf

Turn on Environment Variables module.

Find and uncomment (add if they're missing) the following two lines:

  #LoadModule env_module         libexec/httpd/mod_env.so
  #AddModule mod_env.c

Allow .htaccess files in the main web directory to modify configurations.

Around line 400 (inside the <Directory "/Library/WebServer/Documents"> on OS X) is the following directive:

  AllowOverride None

Change it to:

  AllowOverride All

(Actually, "AllowOverride FileInfo Options Indexes" should be sufficient.)

Modifying User .conf file(s)

MacOS X has an individual .conf file for each user on the system. In the /private/etc/apache2/users will be a .conf file for each user on the system. Edit the user.conf file for each user who will be using Molly as follows.

Change:

  AllowOverride None

to:

  AllowOverride FileInfo Options

Configure Database

Molly Account and Database

If you are the database administrator you will need to log in and create the database and username that Molly will use to access the database. If you do not have administrative privileges, skip to the next section and use the username and database assigned to you.

Replace MySQL stuff with updated screen captures.

Log in as the root user:

 
  [Ronald-Vullos-Computer:~/Sites] rvullo% mysql -uroot -p
  Enter password:
  Welcome to the MySQL monitor.  Commands end with ; or \g.
  Your MySQL connection id is 355 to server version: 4.0.17-standard
  
  Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
  
  mysql>

Let's assume you want to create a database named "mollydb" and that Molly will be connecting to this system as user "mollyuser" with the password "mollypass." As root user you would create the database and assign the access privileges as such:

 
  mysql> create database mollydb;
  Query OK, 1 row affected (0.07 sec)
  
  mysql> grant all privileges on mollydb.* to mollyuser@localhost identified by 'mollypass';
  Query OK, 0 rows affected (0.71 sec)
  
  mysql> 

Root administrative tasks are finished, so log out:

 
  mysql> exit
  Bye
  [Ronald-Vullos-Computer:~/Sites] rvullo% 

Install Database Tables

Creating Molly's Tables and Loading Default Data

The easiest way to do this is to first change directories into the directory containing the SQL files provided with Molly:

 
  [Ronald-Vullos-Computer:~/Sites] rvullo% cd system/database/sql
  [Ronald-Vullos-Computer:system/database/sql] rvullo% 
   

Next you will log into MySQL using the username and password that Molly will use (either created above, or provided by your database administrator or ISP). Once logged in you will select Molly's database and into it load first the schema which will create all the tables (mysql.sql), then the data to populate those tables (data.sql):

 
  [Ronald-Vullos-Computer:system/database/sql] rvullo% mysql -umollyuser -p
  Enter password: 
  Welcome to the MySQL monitor.  Commands end with ; or \g.
  Your MySQL connection id is 357 to server version: 4.0.17-standard
  
  Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
  
  mysql> use mollydb;
  Database changed
  mysql> source mysql.sql;
  Query OK, 0 rows affected (0.43 sec)
  
  Query OK, 0 rows affected (0.06 sec)
  
       Several identical lines deleted for brevity
  
  Query OK, 0 rows affected (0.00 sec)
  
  mysql> source data.sql;
  Query OK, 1 row affected (0.02 sec)
  
  Query OK, 1 row affected (0.00 sec)
  
       Many identical lines deleted for brevity
  
  Query OK, 1 row affected (0.00 sec)
  
  mysql> exit
  Bye
  [Ronald-Vullos-Computer:system/database/sql] rvullo% 
  

At this point Molly's database should be all set. The next step will be to set the appropriate values in the molly.ini file.

Edit molly.ini file

Go to the system directory within Molly and open up the molly.ini file. There are several things that you will need to change in this file.

  1. In line 34, change "jpeg" to "png" if necessary depending on your operating system.
  2. In line 41, change the email address to your own email address.
  3. In lines 48, 49, and 50, change the file paths to the correct paths to your directories.
  4. In lines 62, 63, 68, 69, 92, 93, 147, and 148, change the information to your database and username.
  5. In lines 64, 70, 94, and 149, change the password to your own password.
  6. In line 72, make the session name something unique.

Edit .htaccess file

The .htaccess file is located inside the main Molly directory. All you need to do with this file is to change "mollyuser" to your username in lines 13 and 14.

Testing Molly

  1. Start by accessing your Molly site from your browser. The URL should be something like: http://www.yourserver.com/~yourid/molly/ and should look like this:

    molly screen capture
  2. If the site looks like the one in the illustration above, then you're good to go. If you see a sort-of broken looking site with lots of pink, then there is a problem with your database, since Molly loads much of the user interface design information from a database table named 'molly_config.' You may also see error messages. Often this is a result of not having the correct mysql username and password settings in the molly.ini file. If what you see is nothing even close to a web site, then you probably have errors in your .htaccess file. (Molly's installer created both of these files for you, but you may edit them if need be.)


Appendix II: MAML Tag Reference

The following documentation is generated automatically from the class definitions used by Molly to implement MAML tags. All MAML & MAGE tags have optional id and style attributes. If you do not provide an ID, Molly will automatically generate a unique ID where appropriate. Default attribute values are shown. Some attribute defaults are set in the system/molly.ini file.

maml:ajax

Attributes:

Prototype: <maml:ajax node = "" event = "" action = "" target = "" id = "maml_ajax_0" class = "" style = "visibility:visible;"></maml:ajax>

ajax docs here
Path: /var/www/html/system/core/tags/maml.ajax.inc
Start Line: #3


maml:block

Attributes:

Prototype: <maml:block permitted = "" blocknum = "" wiki = "" blockid = "" id = "maml_block_1" class = "" style = "visibility:visible;"></maml:block>

Description: Allows the webmaster to designate an area of the page as editable online by members of the permitted group. When those members are logged in they will see an editor in place of the normally static content.

Molly automatically creates the link between blocks and the records in the molly_blocks table (field: block_id) however it should be noted that these links are somewhat fragile as they are based on the file name (and path relative to HTMLRoot), and the position (order) of the block on the page if there are more than one block. Because of this, there is an optional blocknum attribute that can be used if the order of blocks on a page must be changed after the records in the database table exist. Alternatively the database record can be edited if neccessary to reflect a relocated block or renamed/moved page.

If the blockid is set, this allows the same block to be used on multiple pages rather than tying it to a particular page.

The block tag can also be used to create a wiki. Setting the wiki attribute returns that wiki page from the database and activates automatic wiki linking via putting {{link name}} in the block’s text. You can only have one wiki block per MAML page. To create a new wiki page, create a wiki link then follow it from the editor’s preview page (). Use of the wiki attribute overrides use of the blockid attribute.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #917


maml:box

Attributes:

Prototype: <maml:box title = "" id = "maml_box_2" class = "" style = "visibility:visible;"></maml:box>

Description: Creates a round-cornered box around whatever it encloses based on the box.top.tplt and box.bottom.tplt template files, the default.css styles, and values in the config database table. The optional title attribute is displayed at the top of the box. The box itself is created from two image files (decor/rounded-left-template.png and decor/rounded-right-template.png) which are colorized using Molly’s image colorizing code. It would be nice to add a color attribute to allow override of the default color BoxFrameColor from the config database table.

Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #148


maml:captcha

Attributes:

Prototype: <maml:captcha id = "maml_captcha_3" class = "" style = "visibility:visible;"></maml:captcha>

Adds captcha protection to Molly forms.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #582


maml:desist

Attributes:

Prototype: <maml:desist name = "data" id = "maml_desist_4" class = "" style = "visibility:visible;"></maml:desist>

Description: destroys a token created by a <maml:persist> tag and removes its data from memory.

Path: /var/www/html/system/core/tags/maml.tokens.inc
Start Line: #25


maml:else

Attributes:

Prototype: <maml:else id = "maml_else_5" class = "" style = "visibility:visible;"></maml:else>

Description: The <maml:else> works within the <maml:if> tag to allow one to conditionally display portions of the page.

<maml:if condition="'*[token]*' == 'value'">
    <p>True Stuff (inside an if).</p>
    <maml:else>
        <p>False Stuff (inside an else).</p>
    </maml:else>
</maml:if>
 
Path: /var/www/html/system/core/tags/maml.constructs.inc
Start Line: #52


maml:extension

Attributes:

Prototype: <maml:extension name = "" id = "maml_extension_6" class = "" style = "visibility:visible;"></maml:extension>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the extension of the file for each file found.

Alternatively you may use the *[extension]* token, for example if you wish to include the extension in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #319


maml:fetch

Attributes:

Prototype: <maml:fetch query = "" table = "" fields = "*" sort = "" order = "ascending" criteria = "" maxentries = "" start = "1" key = "" detail = "" host = "" database = "" user = "" password = "" id = "maml_fetch_7" class = "" style = "visibility:visible;"></maml:fetch>

Description: Used to retrieve results from a database. Together with the <maml:row> and <maml:field> tags this allows you to retrieve and display data from Molly’s database.

Example:

<maml:fetch table="molly_test" key="name" criteria="true" detail="form.maml" format="off">
    <table style="width:20em;">
        <tr>
            <th><maml:sort sort="name">Name</maml:sort></th>
            <th><maml:sort sort="eyecolor" order="descending">Eye Color</maml:sort></th>
            <th><maml:sort sort="age">Age</maml:sort></th>
        </tr>
        <maml:row maxentries="3">
        <tr>
            <td><maml:field name="name"/></td>
            <td><maml:detail href="advancedLists.maml"> <maml:field name="eyecolor"/></maml:detail></td>
            <td><maml:detail href="advancedForm.maml"> <maml:field name="age"/></maml:detail></td>
        </tr>
        </maml:row>
    </table>
  Total Records: <maml:numrows/><br/>
  <maml:previous>Previous <maml:numrows/> Records </maml:previous>
  | <maml:pages delimiter="-" /> |
  <maml:next>Next <maml:numrows/> Records </maml:next><br/>
</maml:fetch> 
 

Results:

Name Eye Color Age
Genny Brown 6
Heather Blue 28
Michelle brown 12
Ron Brown 48
Tim brown 22
Total Records:
Previous Records | | Next Records

Things which are known to be not working:

Example from select_tag_test.maml - be sure to update these docs as functionality is added.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #17


maml:field

Attributes:

Prototype: <maml:field name = "" id = "maml_field_8" class = "" style = "visibility:visible;"></maml:field>

Description: Used in conjunction with <maml:fetch> tag to retrieve results from a database.

Replaces itself with the data retrieved from that field by the <maml:fetch> tag’s query.

See <maml:fetch> tag for example usage.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #243


maml:filelist

Attributes:

Prototype: <maml:filelist path = "FilePath" extension = "" dateformat = "d F Y H:i:s" id = "maml_filelist_9" class = "" style = "visibility:visible;"></maml:filelist>

<maml:filelist path="/unix/" extension="jpg" filetype="dir | file" dateformat="d F Y H:i:s">

The maml:filelist tag, together with the associated maml:filename, maml:fileroot, maml:filesize, maml:permissions, maml:filetype, maml:modtime, and maml:extension tags allow you to gather and use information about all of the files in a specified directory. This can be to display a simple list, like the example below, or to build a file picker widget like the one used in the config administration tool. The maml:filelist tag pair repeats its contents for each file found in the directory. Using the extension attribute you can limit the results to one or more file types.

Example:

<table>
    <tr>
        <th>filename</th>
        <th>fileroot</th>
        <th>filesize</th>
        <th>permissions</th>
        <th>filetype</th>
        <th>modtime</th>
        <th>extension</th>
    </tr>
    <maml:filelist path="/var/www/html/decor/skins/mx/images/" extension="gif jpg">
        <tr>
            <th><maml:filename /></th>
            <td><maml:fileroot /></td>
            <td><maml:filesize /></td>
            <td><maml:permissions /></td>
            <td><maml:filetype /></td>
            <td><maml:modtime /></td>
            <td><maml:extension /></td>
        </tr>
    </maml:filelist>
</table>
 

Results:

filenamefilerootfilesizepermissionsfiletypemodtimeextension
img01.tplt.jpg img01.tplt 22804 -rwxr-xr-x file 20 January 2012 08:41:27 jpg
img03.tplt.jpg img03.tplt 8372 -rwxr-xr-x file 09 October 2014 13:27:26 jpg
mxhead-dark.tplt.jpg mxhead-dark.tplt 42069 -rw-r--r-- file 10 October 2014 10:39:34 jpg
mxhead-light.tplt.jpg mxhead-light.tplt 59228 -rwxr-xr-x file 10 October 2014 10:35:12 jpg
mxhead.tplt.jpg mxhead.tplt 44546 -rw-r--r-- file 10 October 2014 10:38:28 jpg
test_pattern_green.gif test_pattern_green 23881 -rw-r--r-- file 19 January 2012 09:25:11 gif
tinymolly.jpg tinymolly 5543 -rwxr-xr-x file 03 February 2011 14:12:37 jpg
Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #108


maml:filename

Attributes:

Prototype: <maml:filename name = "" id = "maml_filename_10" class = "" style = "visibility:visible;"></maml:filename>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the name of the file for each file found.

Alternatively you may use the *[filename]* token, for example if you wish to include the filename in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #223


maml:fileroot

Attributes:

Prototype: <maml:fileroot name = "" id = "maml_fileroot_11" class = "" style = "visibility:visible;"></maml:fileroot>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the name of the file sans the extension for each file found.

Alternatively you may use the *[fileroot]* token, for example if you wish to include the fileroot in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #239


maml:filesize

Attributes:

Prototype: <maml:filesize name = "" id = "maml_filesize_12" class = "" style = "visibility:visible;"></maml:filesize>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the filesize of the file for each file found.

Alternatively you may use the *[filesize]* token, for example if you wish to include the filesize in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #255


maml:filetype

Attributes:

Prototype: <maml:filetype name = "" id = "maml_filetype_13" class = "" style = "visibility:visible;"></maml:filetype>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the filetype of the file for each file found.

Alternatively you may use the *[filetype]* token, for example if you wish to include the filetype in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #287


maml:form

Attributes:

Prototype: <maml:form keyvalue = "" table = "" keyfield = "" criteria = "" response = "" mode = "" action = "none" name = "maml_form_14" schema = "off" ownership = "none" owner = "" permitted = "all" linkfield = "" id = "maml_form_14" class = "" style = "visibility:visible;"></maml:form>

Description: Molly’s forms are, by design, very similar to the HTML forms webmasters are used to. The big difference is that Molly’s forms automatically connect with the database and require no additional programming.

The table attribute is the name of the database table that this form will be interacting with. The response attribute is the url of the page that the user will be sent to after submitting the form. The keyfield attribute identifies the field in the database used as the primary key. The schema attribute tells Molly to write the basic SQL code needed to create a database table to support the form (partially implemented).

<maml:form table="molly_test" response="form_test.maml" keyfield="test_id" keyvalue="*[t_Link]*" mode="replace" schema="on">
   Name: <maml:input type="text" name="name" size="24" /><br/>
   Eye Color: <maml:input type="text" name="eyecolor" value="*[t_RenderAs]*"/><br/>
   Age: <maml:input type="text" name="age" value="*[t_Link]*"/><br/>
 
    <maml:fetch table="molly_username" maxentries="2" fields="lastname, firstname, user_id" orderby="lastname">
        <maml:select name="file_token" size="1">
            <maml:option>Choose One:</maml:option>
            <maml:row>
                <maml:option value=""><maml:field name="lastname" />, <maml:field name="firstname"/> (*[user_id]*)</maml:option>
            </maml:row>
        </maml:select>
    </maml:fetch>
 
   <maml:input type="submit" value="MAML submit Button"/>
</maml:form>
 
Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #331


maml:if

Attributes:

Prototype: <maml:if condition = "TRUE" else = "" id = "maml_if_15" class = "" style = "visibility:visible;"></maml:if>

Description: The <maml:if> tag allows one to conditionally display portions of the page.

<maml:if condition="'*[token]*' == 'value'">
    <p>True Stuff (inside an if).</p>
    <maml:else>
        <p>False Stuff (inside an else).</p>
    </maml:else>
</maml:if>
 
Path: /var/www/html/system/core/tags/maml.constructs.inc
Start Line: #7


maml:img

Attributes:

Prototype: <maml:img id = "maml_img_16" class = "" style = "visibility:visible;"></maml:img>

Description: This is a placeholder for a future <maml:image /> tag with the following features:

Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #246


maml:include

Attributes:

Prototype: <maml:include src = "" parse = "maml" debug = "" id = "maml_include_17" class = "" style = "visibility:visible;"></maml:include>

Description: Reads the file specified in the src attribute and inserts it into the document. If parse="maml" then it is processed as a MAML file as it is being inserted. If parse="html" then only the portion of the file between the <body> and </body> tags is included. If src is a URL instead of a filespec, then this tag will fetch the file from the specified server. parse="xml" is not yet implemented.

Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #184


maml:input

Attributes:

Prototype: <maml:input type = "" name = "" value = "" size = "16" selected = "" id = "maml_input_18" onclick = "" onfocus = "" onblur = "" onchange = "" onselect = "" onreset = "" class = "" style = "visibility:visible;"></maml:input>

New tag documentation goes here.

Old Docs:

Must be within <maml:form></maml:form> pair.

Required Attribute: type [text|submit|hidden|checkbox|radio|password|reset]
Optional Attribute: name
Optional Attribute: value
Optional Attribute: selected 	// [CHECKED] for radio andcheckbox
Example:
	<maml:form table="test" response="/~rvullo/m2/test/list.maml" keyfield="age" schema="on">
		Name: <maml:input type="text" name="name"/><br/>
		Eye Color: <maml:input type="text" name="eyecolor"/><br/>
		Age: <maml:input type="text" name="age"/><br/>
		<maml:input type="submit" value="I am a submit Button"/>
	</maml:form> 
Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #601


maml:item

Attributes:

Prototype: <maml:item href = "" target = "_self" selected = "" id = "maml_item_19" class = "" style = "visibility:visible;"></maml:item>

prototype_tag is a generic class for MAML tags so that they can inherit methods such as id(). Undocumented tag classes inherit this documentation.
Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #105


maml:login

Attributes:

Prototype: <maml:login response = "/" fail = "Invalid Login" logout = "" id = "" class = "" style = "visibility:visible;"></maml:login>

prototype_tag is a generic class for MAML tags so that they can inherit methods such as id(). Undocumented tag classes inherit this documentation.
Path: /var/www/html/system/core/tags/maml.security.inc
Start Line: #4


maml:menu

Attributes:

Prototype: <maml:menu type = "tabs" id = "maml_menu_20" class = "" style = "visibility:visible;"></maml:menu>

prototype_tag is a generic class for MAML tags so that they can inherit methods such as id(). Undocumented tag classes inherit this documentation.
Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #72


maml:modtime

Attributes:

Prototype: <maml:modtime name = "" id = "maml_modtime_21" class = "" style = "visibility:visible;"></maml:modtime>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the modtime of the file for each file found.

Alternatively you may use the *[modtime]* token, for example if you wish to include the modtime in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #303


maml:multiple

Attributes:

Prototype: <maml:multiple count = "1" button = "after" label = "Add Another" id = "maml_multiple_22" class = "" style = "visibility:visible;"></maml:multiple>

Description: This tag allows the user to replicate whatever it encloses using client-side (JavaScript/DOM) code. This is particularly useful inside a <maml:form> to allow the user to create several records at once when submitting a form. (This is actually what it is designed for, but we opened it up to be used outside fo forms to see what other uses we might find for it.)

Button value placements:

before Before the section to be duplicated.
after After the section to be duplicated.
beforeeach At the beginning of the section to be duplicated. (Gets duplicated along with section.)
aftereach At the end of the section to be duplicated. (Gets duplicated along with section.)
Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #272


maml:nothing

Attributes:

Prototype: <maml:nothing id = "maml_nothing_23" class = "" style = "visibility:visible;"></maml:nothing>

Description: The <maml:nothing tag allows you to insert tags to make the parser happy, such as declaring the maml namespace for files that only produce snippets for inclusion or AJAX calls.

Path: /var/www/html/system/core/tags/maml.xml.inc
Start Line: #6


maml:numrows

Attributes:

Prototype: <maml:numrows id = "maml_numrows_24" class = "" style = "visibility:visible;"></maml:numrows>

Description: Used in conjunction with <maml:fetch> tag to display the number of records returned.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #305


maml:option

Attributes:

Prototype: <maml:option id = "maml_option_25" onclick = "" ondblclick = "" onmousedown = "" onmousemove = "" onmouseout = "" onmouseover = "" onmouseup = "" onkeydown = "" onkeypress = "" onkeyup = "" disabled = "" label = "" selected = "" value = "" class = "" style = "visibility:visible;"></maml:option>

prototype_tag is a generic class for MAML tags so that they can inherit methods such as id(). Undocumented tag classes inherit this documentation.
Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #809


maml:permissions

Attributes:

Prototype: <maml:permissions name = "" id = "maml_permissions_26" class = "" style = "visibility:visible;"></maml:permissions>

Description: Used in conjunction with <maml:filelist> tag to retrieve a list of files from a directory.

Replaces itself with the unix-style permissions string of the file for each file found.

Alternatively you may use the *[permissions]* token, for example if you wish to include the permissions in an attribute of another tag.

See <maml:filelist> tag for example usage.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #271


maml:persist

Attributes:

Prototype: <maml:persist name = "data" id = "maml_persist_27" class = "" style = "visibility:visible;"></maml:persist>

Description: Creates a token and stores the contents of the tags in that token. Tokens persist until the browser session ends or times out, or until a <maml:desist> tag is encountered.

Path: /var/www/html/system/core/tags/maml.tokens.inc
Start Line: #4


maml:protect

Attributes:

Prototype: <maml:protect permitted = "all" denied = "" id = "maml_protect_28" class = "" style = "visibility:visible;"></maml:protect>

Description: The <maml:protect> tag allows one to restrict access to/viewability of a portion of page based on the user’s membership in a group specified in the permitted attribute. (These groups are represented in the molly_permissions table in the database.) The special group all allows all logged in users access, but not users who have not logged in (it represents, therefore, “all registered users”). Another special group guest allows only users who are not logged in to see the content.

The optional denied attribute specifies a string to be used to replace the protected section of the page. in the absence of the denied attribute the area will be left empty.

Path: /var/www/html/system/core/tags/maml.security.inc
Start Line: #59


maml:redirect

Attributes:

Prototype: <maml:redirect href = "" id = "maml_redirect_29" class = "" style = "visibility:visible;"></maml:redirect>

Description: The <maml:redirect> leaves the current page and goes to the page specified in the href attribute. (Technically, it sends a location header to the browser telling it to request the new page.)

Path: /var/www/html/system/core/tags/maml.constructs.inc
Start Line: #81


maml:row

Attributes:

Prototype: <maml:row empty = "" maxentries = "" id = "maml_row_30" class = "" style = "visibility:visible;"></maml:row>

Description: Used in conjunction with <maml:fetch> tag to retrieve results from a database.

The <maml:row> tag duplicates its contents for each row (record) found by the <maml:fetch> tag’s query.

See <maml:fetch> tag for example usage.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #202


maml:select

Attributes:

Prototype: <maml:select name = "" size = "" disabled = "" multiple = "" tabindex = "" onclick = "" onfocus = "" onblur = "" onchange = "" onselect = "" onreset = "" id = "maml_select_31" class = "" style = "visibility:visible;"></maml:select>

prototype_tag is a generic class for MAML tags so that they can inherit methods such as id(). Undocumented tag classes inherit this documentation.
Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #717


maml:sort

Attributes:

Prototype: <maml:sort sort = "" order = "ascending" id = "maml_sort_32" class = "" style = "visibility:visible;"></maml:sort>

Description: Used in conjunction with <maml:fetch> tag to retrieve results from a database.

Creates links which allow the user to sort the results of the <maml:fetch> tag’s query.

See <maml:fetch> tag for example usage.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #260


maml:textarea

Attributes:

Prototype: <maml:textarea name = "" id = "maml_textarea_33" cols = "50" rows = "25" class = "" style = "" onclick = "" onfocus = "" onblur = "" onchange = "" onselect = "" onreset = ""></maml:textarea>

Tag documentation goes here.

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #1056


maml:timeformat

Attributes:

Prototype: <maml:timeformat format = "unix" id = "maml_timeformat_34" class = "" style = "visibility:visible;"></maml:timeformat>

Description: Converts a timestamp (as from a database) to either unix or javascript timestamp format (i.e. second or miliseconds since January 1, 1970 00:00:00 UTC).

Path: /var/www/html/system/core/tags/maml.database.inc
Start Line: #1166


maml:token

Attributes:

Prototype: <maml:token name = "" value = "" id = "maml_token_35" class = "" style = "visibility:visible;"></maml:token>

Description: The <maml:token> tag allows you to set the value of a token for use later on the page. The token specified by the name attribute is set to the contents of the tag. You may also use the optional value attribute which will override the contents of the tag and so should be used with he empty tag syntax for clarity.

<maml:token name="Fred">My Name is Fred.</maml:token>
Token *<span>[Fred]</span>* is <strong> *[Fred]* </strong>

or

<maml:token name="Fred" value="My Name is Fred" />
Token *<span>[Fred]</span>* is <strong> *[Fred]* </strong>
Path: /var/www/html/system/core/tags/maml.tokens.inc
Start Line: #42


maml:upload

Attributes:

Prototype: <maml:upload label = "Upload Files" maxsize = "1048576" destination = "mp/videotracks" response = "" process = "" type = "" callback = "" id = "maml_upload_36" class = "" style = "visibility:visible;"></maml:upload>

Creates a widget for uploading files via AJAX.

Path: /var/www/html/system/core/tags/maml.file.inc
Start Line: #6


maml:windoid

Attributes:

Prototype: <maml:windoid title = "" showMsg = "" hideMsg = "" id = "maml_windoid_37" class = "" style = "visibility:visible;"></maml:windoid>

Description: Creates a window-like box around whatever it encloses based on the windoid.begin.tplt and windoid.end.tplt template files, the default.css styles, and values in the config database table. The title attribute is displayed in the titlebar of the windoid.

In previous versions of Molly this tag had additional attributes, some of which we may wish to re-create or re-think:

Path: /var/www/html/system/core/tags/maml.format.inc
Start Line: #2



Appendix III: Modules Reference

Modules are optional add-ons to Molly. Over time some modules may migrate into Molly's core.

Modules to be loaded are specified in the molly.ini file for the site in the [Modules] section. There each module is listed with the path to the module's directory. Molly will then automatically include any .inc files found within that directory. Most modules will only require one .inc file and by convention that .inc file will be named the same as the module. So, for example, the Calendar module included with Molly is located in the calendar directory and has one .inc file named calendar.inc

Example [Modules] Section of molly.ini

[Modules]		; path relative to [Paths]HTMLRoot + [Paths]ModulesDir
ZipCodes = "zipcodes/"
Calendar = "calendar/"			

Modules should also include a documentation file named docs.htmf which is automatically included into this Modules appendix. (htmf stands for HyperText Markup Fragment and indicates that this file should include valid, well formed HTML and text, but is not a complete HTML document. Its contents are to be inserted into a complete HTML document.)

Simplest Example Module docs.htmf Document:

<h3>Module Name</h3>
<p>Docs go here.</p>

Site Specific Code

If you have site-specific PHP code you would like to include on all of your pages, creating a module for that site is the safest and most convenient way to accomplish that.

Installed Modules Documentation

The following documentation is generated automatically from information provided by the modules' authors.


Appendix IV: Programmers' Documentation

This appendix is available for PHP programmers interested in understanding how Molly works "under the hood" but is primarily here for the active developers of the core Molly code. Please note that there is no need to understand or program PHP to use Molly. If you do not wish to extend or improve Molly, or write modules for Molly using PHP, then you can safely ignore this appendix.

Molly is open source, so if you make improvements or extensions to Molly please share them with us so that we can roll them into the next release.

File Types & Molly

Molly's Default behavior is to consider the extension of the files and processes them as follows:

Extension Action
.php Process as normal php, no Molly functionality
.inc PHP include files
.html Process similarly to Molly 1, that is, set all the globals and include basic function and object libraries and module libraries, then procede to pass the file through the php parser. (Note that for normal HTML files this does essentially nothing, but that it allows you to minimally incorporate some of Molly's functionality if you understand the underlying architecture.)
.maml Set all the globals and include all the libraries and modules, then parse the file through Molly's MAML XML parser.
.tplt template files
.ini prevent being served to the web
.txt (Maybe turn into a nice formatted web page?)
.css Treated like a template file - that is, all *[tokens]* are replaced with config values

Molly Naming Conventions

When developing code (including modules) please adhere to the following naming conventions:

Prefix Example Meaning
$gv_ $gv_VarName Global Variable (will be found in $GLOBALS)
$fv_ $fv_VarName Variable with scope local to a function
$go_ $go_ObjectName Global Object
$fo_ $fo_ObjectName Object with scope local to a function
$pv_ $pv_ParemeterName Parameter passed to a function (function scope)
$po_ $po_ParameterObject Object passed to a function (function scope) or class
$t_ $GET['t_Name'] Tokens passed via the query string
maml_ maml_TagName Class name for MAML Tag
molly_ molly_ClassName Class name for non-tag objects used in Molly
molly_ molly_TableName Database Table specific to Molly
m_ m_FunctionName Function that is part of Molly
MOLLY_ MOLLY_CONST_NAME Molly Constants

Inline Documentation

When defining a maml_ class to create a new tag programmers must take care to set the $doctext to explain the use of the tag. This will allow Molly to generate user documentation which is accurate and current with the code and better able to withstand versioning. We will use PHP's Nowdoc syntax (http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.nowdoc) to accomplish this.

Molly System Constants

Constant Value
MOLLY_SYSTEM_DIRECTORY Unix Path to Molly's system directory (core functionality)
MOLLY_INI File Name of This Site's .ini file (allows multiple sites to share the same codebase by having different .ini files)

Molly's Internal Functions

m_AppendJavaScript($pv_Scripts, $pv_ScriptName, $pv_AllowDuplicates) [system/core/40_tags.inc]
Adds $pv_Scripts to the JavaScript section in the head of the page. $pv_ScriptName is tracked to know which scripts have already been added. $pv_AllowDuplicates is FALSE by default.
m_AppendQueryString($pv_Key, $pv_Value) [system/core/40_tags.inc]
Allows Molly to dynamically create the querystring for links such as <maml:sort>
m_AppendStylesheet($pv_Styles, $pv_StyleName, $pv_AllowDuplicates) [system/core/40_tags.inc]
Adds $pv_Styles to the stylesheet in the head of the page $pv_StyleName is tracked to know which styles have already been added. $pv_AllowDuplicates is TRUE by default.
m_ArrayLastKey($pv_TheArray) [system/core/80_environment.inc]
Returns the last key of an array
m_AutoInclude($pv_PathToIncludesDirectory, $pv_FileExtension) [system/loader.php]
Includes all the files in a directory with the specified extension
m_captchabasepath() [system/core/captcha/captcha-settings.php]
Returns the path to the captcha library directory.
m_captchacode() [system/core/captcha/captcha.inc]
Generates the random captcha code.
function m_captchadone() [system/core/captcha/captcha.inc]
Unsets the session variable that holds the current captcha code being tested against.
m_captchaimgurl() [system/core/captcha/captcha.inc]
Returns the global $captchaimg.
m_captchasendimg() [system/core/captcha/captcha.inc]
Generates an image of the current captcha code (generating a new code if one does not exist in the $_SESSION array). Randomly tilts, sizes, etc. the characters and generates noise to foil OCR systems.
m_captchasendwav() [system/core/captcha/captcha.inc]
Generates an spoken reading of the current captcha code (generating a new code if one does not exist in the $_SESSION array) formatted as a wav audio file.
m_captchawavurl() [system/core/captcha/captcha.inc]
Returns the global $captchawav.
m_CheckLogin($pv_LoginName, $pv_Password) [system/core/27_security.inc]
returns user_id for successful login, FALSE for failed login.
m_clean_params_for_query($pv_QueryComponent) [system/core/27_security.inc]
Used to clean user-provided data before building a query with it. Strips off semicolon and anything following it, then escapes other characters that are problematic in a database query.
m_DateGMT($p_UnixTimeStamp) [system/core/10_date_time.inc]
Converts a Unix timestamp to a formatted date, adjusted by user's timezone
m_debug($pv_TheDebugString) [system/core/05_utility.inc]
Caches debug string for output after parsing completes. Saves debug string(s) in a session variable until they can be displayed on the next MAML page since HTML pages are often used for invisible (to the user) forms processing. (see system/parser.php)
m_DirectoryList($pv_Directory, $pv_DateFormat="d F Y H:i:s") [system/core/15_file.inc]
Creates an array of hashes for each file in a specified directory. The hashes contain 'name', 'root', 'size', 'perm', 'type', 'time', 'extension' elements.
m_DoInsert($pv_Query, $pv_HostName='', $pv_User='', $pv_Password='', $pv_Database='', $pv_DatabaseApp='') [system/core/20_database.inc]
Does an insert query and returns an Insert ID.
m_DoLogin($pv_UserID) [system/core/27_security.inc]
Creates session variables to make a user logged in
m_DoQuery($pv_Query, $pv_HostName='', $pv_User='', $pv_Password='', $pv_Database='', $pv_DatabaseApp='') [system/core/20_database.inc]
Does a query and returns record set of the results.
m_EchoModulesDocs() [system/core/70_modules.inc]
Checks for the existence of docs.htmf file in each module directory (as specified in the molly.ini [Modules] section) and echos it (or a file not found message). This function is used in the docs page.
m_FetchDBHash($pv_Query, $pv_HostName='', $pv_User='', $pv_Password='', $pv_Database='', $pv_DatabaseApp='') [system/core/20_database.inc]
Does a query and returns an array of associative arrays (array of hashes)
m_FetchRecordsArray($p_TableName, $p_Fields, $p_Query, $p_OrderBy="", $p_Limit="") [system/core/20_database.inc]
Wrapper function for m_FetchDBHash that builds the SQL from appropriate pieces.
m_GetDocument ($pv_URL) [system/core/15_file.inc]
Returns the text of a file specified by $pv_URL
m_HashArrayToXML() [system/core/30_XML.inc] /* Not Currently Used */
m_ImplementedTags() [system/core/80_environment.inc]
returns an array of class names for implemented tags.
m_Interpolate($template, $hash, $prefix = '*[', $postfix = ']*') [system/loader.php]
Replaces placeholders in a template string with values from a hash
m_IsMollyTag($pv_TheTagName) [system/core/80_environment.inc]
Checks a string to see if it's a defined Molly tag classname
m_LoadModules() [system/core/70_modules.inc]
Loads modules specified in the molly.ini file for the site in the [Modules] section.
m_MakeUnixTimestampGMT($hh=0, $mm=0, $ss=0, $m, $d, $y) [system/core/10_date_time.inc]
Creates a unix timestamp from hour, minute, second, year, month, day
m_NakedHTML ($pv_URL) [system/core/15_file.inc]
Returns the text from between the <body></body> tags of an HTML document specified in $pv_URL
m_ParentDir($pv_Path) [system/loader.php]
Returns the parent directory pasth of the unix file path passed to it.
m_Permissions($pv_FilePathName) [system/core/15_file.inc]
Returns the the unix style permissions (as in ls -l) for the fully qualified file name passed as $pv_FilePathName.
m_permitted($pv_Group) [system/core/27_security.inc]
Checks to see if the currently logged in user is a member of the permissions group. Returns boolean.
m_PullParse() [system/core/90_parser.inc]
This is the actual XML parsing function that does Molly's magic. Starting with this version of Molly the parsing is done using the XMLReader extension (http://us.php.net/manual/en/intro.xmlreader.php). Previous versions used the expat XML Parser (http://us.php.net/manual/en/intro.xml.php).
m_session_close() [system/core/25_sessions.inc]
Callback function for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers.
m_session_destroy($pv_Key) [system/core/25_sessions.inc]
Callback function for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers.function m_session_destroy deletes the associated record in the session table, thus ending the session.
m_session_gc($maxlifetime) [system/core/25_sessions.inc]
Callback function for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers. This is the function which collects garbage by deleting expired sessions from the sessions database. The probability that PHP will run this function is set in the php.ini directive "session.gc_probability."
m_session_open($pv_SavePath, $pv_SessionName) [system/core/25_sessions.inc]
Callback function for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers. This function collects garbage by deleting expired sessions from the sessions database whenever a new session is opened.
m_session_read($pv_Key) [system/core/25_sessions.inc]
Callback function for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers. This function reads the user's session data from the sessions database updates their session record to reset their session expiration time.
m_sess_write() [system/core/25_sessions.inc]
Callback function for session_set_save_handler() allowing Molly to store sessions and associated information in a database table. Among other things this allows us to easily determine who's logged in, and to share sessions across multiple web servers. This function stores the session data for a particular user. If the user already exists in the table, it updates the user's session value and expiry time. PHP serializes the session data and sends it in as a string.
m_SessionQuery($pv_Query) [system/core/25_sessions.inc]
Sends a query to the session database as configured in the molly.ini file - such that multiple servers can share the same session.
m_ShowINI($pv_VariableName) [system/core/80_environment.inc]
debugging tool for outputting two dimensional arrays as are read from INI files
m_StringToStyleClassName($pv_TheString) [modules/calendar/calendar.inc]
Converts a string to a valid CSS class name. (Part of Calendar module.)
m_testDOMi() [system/core/30_XML.inc] /* Not Currently Used */
m_TimeGMT($p_UnixTimeStamp) [system/core/10_date_time.inc]
Converts a Unix timestamp to a formatted time, adjusted by user's timezone
m_ValidateAgainstDB($pv_LoginName, $pv_Password) [system/core/27_security.inc]
Returns a user_id for successful login, FALSE for failed login using login database and hash algorithm specified in the molly.ini file.
m_ValidateAgainstLDAP($pv_LoginName, $pv_Password) [system/core/27_security.inc]
Returns a user_id for successful login, FALSE for failed login using the LDAP/Active Directory server specified in the molly.ini file. If the suser does not exist in the Molly login/username tables a record is created for the newly ldap-validated user.

The following list of Molly's internal functions is generated automatically for this particular installation.

Output Buffering & Molly

Output Control

The output buffering functions allow you to control when output is actually sent from the web server to the browser. By default, output is sent as soon as it's generated.

Output buffering can be useful in several different situations, especially if you need to send headers to the browser after your script has begun outputting data. The Output Control functions do not affect headers sent using header() or setcookie(), only functions such as print(), echo, var_dump() and plain HTML between blocks of PHP code are buffered.

Start Buffering

Use the ob_start(); function to turn output buffering on. From this point, no output will be sent to the browser until you turn off buffering.

End Buffering

To end buffering and send all the accumulated text on its way to the browser, call the ob_end_flush(); function.

Simple Example

<?php
ob_start();
echo "Hello\n";
 
setcookie("cookiename", "cookiedata");
 
ob_end_flush();
 
?>

This simple example allows you to send headers - with setcookie() - "after" you've had output from the echo.

Output Buffering in Molly

"OK, but why does this matter to me?"

When you're programming in Molly, you need to know that before any output is sent, output buffering is turned on. And the last thing Molly does after parsing a page is turn output buffering off and send the whole page.

So...

Let's...

...build a tag that uses output buffering: the <maml:smiley> tag.

The smiley tag will find any smileys like :) ;) and :( in its enclosed text and convert them into graphical smileys like :) ;) and :(

To save you some work, I've written a function that does the actual conversion for you, so all we have to worry about is the output buffering. The function is defined thusly:

<?php
    function smileys2Graphics($p_TheText) {
 
        global $g_HTMLRoot;
        $p_TheText =  str_replace (':)','<img src="' . $g_HTMLRoot . 'decor/icons/smile.gif" alt=":)">',$p_TheText);    
        $p_TheText =  str_replace (':-)','<img src="' . $g_HTMLRoot . 'decor/icons/smile.gif" alt=":-)">',$p_TheText);    
        $p_TheText =  str_replace (':(','<img src="' . $g_HTMLRoot . 'decor/icons/pout.gif" alt=":(">',$p_TheText);    
        $p_TheText =  str_replace (':-(','<img src="' . $g_HTMLRoot . 'decor/icons/pout.gif" alt=":-(">',$p_TheText);    
        $p_TheText =  str_replace (':P','<img src="' . $g_HTMLRoot . 'decor/icons/yuck.gif" alt=":P">',$p_TheText);    
        $p_TheText =  str_replace (':p','<img src="' . $g_HTMLRoot . 'decor/icons/yuck.gif" alt=":p">',$p_TheText);    
        $p_TheText =  str_replace (':b','<img src="' . $g_HTMLRoot . 'decor/icons/yuck.gif" alt=":b">',$p_TheText);    
        $p_TheText =  str_replace (':-P','<img src="' . $g_HTMLRoot . 'decor/icons/yuck.gif" alt=":-P">',$p_TheText);    
        $p_TheText =  str_replace (':-p','<img src="' . $g_HTMLRoot . 'decor/icons/yuck.gif" alt=":-p">',$p_TheText);    
        $p_TheText =  str_replace (':-b','<img src="' . $g_HTMLRoot . 'decor/icons/yuck.gif" alt=":-b">',$p_TheText);    
        $p_TheText =  str_replace (';)','<img src="' . $g_HTMLRoot . 'decor/icons/wink.gif" alt=";)">',$p_TheText);    
        $p_TheText =  str_replace (';-)','<img src="' . $g_HTMLRoot . 'decor/icons/wink.gif" alt=";-)">',$p_TheText);    
        $p_TheText =  str_replace ('[])','<img src="' . $g_HTMLRoot . 'decor/icons/coffee.gif" alt="[])">',$p_TheText);    
        $p_TheText =  str_replace (':.','<img src="' . $g_HTMLRoot . 'decor/icons/oh.gif" alt=":.">',$p_TheText);    
        $p_TheText =  str_replace (':-.','<img src="' . $g_HTMLRoot . 'decor/icons/oh.gif" alt=":-.">',$p_TheText);    
        return $p_TheText;
    } //smileys2Graphics
?>

Skeleton Tag

Here is the skeleton of our tag code. (All MAML tags start this way.)

class maml_smiley extends prototype_tag {
    protected $doctext = <<<'DOCBLOCK'
Convert typed smileys to graphics
DOCBLOCK;
 
    public function begin(){ //called at the <maml:smiley> tag
 
    }
 
    public function end(){ //called at the </maml:smiley> tag
 
    }
}
 

The Plan

We only want to convert smileys between our tags, so what we want to do is save the text that's been buffered so far and flush the buffer when our begin tag is encountered. When we get to the end tag, the only thing in the buffer is what's between our tags. At that point we can save that, flush the buffer again, and return the saved text to the buffer. Finally we can process the text between our tags and add it to the restored buffer.

Save and Flush

class maml_smiley extends prototype_tag {
    protected $doctext = <<<'DOCBLOCK'
Convert typed smileys to graphics
DOCBLOCK;
    protected $OutputCache='';
 
    public function begin(){ //called at the <maml:smiley> tag
        $this->OutputCache = ob_get_contents(); 
        // Fetch and save all the output cached thus far and... 
        ob_clean(); // ...clean the output buffer
    }
 
    public function end(){ //called at the </maml:smiley> tag
 
    }
}
 

Process and Restore

class maml_smiley extends prototype_tag {
    protected $doctext = <<<'DOCBLOCK'
Convert typed smileys to graphics
DOCBLOCK;
    protected $OutputCache='';
 
    public function begin(){ //called at the <maml:smiley> tag
        $this->OutputCache = ob_get_contents(); 
        // Fetch and save all the output cached thus far and... 
        ob_clean(); // ...clean the output buffer
    }
 
    public function end(){ //called at the </maml:smiley> tag
    // Fetch all the data between the <maml:smiley> and
    //</maml:smiley> tags after it's been parsed
        $v_SmileyText = ob_get_contents(); 
 
         // clean the output buffer                                    
        ob_clean();
        // return the previously saved cached output to the output buffer
        echo $this->OutputCache; 
        //Process our text
        $v_GraphicText=smileys2Graphics($v_SmileyText);
        // add the converted text to the page buffer
        echo $v_GraphicText;
    }
}
 

Molly is Smart

Because we do this all the time in Molly, the prototype_tag class which we extended to create our tag has output buffering methods and variables built in to simplify this process:

class maml_smiley extends prototype_tag {
    protected $doctext = <<<'DOCBLOCK'
Convert typed smileys to graphics
DOCBLOCK;
 
    public function begin(){ //called at the <maml:smiley> tag
        $this->startCache();
    }
 
    public function end(){ //called at the </maml:smiley> tag
        $this->finishCache();    
        $v_GraphicText=smileys2Graphics($this->tagCache);
        // add the converted text to the page buffer
        echo $v_GraphicText;
    }
}