To see how to navigate between requests, let's use mod_perl to
log to a database.
In this example, we'll use a persistent database connection to a relational
database. We'll also connect to a MySQL
database - a free, powerful relational database. Note that the concepts described
here are applicable to most database servers, especially those that have
drivers written for the DBI
interface.
Let's start with the database design. In this example, all we want to
log is which hosts accessed what file, and we'll rely on Apache's text
logging to give us the detailed info. To keep things simple, let's use the
following SQL statement to define our table:
CREATE TABLE LOGS
(
HOST VARCHAR(255) NOT NULL,
REQUEST VARCHAR(255),
TIME_STAMP DATE
);
With the table built and the database accepting connections, we now
need to tell Apache that we want to create a handler that logs all requests
to the directory /images. To do this, stick the following in the
access.conf file:
<Location /images>
PerlLogHandler Apache::Logger
</location>
Once again we've defined a Perl handler for a specific URL. This time we're
doing logging, so we use the PerlLogHandler.
package Apache::Logger;
use Apache ();
use Apache::Constants qw(:common &OPT_EXECCGI &REDIRECT);
use Mysql;
BEGIN {
$dbh = Mysql>connect(undef,
"logs",
undef,
"root") ||
die "DBErr: $!\n";
}
sub handler {
my $r = shift; # @_[0] contains a reference to
# the current request handler
my ($request);
my ($hostname);
# Returns a blessed reference
if ($r->main) { # unless this is the main request
$orig = $r->main;
} else {
$orig = $r;
}
$hostname = $orig->get_remote_host;
$request = $orig->filename;
$dbh->query("insert into LOGS (host,request,time_stamp) VALUES
('$hostname','$request',NOW())");
}
END {
undef($dbh);
}
1;
This example does a few important things. First, it makes simple use of logging. We can define a handler to be
called after each connection is serviced.
It also takes advantage of nested requests by using the reference to the
current request to reference the original incoming connection. What we've
done is log what the client was originally requesting, not what it was
internally mapped to. This is not always ideal - sometimes you want to log
the request after some internal mapping has taken place within Apache. In
that situation, you can use the next, last, and prev commands to
manipulate your way around the request handlers.
We also build a persistent database connection in this example. When
Apache creates a new child, it has to create a new copy of the Perl
interpreter, which will call the data within the BEGIN block as soon as it
has compiled the module. The same is true for the END block, which is
processed as the Perl interpreter is shutting down. This means that we can
build a connection to the database for each Apache sub-process and have
that connection open for the duration of the lifetime of that child.
next page»