ECMS - easy content management system
ecms.pl
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.
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.
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).
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$pass$data_dirYou 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_dirThis 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$files_dir.
$board_dir
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/";
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.
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.
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).
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 "
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#
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.
@args array,
that is in scope.
p(@strings)include_escape($str)EXAMPLE
my $a = include_escape("#foobar,blubb#")
$a == "##foobar,blubb##"
include_unescape($str)EXAMPLE
my $a = include_unescape("##foobar,blubb##");
$a == "#foobar,blubb#"
comma_escape($str)$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)$str and escapes all HTML formatting characters in it.
EXAMPLE
my $a = html_escape ("<foo>");
$a == "<foo>"
url_escape($str)url_unescape($str)url_escape.
<: 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>
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.
# 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.
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.
All other arguments can be accessed with the %<argument number>% placeholder.
%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...)
<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#
A link to another content page in the CMS.
If the label argument is omitted, the label will be set to the first argument.
%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.
<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#
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.
If the label argument is omitted, the label will be set to the first argument.
%url% - replaced by the destination url
%label% - replaced by the link label
<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/#
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.
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.
$board_dir.
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 (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.
PApp/Agni
Robin Redeker <elmex@x-paste.de> http://www.x-paste.de/