Alias /perl/ ...
and <Location /perl>...
directives to access.conf as described in mod_perl.pod. And of course the
script must be in the directory specified by the Alias directive and it
must be readable and executable by the user that the web server runs as.
chmod 755 /path/to/my/mod_perl/scripts chmod 755 /path/to/my/mod_perl/scripts/foo
If the error.log claims there are syntax errors in your script, but
perl -c /path/to/my/mod_perl/scripts/foo
says it is OK, you have probably used __END__ or __DATA__. Sorry. Mod_perl's Apache::Registry can't deal with that.
When diagnosing a problem that might be caused by variable lifetimes, always start the web server in single process mode. Apache normally spawns a number of child processes to handle queries, and they get used in round-robin fashion, which makes test results unpredictable.
The command
# ./httpd -X
will start a single-process server with its default configuration. You can specify a different configuration with the -f flag (and thus use a different port number for testing, for instance).
Now try executing your script from a browser or with a tool such a wget. Here are some of the effects that you might see.
exit()
function. That is not a problem in a conventional CGI script, provided that
query processing is complete. But you almost certainly don't want to exit
in a mod_perl script. It kills the server process that handled the request,
meaning that the advantage of using mod_perl to avoid startup overhead is
lost.
The best way to avoid calling exit()
is to restructure the script so that all execution paths return to a common
point at the end of the script. If this seems impractical you can force the
same effect by placing a label after the last executable statement and
replacing calls to
exit()
with goto label;
See also what mod_perl_traps says about Apache::exit()
and the way that Apache::Registry causes it to terminate the script but not
the httpd child.
There may be exceptional circumstances in which you explicitly want to
terminate the httpd child at the end of the current request. In this case Apache->exit(-2)
should be used.
This does not matter in a conventional CGI script, because the script starts with a clean slate for each new request. But a mod_perl script gets compiled into a subroutine by the Apache::Registry handler and then processes an arbitrary number of requests. To make sure that both you and the perl interpreter have the same idea about the meaning of your script, make sure it starts like this:
#!/usr/bin/perl -w use strict;
It is good for you! It will make perl point out all variables that you have
not explicitly declared. You can then think about whether they need to be
global or if they can be lexical. Try to declare things lexically, with
my().
These variables disappear when the block they are
declared in ends, so they don't occupy memory when they are not in use and
they also do not need a run-time symbol table entry.
Beware, though, of referring to a lexical variable indirectly from within a subroutine. To quote perlsub, the variable ``... now becomes unreachable by the outside world, but retains its value between calls to ...'' the subroutine. You will see classic ``sticky query'' symptoms if your code looks like this:
#!/usr/bin/perl -w use strict; use CGI; my $q = CGI->new(); doit(); sub doit { print($q->header(), $q->start_html()); print('Value is ', $q->param('val')) if $q->param; $q->print('<p>', $q->startform, 'Value? ', $q->textfield(-name=>'val', -size=>20), ' ', $q->submit('enter'), $q->endform); print($q->end_html()); }
Because you remembered to put the -w switch on the first line, the error
log will tell you that ``Variable $q
will not stay shared''
(provided you are using perl5.004 or higher).
You must either pass the variable to the subroutine as a parameter,
doit($q)
sub doit { my($q) = @_; ....
or declare this variable to be global,
use vars qw($q); $q = CGI->new();
The reason why Perl works this way is explained in a news posting by Mike Guy that is included with this FAQ (mjtg-news.txt).
CGI.pm detects that it is running under Apache::Registry by looking for an
environment variable. This test can fail if use CGI
is evaluated too early, before the environment has been set up. That can
happen if you have use CGI
in a script and pull the script in with a PerlRequire
directive in httpd.conf. Replacing use CGI
with
require CGI
will fix it.
Apache::PerlRun
. See the documentation of that module, which is included with recent
versions of mod_perl.
You can achieve this by registering the subroutine that processes the form as a cleanup handler:
if($ENV{GATEWAY_INTERFACE} =~ /^CGI-Perl/) { Apache->request->register_cleanup(sub { doProcess($query) }); }