NAME

ECMS - easy content management system


SYNOPSIS

  ecms.pl


DESCRIPTION

ECMS is a simple and basic content mangement system. The ecms.pl file is a simple plain CGI script, that displays a site, has a simple login system (cookie based), an upload capability and an editor and manager for all the sites in the CMS.

A site is build up on content entities. A content entity might be a Template, PerlTempl, PerlFilter, FileLink, InternLink ExternLink, or whatever (see below for a detailed listing of these).

These Entities are linked/included by special include statements. See Template entity in Content entities for a description of the special include syntax.

When you are logged in, there will be an edit-bar on the top of the page. You can jump to the editor or the uploader, or set the view-mode.

The view mode can be toggled to 'edit' and 'view' by the link which starts with '[view-mode:'.

When you are in the 'edit' view-mode, you will notice a edit link (just a link with the name of the entity) next to the displayed content entity. The edit link will be wrapped into a red box, and the entity is wrapped into a blue box. The edit link will bring you to the editor to edit the entity in the blue box next/below to it.

If there are and FileLinks in the site, a link next to them will be inserted in 'edit' view-mode: [upload:<filename>] (where <filename> stands for the filename ;-)

When the CGI is started without any CGI parameters it will go into the 'view' view-mode and display the entity named 'topsite'. ('topsite' is the default entry, which will be displayed when no 'entry' CGI parameter is given).

If a entity with the name '_entry' exists, it will be called each time the CGI is called, with the selected entity name as second argument (see Redirector). The return value will be used to determine which entity to display.

If you want to login, call the ecms.pl like this:

   http://your.server.here.com/ecms.pl?login=1

It will bring you to the Login dialouge.

Entity storage

The Entities are stored as files in the $data_dir (see below) in Configuration section. The filename of an entity is the name of the entity (see Entity name below).

The Fileformat of an entity is a plain text file you can edit by hand, if you take care of the file format (escaping ``.\n'' correctly). The file consists of data blocks. A data block is a plain text block which ends with ``\n.\n'' (A single '.' on a new line). Within the data blocks occurences of ``.\n'' are escaped by adding a '.' at the end. (``.\n'' is escaped to ``..\n'').

The first data block is the type of the entity, after the first data block key/value pairs (also data blocks) follow.

When editing this by hand, note that the content data from browser often has ``\r\n'' as lineendings and not ``\n'' (like linux uses).

EXAMPLE

   ECMS::Link
   .
   cont
   .
   <a href="%url%">%label%</a>
   .
   token
   .
   i

The type is: 'ECMS::Link'.

And the key/value pairs are:

   'cont' => "<a href="%url%">%label%</a>"
   'token' => "i"

'cont' is the content of the entity. and 'token' is the name of the entity.

Entity name

Note that an entity name is limited. As every entity is stored in the $data_dir directory the name of an entity is limited to a filename (for example you can't have '/' in the entity name).


Configuration

There are 4 configuration variables that have to be set right. You find them on the top (or near to it) of ecms.pl.

$main_title
This will be put as the main title in the dialouges of ECMS. And will also be used as title when no html-document is generated, but a partial html file.

$pass
This is the password for ECMS. Just set it to whatever you want. You will be asked for this password in the Login dialouge.

$data_dir
This is the local directory where the content entities are saved to.

You have to take care that it is readable, accessible, and writeable by the webserver.

This also can be a relative url to the CGI script.

$files_dir
This is the directory where the uploaded files will go to.

This directory has to be accessible via http. See $files_url.

You have to take care that it is readable, accessible, and writeable by the webserver.

This also can be a relative url to the CGI script.

$files_url
This is the http URL to the $files_dir.

$board_dir
This is the directory where all data for the CommentBoard entity go.

EXAMPLES

An example with absolute paths:

   our $main_title = "My cool site";
   our $data_dir   = "/var/www/data/";
   our $files_dir  = "/var/www/data/files/";
   our $files_url  = "http://my.cool.web.server.com/data/files/";;

An example with relativ paths:

   our $main_title = "bla site";
   our $data_dir   = "data/";
   our $files_dir  = "data/files/";
   our $files_url  = "/data/files/";

NOTE: The $files_dir doesn't have to be a subdirectory of $data_dir:

   our $main_title = "Foobar site";
   our $data_dir   = "/var/data/";
   our $files_dir  = "/var/www/files/";
   our $files_url  = "http://another.webserver.com/files/";;


ECMS Dialouges

Login

The login dialouge is simple, just put in the corrent password, and a cookie will be created for one session. (the cookie will expire as soon as you quit the browser)

You have to go into login-mode manually, with a link like:

   http://webserver.with.ecms.com/ecms.pl?mode=login

After login you will see the main page (topsite) with the link bar on top of it.

Upload

The upload dialouge can be accessed via FileLinks.

Under the links on the top you will find the file-selector. You can choose a file and upload it.

The filename on the server will be automatically entered in the Filename textfield in the Fileselector. If you want a different filename on the server, you can change it there. (Make sure you correct the filename in the FileLink also...)

After uploading a file you will remain in the upload dialouge, You can either upload another file, or view or edit the topsite with the links on the top (which are just there for the convinence not to push 'back' in your browser so often :)

You can enter a new filename in the Filename field and upload another file for example.

Below the Fileselector you have a directory listing, you can delete directorys and files there, and also create new directorys with the form in the last box (``New Dir.''). NOTE: When you click on the 'del' link, the file/directory will be deleted WITHOUT ASKING! NOTE2: Directoys won't be deleted recursively. You have to empty it yourself.

Editor

The Editor dialouge is the place where actual editing takes place. On the left of the Editor is a list of all defined entities sorted by type and alphabetical.

The first column is the Type of the Entity, you find a mapping from shortnames of the Types to their long names under the entity list. The second column is the name of the entity. On the right of the entitys in the list, are always 3 links: 'edit', 'view' and 'del'. 'edit' will display that entity in the editor, 'view' will show it's output and 'del' will delete the entity WITHOUT ASKING!.

On the right is a box with a big textarea, an 'Entity name' textfield and a 'Entity type' popdown-box.

The textarea displays the content of the current edited entity, the name of the current edited entity is displayed in the header of the editor and in the 'Entity name' textfield. The type of the entity can be set in the 'Entity type' selectbox.

If you press the 'save' button, the content in the textarea will be saved under the name in the 'Entity name' textfield. You can easily copy entities by simply changing the namefield and pressing 'save' (for example).


Content entities

Template

This is the basic content type for the CMS.

The content of this template is plain HTML with a special include syntax:

   #<destination entity name>,<argument 1>, ... , <argument n>#

This include statement expands to the output of the destination entity.

For example, if you have a content entity ExternLink (see below) speciallink:

   <a href="%url"><b>%label%</b></a>

and write:

   #speciallink,http://www.google.de/,fancy search page!#

This will be expanded to:

   <a href="http://www.google.de/"><b>fancy search page!</b></a>

If you want to have a simple '#' in the output, you have to escape it with a second #, so following examples are left untouched:

   ##foo bar, lalal
   ##bla##

NODE: all whitespace beween the commas in the list in the include statement will be preserved, if you want to have an ',' in the argument, escape it with a '\':

   #speciallink,http://www.foobar.com/,This is it\, or not?#

Would be expanded to:

   <a href="http://www.foobar.com/"><b>This is it, or not?</b></a>

The fact that all whitespace is preserved makes it obviously possible to have include statmes over multiple lines:

   #cooltemplate,
      Testing is nice\,
      debugging is better!
   #

This would replace argument 1 in cooltemplate with:

   "\n      Testing is nice,\n      debugging is better!\n   "
ARGUMENTS
The arguments to a template can be included by using the position number of the argument in the include statement as content entity name in a include statement.

The first argument would be: #0# The first argument #0# to the template is always it's own name. And the first argument after the entity name would be: #1#

When an argument is expanded, the ',' and '\' in the expansion will be escaped by a '\'. So you can savely expand arguments as arguments of an include statement.

When expanding an argument with the #<number># syntax, you get an '#' unescaped expansion. That means, that you can pass include statements as arguments to an entity.

If you don't want an include statement in an argument expanded, you can use the #?<number># syntax. It escapes the '#' in the argument.

I hope the following examples help:

EXAMPLE:

   When including a template with:
      #mypage,A fine title,Foo,Blubb,##testo###
   Then the arguments in the 'mypage' template will
   be expanded as follows:
   #0#  => mypage
   #1#  => A fine title
   #2#  => Foo
   #3#  => Blubb
   #4#  => <content of the 'testo' entity>
   #?4# => #testo#

ESCAPING/QUOTING EXAMPLE:

   If you have an template entity 'foopage' like this:
      Foopage, 
      argument 1 unescaped #1#
      argument 2 escaped   #?1#
   And an template entity 'garfield' like this:
      Meow Meow, Growl
   And you have following include statement in another 
   Template entity:
      #foopage,##garfield###
   Then the output would look like:
      Foopage,
      argument 1 unescaped Meow Meow, Growl
      argument 2 escaped   #garfield#

PerlTempl

This is a special Type of Templates, it's for the users that know Perl and want more flexibility in their Templates.

The PerlTempl has a special embedding syntax for the Perl code. You just enclose your perl code in '<:' and ':>'. If you want to make output in the Perl code use the p(@strings) function (see below).

PerlTempl also provides a short cut syntax for appending strings/scalars to the output: '<? $blubb :>' is the same as '<: p ($blubb) :>'.

There are some symbols in the scope of the executed code that are allowed to be used (that means, that it's guranteed that these functions and variables are in the scope).

The output of the PerlTempl will be processed like a simple Template entity, that means that the include statements (for example '#include_this_site#') are expanded (see Template entity).

Note that exceptions (if you 'die, or have an syntax error) are caught and displayed instead of the output of PerlTempl together with the source of the PerlTempl entity.

ARGUMENTS
The arguments of the include statement can be accessed via the @args array, that is in scope.

FUNCTIONS
The following list of additional (useful) functions can be used in a PerlTempl entity:
p(@strings)
Takes am include statement and escapes it.

include_escape($str)
Takes a string and returns an include statement escaped string. This might be useful to escape the arguments for a Template include statement.

EXAMPLE

   my $a = include_escape("#foobar,blubb#")
   $a == "##foobar,blubb##"

include_unescape($str)
Takes an escaped include statement and unescapes it.

EXAMPLE

   my $a = include_unescape("##foobar,blubb##");
   $a == "#foobar,blubb#"

comma_escape($str)
This function escapes the commas (',') and backslashes ('\') in $str with a backslash ('\'). This is useful for escaping arguments for Template include statements.

EXAMPLE

   my $a = comma_escape("This is a nice, thing");
   $a == "This is a nice\\, thing"

html_escape($str)
This takes the string $str and escapes all HTML formatting characters in it.

EXAMPLE

   my $a = html_escape ("<foo>");
   $a == "&lt;foo&gt;"

url_escape($str)
This takes a string and escapes it so that i can be used in an URL as CGI parameter.

url_unescape($str)
This takes a string and unescapes the escaping of url_escape.

EXAMPLE
This is a example site for putting all the arguments of the PerlTempl entity into a list:
   <: shift @args; # ignore the first argument, it's the name of the entity
      # note here, that you can't put a :> in a perl comment, it would result in
      # a syntax error.
   :>
   <table border="0">
      <: for (@args) { :>
         <tr><td><?html_escape ($_):></td></tr>
      <: } :>
   </table>

PerlFilter

This is another very special Template type. The content of this entity is just plain perl code, that will be called like a ordinary subroutine.

The arguments to a PerlFilter subroutine can be interpreted as names of entities (by prepending 'f:' to the argument), which are called without any arguments (this might be extende in later versions of ECMS) and their output will be used in their place as argument to the PerlFilter entity.

The return value of the subroutine is the output that will be displayed.

Same as in PerlTempl the output will be processed like a simple Template (see Template and PerlTempl).

And also any exceptions or syntax errors are caught end displayed like PerlTempl does.

ARGUMENTS
The arguments of the include statement have a special interpretation

EXAMPLE
Assume you have a PerlFilter named 'coolfilter' defined like this:
   # this PerlFilter just takes all
   # argument entitiy output and substitutes
   # the word which is the second argument to the Filter with 
   # 'bar' and returns eveything concationated.
   my (@a) = @_;
   shift @a; # ignore the name of the PerlFilter entity ('coolfilter')
   my $word = shift @a;
   @a = map { s/\Q$word\E/bar/gs; $_ } @a;
   return join '', @a;

And you have a Template named 'inputtemplate' with following content:

   All my foos were alone in the foo.

If you know call the PerlFilter 'coolfilter':

   #coolfilter,foo,f:inputtemplate#

You get the output:

   All my bars were alone in the bar.

FileLink

A link to a file in the data directory of the server. Special with this link is: when you are in edit mode of the CMS, a link will be displayed next to this file link, to make it easier to upload a file to the server.

ARGUMENTS
A FileLink template takes as first argument: the filename on the server (this can also be a path).

All other arguments can be accessed with the %<argument number>% placeholder.

PLACEHOLDERS
   %urlbase% -  base URL to the CMS' data directory
   %url_filename% - the first part of the filename 
                    (without extension) (url escaped)
   %url_fileext% - the file extension, might be empty
                   if the file has no extension.
                   (url escaped)
   %url% - the complete url to the file
   %file% - the complete filename
   %0% .. %n% - the 'n-th argument 
                (0 is the name of the entity,
                 1 is the filename, and so on...)
EXAMPLE
A typical template would be:
   <a href="%url%">
      <img border="0" src="%url%" alt="%file%" />
   </a>

And the usage would be (If you defined a FileLink with the name imagefile):

   #imagefile,my_cat.png#

InternLink

A link to another content page in the CMS.

ARGUMENTS
A InternLink takes 2 arguments: the name of the internal CMS entity to link to and the label of the link.

If the label argument is omitted, the label will be set to the first argument.

PLACEHOLDERS
   %url% - replaced by the destination 
           url to the internal page
   %label% - replaced by the link label

NOTE: The first argument (placeholder %url%) will be used as %label% when the second argument is omitted.

EXAMPLE
A typical internal link template is:
    <a href="%url%">%label%</a>

A usage in a template would be (if you defined a InternLink template with the name i:

   #i,links,Link page#
Or:
   #i,links#

ExternLink

A link to an external source (other website, image, whatever). The contents of this entity is a template for a link to an external source.

NOTE: The first argument (placeholder %url%) will be used as %label% when the second argument is omitted.

ARGUMENTS
A ExternLink takes 2 arguments: the url to the external resource and the label of the link.

If the label argument is omitted, the label will be set to the first argument.

PLACEHOLDERS
   %url% - replaced by the destination url
   %label% - replaced by the link label
EXAMPLE
A typical external link template is:
   <a href="%url%">%label%</a>

A usage in a template would be (if you defined a ExternLink template with the name i:

   #i,http://www.google.de/,a great search page#
Or:
   #i,http://www.google.de/#

Redirector

This entity implements a entity name redirector. It's a simple plain Perl subroutine and the code will be enclosed by sub { } like the PerlFilter.

The return value can be a list, and the first element of that list is the entity that will be called. The rest of the return list is used as arguments to that entity.

There is a special (redirector) entity, that will be called when it exists: '_entry' for every call of the CGI.

Warning! If you use '_entry' and return non-exisiting entity names, you will be redirected to the editor. This might result in unexpected behavoir to you. Just check whether the '_entry' redirector does really the right thing. (This might not be easy to debug, but try to use warn() and see the webserver logs for help).

See PerlTempl for a listing of aviable functions. But! The p() function isn't supported by Redirector.

ARGUMENTS
The first argument is the name of the redirector itself, and the second is the entity name that the redirector is called with. The rest of the arguments have no special meaning.

EXAMPLE
TODO

CommentBoard

This entity implements a simple comment board. The content of this entity is a special kind of configuration format for the comment board. You can and have to make your own layout for the board.

All posts are stored in the $board_dir with the name of the board (see below also).

Each post has a random token to seperate it from the other posts in the board directory.

ARGUMENTS
It only has 1 argument: The name of the board. Be careful not to have a '/' in the name, as the name will be used as subdirectory name in the $board_dir.

CONFIGURATION and PLACEHOLDERS
TODO

EXAMPLE
TODO


KNOWN BUGS

If are logged in and hit reload too often, you maybe get a 'Internal Server Error' 500. That happend because ECMS uses GDBM_File, which seems to be locking. If you get this, just reload once more.

Also, there is no further locking implemented around GDBM_File, it may happens, if your libgdbm doesn't support locking, that the database becomes corrupted.


COPYRIGHT

Copyright (C) 2005 Robin Redeker <elmex@x-paste.de>. All rights reserved.

This library is free software. You can modify and or distribute it under the same terms as Perl itself.


SEE ALSO

 PApp/Agni


AUTHOR

 Robin Redeker <elmex@x-paste.de>
 http://www.x-paste.de/