Wrapping Perl with PHP
Wednesday, 9 October 2008 - Jochen Lüll
PHP Perl Wrapper
Although PHP is good for creating web pages it might be sometimes desirable to use Perl scripts.
This articles shows how to write an PHP to Perl wrapper to supper Per CGI scripts for web hosting solutions on which only PHP is supported.
A
lthough Perl CGI scripts are not officially supported, most ISPs using
Unix based servers will have Perl installed on there systems.If this is the case and PHP is support for creating web pages, the wrapper which we will develop can be used.
One thing first. I'm not a PHP developer and this is one of the first PHP scripts I've written so far. So the script is far from being perfect and has some limitations (see box on the right). But for simple Perl scripts it should be sufficient.
The Script
Limitations
The wrapper script performs the following tasks:- Not all environment variables might have been adjusted
accordingly. For simple Perl scripts that should not bee an issue.
- Multipart/form-data
is not passed to the Perl script. This is due to the fact that
$HTTP_RAW_POST_DATAdoes not handle Multipart/form-data.
Wrapper Limitations
- Calls Perl and pipes the standard input of the PHP script to the stdin of the Perl script.
- Reads the response from stdin of the Perl script
- Extracts the header information and sets them by
calling
header()in the PHP script. - Reads stderr from Perl script and returns "500 Internal Server Error" if the exit value of the Perl process is not equals 0 and the <i>debug</i> parameter is not present.
The script is called in the following way:
perlwrapper.php?cgi=<name
of script>[&debug=1]The
debug parameter is optional and
prints the content of the stderr output instead of a "500 Internal
Server Error" message. <?php
/* PERL CGI WRAPPER PHP SCRIPT */
/* Note: Does not handle "multipart/form-data" */
/* Populate $HTTP_RAW_POST_DATA if not available */
if (!isset($HTTP_RAW_POST_DATA)){
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
}
/* A little bit of security */
$cgi = str_replace("..", "", $cgi);
$command = "perl ./" . $cgi;
$io = array();
$p = proc_open($command,
array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')),
$io);
/* Write the raw POST data to the pipe */
fwrite($io[0], $HTTP_RAW_POST_DATA);
fclose($io[0]);
/* Read output sent to stdout. */
while (!feof($io[1])) {
$stdout .= fgets($io[1]);
}
/* Extract header section */
preg_match('/^(.*?)[\n]{2}(.*)$/s', $stdout, $regs);
/* Set HTTP headers */
$headers = preg_split("/[\n]/", $regs[1]);
foreach ($headers as $header) {
header($header);
}
$stdout = $regs[2];
echo $stdout;
/* Read output sent to stderr. */
while (!feof($io[2])) {
$stderr .= fgets($io[2]);
}
/* Close handles */
fclose($io[1]);
fclose($io[2]);
$exit = proc_close($p);
/* Set HTTP status code to 500 if an error occured */
if($exit != 0 && !isset($debug)) {
header(getenv("HOME") . " 500 Internal Server Error");
}
else if($exit != 0) {
print $stderr;
}
?> Source Code of perlwrapper.php
Adjusting Perl Scripts
Normally the Perl scripts should run out of the box.In some cases the bellow errors might occur.
Insecure $ENV{PATH} while running with ...
Sometimes the following error might occur: "Insecure $ENV{PATH} while running with ..."To avoid this error message add the following lines to the start of your script:
# To prevent: "Insecure $ENV{PATH} while
running with ..."
$ENV{'PATH'} =~ /(.*)/; $ENV{'PATH'} = $1;
$ENV{'PATH'} =~ /(.*)/; $ENV{'PATH'} = $1;
Perl Script adjustment (1)
Insecure dependency in require while running setgid at ...
If you get the error message "Insecure dependency in require while running setgid at ...", add the parameters -wU to the Perl call in perlwrapper.php.$command = "perl -wU ./" . $cgi;
Perl Script adjustment (2)
Demos
Visit the demo page, if you would like to see the wrapper in action.Hope this article is useful ... have fun!

(joschi)
Version: 0.1
Author's e-Mail address: jochen [at] fun2code.de
