One workaround is to use backticks:
print `command here`;
But a cleaner solution is provided by the
Apache::SubProcess module. It overrides the
exec( ) and system( ) calls
with calls that work correctly under mod_perl.
Let's look at a few examples. This example overrides
the built-in system( ) function and sends the
output to the browser:
use Apache::SubProcess qw(system);
my $r = shift;
$r->send_http_header('text/plain');
system "/bin/echo hi there";
This example overrides the built-in exec( )
function and sends the output to the browser. As you can guess, the
printstatement after the exec(
) call will never be executed.
use Apache::SubProcess qw(exec);
my $r = shift;
$r->send_http_header('text/plain');
exec "/usr/bin/cal";
print "NOT REACHED\n";
The env( ) function sets an environment variable
that can be seen by the main process and subprocesses, then it
executes the /bin/env program via
call_exec( ). The main code spawns a process, and
tells it to execute the env( ) function. This call
returns an output file handle from the spawned child process.
Finally, it takes the output generated by the child process and sends
it to the browser via send_fd( ), which expects
the file handle as an argument:
use Apache::SubProcess ( );
my $r = shift;
$r->send_http_header('text/plain');
my $efh = $r->spawn_child(\&env);
$r->send_fd($efh);
sub env {
my $fh = shift;
$fh->subprocess_env(HELLO => 'world');
$fh->filename("/bin/env");
$fh->call_exec;
}
This example is very similar to the previous example, but it shows
how you can pass arguments to the external process. It passes the
string to print as a banner via a subprocess:
use Apache::SubProcess ( );
my $r = shift;
$r->send_http_header('text/plain');
my $fh = $r->spawn_child(\&banner);
$r->send_fd($fh);
sub banner {
my $fh = shift;
# /usr/games/banner on many Unices
$fh->filename("/usr/bin/banner");
$fh->args("-w40+Hello%20World");
$fh->call_exec;
}
The last example shows how you can have full access to the
STDIN, STDOUT, and
STDERRstreams of the spawned subprocess, so that
you can pipe data to a program and send its output to the browser:
use Apache::SubProcess ( );
my $r = shift;
$r->send_http_header('text/plain');
use vars qw($string);
$string = "hello world";
my($out, $in, $err) = $r->spawn_child(\&echo);
print $out $string;
$r->send_fd($in);
sub echo {
my $fh = shift;
$fh->subprocess_env(CONTENT_LENGTH => length $string);
$fh->filename("/tmp/pecho");
$fh->call_exec;
}
The echo( ) function is similar to the earlier
example's env( ) function.
/tmp/pecho is as follows:
#!/usr/bin/perl
read STDIN, $buf, $ENV{CONTENT_LENGTH};
print "STDIN: '$buf' ($ENV{CONTENT_LENGTH})\n";
In the last example, a string is defined as a global variable, so its
length could be calculated in the echo( )
function. The subprocess reads from STDIN, to
which the main process writes the string ("hello
world"). It reads only the number of bytes specified
by the CONTENT_LENGTH environment variable.
Finally, the external program prints the data that it read to
STDOUT, and the main program intercepts it and
sends it to the client's socket (i.e., to the
browser).
Available from CPAN. See the module manpage for more information.