This is a list of answers to Frequently Asked Questions concerning mod_perl.
This FAQ is maintained by Patrick Michael Kane, please send all updates to modus@enews.com.
Additional information can be found at the mod_perl homepage at: http://www.osf.org/~dougm/apache/.
mod_perl is an Apache module that embeds a Perl interpreter into the Apache HTTP server.
The benefit of this [mod_perl] is that we are able to run scripts without going through the expensive (fork/exec/parameter passing/parsing, etc.) CGI interface. The scripts will run faster and they have direct access to the C API of the server.
Since mod_perl scripts have access to the server's C API, full-fledged Apache modules can be written in Perl! For example, the current mod_perl package has bundled with it an example module, written in Perl, that replicates the behavior of the Apache 1.1.1 server side includes (SSI) module, and lets Perl programmers extend the module from the comfort of a Perl programming environment instead of C.
No. mod_perl is not CGI and requires some changes to your existing scripts to get them running. However, much work has been done to make this task easier:
For more technical information on porting your CGI to mod_perl, see Q3.1
Yes. You can subscribe by sending mail to to majordomo@listproc.itribe.net with the string "subscribe modperl" in the body. The list is archived at http://www.coe.missouri.edu/~faq/lists/modperl/.
It's a good idea to check both this FAQ and the mail archives before posting a question to the mailing list.
Doug MacEachern
Rob Hartill
Jeff Rowe
You will need:
Note: mod_perl includes a patch for Perl5.003 that fixes an obscure filehandle bug. This bug was fixed in subsequent releases of Perl5.
In order to simply get your scripts running, only a few changes are necessary:
First, you need to add some directives to Apache's configuration files (typically srm.conf). You'll need to remove any ScriptAlias (or equivalent) directives that tell Apache to treat you CGI as such and instead, tell Apache that mod_perl is going to invoke your Perl e.g.
Alias /perl/ /real/path/to/perl-scripts/ <Location /perl> SetHandler perl-script PerlHandler Apache::Registry Options ExecCGI </Location>Now, any file that lives under /perl will be compiled by mod_perl, provided the file has the executable bit set and server configuration allows execution of that file. The file is re-compiled only if it has changed on disk.
By default, mod_perl does not send any headers by itself, however, you may wish to change this:
PerlSendHeader On
By default, mod_perl does not setup %ENV, you may wish to change this:
PerlSetupEnv On
Apache's i/o is not stream oriented. So, by default, you cannot
print() to STDOUT from your script, use $r->print() instead.
Nor can you read() from STDIN, use $r->read*() or the $r->content methods to read POST data. As of Perl5.003_02, there are two mechanisms in place for redirecting the STDIN and STDOUT streams. (See section 1.3.)
This is all very straightforward but a little tedious for new users. Try not to let it let it put you off.
$r->print "Content-type: text/html\n\n"; $r->print "Date: ", scalar localtime, "\n"; $r->print "%ENV: \n", map { "$_ = $ENV{$_} \n" } keys %ENV;
mod_perl is not CGI. this is a lesson you must learn. CGI scripts written in Perl are standalone processes that are called once and die after one request. Of course, you now know that this is a tad inefficient and that there's a lot to be gained by mod_perl's approach of reusing the same pre-"compiled" Perl code to serve multiple requests. However, many experienced CGI script writers encounter some unexpected (though reasonable once understood) quirks that the one off CGI processes are immune from.
Properly scope your variables. Stop and read that sentence again. Conventional CGI scripts can be as sloppy with their namespace as they want, since they are restarted anew for each request. Your mod_perl script has a much longer lifetime (potentially as long as your Apache server is running), and requires much more care. Scope everything except long-lived variables with my() and use strict; so Perl will demand that you recognize your global variables.
Localize global variables. If you change any of Perl's global variables (e.g. $/ to change the input record separator), or even your own global variables remember to reset them or better still, always localize global variables before using them, e.g. local($/) = undef. If you can, reduce your dependency on global variables.
A local() variable is just a local copy of a local variable that can be seen by other subroutines. A my() variable only exists within the scope of a block, in this case the subroutine. If you use the -w flag for Perl (or set $^W=1; in mod_perl), you'll see something like:
Variable "$var" will not stay shared at (eval 17) line 3206.
This means the inner subroutine cannot change $var because $var is scoped using my() in the outer subroutine. Try passing $var to the subroutine as a parameter. See 'perlref' in the Perl man pages.
sub something {}
but 'something' is actually the filename translated into a valid package name. Your top level program is actually a subroutine. It pays to remember this when using global variables in subroutines (See section 3.2).
mod_perl provides a hook for each stage, where a perl subroutine callback may be defined to handle that stage on per-directory basis. The stages and coresponding perl hooks are as follows:
We've seen one example of an Apache/Perl module implementing a PerlHandler in section 3.1, the Apache::Registry module. Here's an example of how to write your own module:
PerlScript /usr/local/httpd/myperl/handlers.pl <Location /myperl/> SetHandler perl-script PerlHandler MyPackage::handler </Location>This tells Apache to call the mod_perl subroutine 'MyPackage::handler' whenever it sees requests that are prefixed by '/myperl/'. The subroutine 'MyPackage::handler' can look at the URL and decide what to do next (in this example it'd probably call another subroutine that acts like a standalone CGI script.
PerlModule MyPackage <Location /myperl/> SetHandler perl-script PerlHandler MyPackage::handler </Location>If PerlHandler is not a defined subroutine, mod_perl assumes it is a class name which defines a handler subroutine. This allows you to reduce configuration to simply:
<Location /myperl/> SetHandler perl-script PerlHandler MyPackage </Location>
For the '/myperl/' example above, you might try something like this:
# this is written in perl. It doesn't need #!/usr/local/bin/perl package MyPackage; sub handler { my($r) = @_; # grab the request info "object" that mod_perl has # has kindly passed as a subroutine argument. %ENV = $r->cgi_env; # setup the ENVironment variables for # the request. Easy eh ? my $uri = $r->uri; # what does the URI (URL) look like ? if ($uri =~ /hello/) { say_hello($r); } elsif ($uri =~ /goodbye/) { say_goodbye($r); } return 1; # tell mod_perl that we did our stuff error free } sub say_hello { my($r) = @_; $r->status = 200; # All's ok, so set a "200 OK" status $r->send_http_header; # Now send the http headers. $r->print("Hello from mod_perl"); } sub say_goodbye { my($r) = @_; $r->status = 200; # All's ok, so set a "200 OK" status $r->send_http_header; # Now send the http headers. $r->print("Goodbye from mod_perl"); }mod_perl ships with several modules that step in during various stages of a request: