=head1 NAME
Mod_perl_cgi - running CGI scripts under mod_perl (
$Date
: 1998/05/28 21:55:33 $)
=head1 DESCRIPTION
This part of the mod_perl FAQ deals
with
questions surrounding CGI
scripts.
=head1 Why doesn't
my
CGI script work at all under mod_perl?
What are the symptoms? Here are some possibilities.
=head2 File not found
Have you made the correct entries in Apache's configuration files? You
need to add the C<Alias /perl/ ...> and C<E<lt>Location /perlE<gt>...>
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.
=head2 Forbidden
You don't have permission to access /perl/foo on this server.
chmod
755 /path/to/
my
/mod_perl/scripts
chmod
755 /path/to/
my
/mod_perl/scripts/foo
=head2 Internal Server Error
The script died
with
an execution error. There should be an error message
in the server's error.
log
saying why. Provided you are using CGI.pm, you
can also see what happens by running the script at a shell prompt.
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.
=head1 My CGI script behaves strangely under mod_perl. Why?
Remember that a conventional CGI script always starts up a fresh perl
interpreter, whereas a mod_perl script is reused in the same process
context many
times
. This means that certain categories of variables can
survive from one invocation of the script to the
next
. You can make that
work to your advantage, but you can also be caught out by it.
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
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.
=head2 The server terminates
after
processing the first request
Your script is calling the CORE perl C<
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 C<
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
C<
exit
()>
with
C<
goto
label;>
See also what mod_perl_traps says about C<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 C<Apache-E<gt>
exit
(-2)> should be used.
=head2 Variables retain their value from one request to the
next
The so-called sticky query effect happens
when
the CGI query object, or
another request-specific variable,
has
a lifetime longer than a single
execution of your script and does not get reinitialised
each
time
the
script is invoked.
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:
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 L<perlsub/
"Private Variables via my()"
>, 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:
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,
$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).
=
for
html
<a href=
"mjtg-news.txt"
>mjtg-news.txt</a>
=head2 Variables B<still> retain their value from one request to the
next
CGI.pm must pull some extra tricks
when
it is being used via
Apache::Registry. Versions of CGI.pm
before
2.35 did not know this,
and Apache::Registry will complain
if
you
try
to
use
an earlier
version.
CGI.pm detects that it is running under Apache::Registry by looking
for
an environment variable. This test can fail
if
C<
use
CGI> is
evaluated too early,
before
the environment
has
been set up. That can
happen
if
you have C<
use
CGI> in a script and pull the script in
with
a C<PerlRequire> directive in httpd.conf. Replacing C<
use
CGI>
with
C<
require
CGI> will fix it.
=head2 Do I have to rewrite
my
legacy code
for
mod_perl?
If you have CGI code that seems to be fundamentally at odds
with
mod_perl's
"compile once, run many"
environment, you may be find that
it will work
if
run under the module C<Apache::PerlRun>. See the
documentation of that module, which is included
with
recent versions
of mod_perl.
=head1 How can
my
script
continue
running
after
sending the response?
If the client submits a form that will take some
time
to process, you
may want to
say
"Thanks for submitting the form"
and
close
the
connection,
before
processing it.
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
) });
}