NOTE: Moved to Wiki

Casual Hacking

Main Menu

OOP Perl CMS using Apache & mod_perl w/ MongoDB backend

A barebones framework as an example, or basis for your own CMS system.

This basic CMS framework is written in Perl, following Khurt Williams' Object Oriented Perl methodology. We use mod_perl configuration directives in the Apache vhosts file to specify our package directory /www/web_root/lib. This CMS is template based, it is configured to pull the template from /www/web_root/ui/layout.html. The example shows how to define functions to dynamically handle requests, define static content in MongoDB, or return static html pages in the web_root.

 

Download

mod_perl CMS with MongoDB backend code download at github.

git@github.com:creamy/mod_perl-mongodb-cms.git

The workhorse of the CMS system is in /lib/Req.pm. The default sub home handles requests if no subroutine is found for the request. In sub home we check the MongoDB for a page which corresponds to the request URI (*path*).

There are some example subs defined in /lib/Req.pm to show how to handle form processing and dynamic content. See sub new_account, which loads a static form in /ui/join.html, sub list_accounts, which displays the list of user accounts, and sub req_new_account, which processes a form submission, validates input and reports errors (or inserts a new record into the MongoDB database on success).

Request -> http://www.example.com/new_account loads sub new_account
Request -> http://www.example.com/list_accounts loads sub list_accounts

Create a function within /lib/Req.pm named "mypage" and access using http://www.example.com/mypage

The "path" parameter in MongoDB pages is path/to/page.

/lib/Auth.pm and /lib/Cookie.pm are the basis for a cookie-based authentication system. To use you will need to work out the details specific to your system.

Installation of components

Installing and setting up Apache, Perl, mod_perl MongoDB and the Perl MongoDB driver. In this example we will compile and build everything from source code, using the latest available releases. Generally it's good to install perl in it's own directory if you are using a yum/rpm package based system, to avoid conflicts with other installed system packages.

Apache 2.2.21

export LDFLAGS="-L/usr/local/lib64 -L/usr/lib64"
./configure --with-expat=builtin --enable-so --enable-rewrite --enable-ssl \
	--enable-cgi --with-ssl=/usr --disable-userdir --disable-status 
make
make install

edit /usr/local/apache2/conf/httpd.conf
uncomment the line
#Include conf/extra/httpd-vhosts.conf
for Virtual Hosting

perl 5.14.2

Build and install the latest Perl source.

export ccflags='-fPIC'
./Configure -des -Dprefix=/usr/local/perl5142 -Duse64bitall
make
make test
make install

# /usr/local/perl5142/bin/perl -v

This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux

Copyright 1987-2011, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

Run CPAN for the first time and configure.

# /usr/local/perl5142/bin/perl -MCPAN -eshell

mod_perl-2.0.5

# /usr/local/perl5142/bin/perl  Makefile.PL MP_APXS=/usr/local/apache2/bin/apxs
make
make install

Add the following line to /usr/local/apache2/conf/httpd.conf

LoadModule perl_module          modules/mod_perl.so

Restart Apache

/usr/local/apache2/bin/apachectl stop
/usr/local/apache2/bin/apachectl start

Check the server response headers

# HEAD http://127.0.0.1
200 OK
Connection: close
Date: Sun, 27 Nov 2011 18:29:27 GMT
Accept-Ranges: bytes
ETag: "3018cff-90a-4b2a7edef2d00"
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8e-fips-rhel5 mod_fcgid/2.3.6 PHP/5.3.8 mod_perl/2.0.5 Perl/v5.14.2
Content-Length: 2314
Content-Type: text/html
Last-Modified: Sat, 26 Nov 2011 19:03:48 GMT
Client-Date: Sun, 27 Nov 2011 18:29:27 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1

Python-2.7.2

We need Python for scons. (scons is used to install MongoDB)

./configure --prefix=/usr/local --enable-unicode
make
make install

scons-2.1.0

/usr/local/bin/python setup.py install

MongoDB

mongodb-src-r2.0.1

mkdir -p /data/db

scons .
scons --prefix=/usr/local/mongo install

/usr/local/mongo/bin/mongod --bind_ip=127.0.0.1 \
	--dbpath=/data/db &

MongoDB Perl driver

export GIT_SSL_NO_VERIFY=true
git clone https://github.com/mongodb/mongo-perl-driver.git
cd mongo-perl-driver

We need to install some Perl modules

/usr/local/perl5142/bin/cpan Bundle::CPAN
/usr/local/perl5142/bin/cpan Module::Install
/usr/local/perl5142/bin/cpan Test::Exception
/usr/local/perl5142/bin/cpan Any::Moose
/usr/local/perl5142/bin/cpan Class::Method::Modifiers
/usr/local/perl5142/bin/cpan Tie::IxHash 
/usr/local/perl5142/bin/cpan boolean 
/usr/local/perl5142/bin/cpan Digest::MD5 
/usr/local/perl5142/bin/cpan DateTime
/usr/local/perl5142/bin/cpan Try::Tiny
/usr/local/perl5142/bin/cpan File::Slurp
/usr/local/perl5142/bin/cpan JSON
/usr/local/perl5142/bin/cpan File::Temp
/usr/local/perl5142/bin/cpan Data::Types

Now we can install the driver.

/usr/local/perl5142/bin/perl Makefile.PL
make
make test
make install

Connect to CMSDB and insert some data.

/usr/local/mongo/bin/mongo CMSDB
db.users.insert({username:'waitman',accountid:'3778fc71686d023f4d8ab1848b64f27b'});
db.pages.insert({path:'test',content:'<h1>This is a test page.</h1><p>Testing 123.</p>'});
db.pages.insert({path:'test2',content:'<h1>This is a second test page.</h1><p>Testing Again.</p>'});


--optional--

libapreq2

This package is similar to CGI.pm and may provide some additional features beyond mod_perl, however is not required for this example.

/usr/local/perl5142/bin/cpan ISAAC/libapreq2-2.13.tar.gz

edit /usr/local/apache2/conf/httpd.conf

add the following line ->

LoadModule apreq_module   modules/mod_apreq2.so

Check server response headers

# HEAD http://127.0.0.1
200 OK
Connection: close
Date: Sun, 27 Nov 2011 20:53:35 GMT
Accept-Ranges: bytes
ETag: "3018cff-90a-4b2a7edef2d00"
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8e-fips-rhel5 mod_fcgid/2.3.6 
	PHP/5.3.8 mod_apreq2-20090110/2.8.0 mod_perl/2.0.5 Perl/v5.14.2
Content-Length: 2314
Content-Type: text/html
Last-Modified: Sat, 26 Nov 2011 19:03:48 GMT
Client-Date: Sun, 27 Nov 2011 20:53:35 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1

Apache2 Virtual Hosts configuration for mod_perl.

Here is an example configuration for a mod_perl based site. There are several things going on here. We are loading APR::Table for table-based strings similar to Perl hash (which is needed for mod_perl $r Request/Response object). We need the startup.pl script to set the library path for our application (/lib). Also we set a Fixup handler (/lib/Fixup.pm) which emulates Apache mod_dir behavior. (without the Fixup.pm then we won't have a DirectoryIndex page, ie index.pl. The root of the mod_dir requirement is that there is a difference between http://www.example.com and http://www.example.com/ - by default Apache will redirect requests for http://www.example.com to http://www.example.com/ - to the root directory path. It is possible to disable this default behavior however it is not recommended. (To avoid problems between requests such as /path and /path/) Using a Fixup is the way to go.

The mod_perl handler happens before mod_dir, without the Fixup the DirectoryIndex is not going to work properly.

Our Response Handler (/lib/Response.pm) is called after /lib/Fixup.pm and after startup.pl.

Location /ui disables the Perl Handler

Note that we can call additional modules to be loaded in the site configurationm, as needed. Check out the mod_perl documentation (see Reference section below).


<VirtualHost *:80>
    ServerAdmin waitman@waitman.net
    DocumentRoot "/www/web_root"
    ServerName www.example.com
    ErrorLog "logs/example-errors"
    CustomLog "logs/example-access" combined
    PerlPostConfigRequire /www/web_root/lib/startup.pl
	PerlModule APR::Table
	<Location />
        	SetHandler perl-script
		PerlResponseHandler Response
		PerlFixupHandler Fixup
		Options +ExecCGI
		DirectoryIndex index.pl
	</Location>
	<Location /ui>
		SetHandler none
	</Location>
	<Directory "/www/web_root">
		Options none
		AllowOverride None
		Order allow,deny
		Allow from all
		DirectoryIndex index.pl
	</Directory>
</VirtualHost>

<VirtualHost *:80>
    ServerName example.com
    ServerAlias *.example.com
    Redirect permanent / http://www.example.com/
</VirtualHost>

 

References

Perl / OOP Perl
http://www.perl.org/
http://www.codeproject.com/KB/perl/camel_poop.aspx

ModPerl/mod_perl, APR
http://perl.apache.org/docs/2.0/index.html
http://perl.apache.org/docs/2.0/api/APR/Table.html
http://perl.apache.org/docs/2.0/user/handlers/http.html
http://httpd.apache.org/apreq/docs/libapreq2/
http://httpd.apache.org/apreq/docs/libapreq2/apreq_faq.html

MongoDB
http://www.mongodb.org/

Mongo Perl Driver
http://search.cpan.org/dist/MongoDB/lib/MongoDB/Tutorial.pod
http://search.cpan.org/~kristina/MongoDB-0.45/lib/MongoDB.pm

NoSQL
http://nosql-database.org/

BSON - Binary JSON
http://bsonspec.org/

Python
http://www.python.org

scons
http://www.scons.org/

Git
http://git-scm.com/
https://github.com/
http://forums.freebsd.org/showthread.php?t=10810

Apache 2.2
http://httpd.apache.org/

 


Copyright 2011 Waitman Gobble · waitman@waitman.net