Using Perl in PHP
Using Perl in PHP
Dmitry Stogov | 8 comments | Wednesday, April 14, 2004 Intended Audience Introduction Perl Interpreter in PHP Using Perl Objects Error Handling Summary
Intended Audience
This article describes the perl extension for PHP. It is intended for developers who use both languages in their projects, or who are migrating from one language to the other. It could be of general interest to other developers.
Introduction
PHP and perl are two very popular Web programming languages. They both have many libraries and extensions that can simplify the process of development, but often you can find a perl library you want, and not the corresponding library in PHP. (Perl is older then PHP, so naturally it has a larger selection of libraries and extensions.) This was the main reason that the perl extension for PHP was written. Many large projects use both PHP and perl, with some subsystems implemented in PHP, and others in perl. Often these subsystems need to communicate with each other, and some perl modules - such as PHP::Include and PHP::Session - have been implemented to achieve this (see http://www.cpan.org/modules/by-module/PHP/ for more information). However, although they allow PHP session files to be read, PHP variables to be serialized and simple PHP code to be executed from within perl, there is no real communication between the two interpreters. The PHP perl extension was implemented to allow the usage of perl code from within PHP. It is a wrapper that embeds the perl interpreter and converts data from PHP to perl and back. At the time of writing it only provides a one-way interface from PHP to perl, but in the future it could be extended to implement a full two-way interface. The perl extension allows the programmer to do the following from a PHP script: load and execute perl files evaluate perl code access perl variables call perl functions instantiate perl objects access properties of perl objects call methods of perl objects
All these features are accessible through a single API class called Perl. PHP's perl extension is available from the PECL web site at http://pecl.php.net/package/perl. The latest development version can be obtained with the following CVS command: $ cvs -d :pserver:cvs.php.net:/repository co pecl/perl If you have a full perl installation, the extension will work with it. If you don't have perl on board,
you can still communicate with the perl interpreter through PHP by putting a copy of perl58.so or perl58.dll somewhere PHP can find it (in the PHP directory or in your system path).
Example 1 (test1.pl)
print "Hello from perl! "
Example 1 (test1.php)
<?php print "Hello from PHP! "; $perl = new Perl(); $perl->require("test1.pl"); print "Bye! "; ?> In this example perl outputs a string directly to the PHP output stream, but in some cases you will want to grab the output as a string and process it with your PHP code. This can be done using the PHP output buffering API:
Example 2 (test2.php)
<?php ob_start(); $perl = new Perl(); $perl->require("test1.pl"); $out = ob_get_contents(); ob_end_clean(); print "Perl: $out"; ?> As you can see, it works fine. Of course the same can be done with PHP's system call, but less efficiently. The system() function will start the interpreter each time it's called, whereas $perl>eval() uses the embedded interpreter in the same address space and doesn't need to create a new process. As was said earlier, the PHP perl extension can evaluate inline perl code. This method is more
useful if you want to execute a small piece of code. With the Perl::eval() method you don't need to create several small perl files, but can instead simply embed perl code into PHP.
Example 3 (test3.php)
<?php print "Hello from PHP! "; $perl = new Perl(); $perl->eval('print "Hello from perl! "'); print "Bye! "; ?> Perl::eval() accepts only one argument - the perl code to execute, in string format. PHP allows three different ways of writing string literals; single quoted, double quoted or heredoc. Note that PHP will act on the content of literal strings in the usual way before they are passed to perl (see http://www.php.net/manual/language.types.string.php for details). In the previous example we didn't receive any unexpected results from Perl::eval(), but we could do so. The perl interpreter can run the same code in different contexts, and the result can be very different in those different contexts. For example, a list returned in a scalar context would be received as the final element of that list. A Perl object uses the scalar context by default, but evaluating in an array or hash context[1] requires the use of special tricks. The method eval() should not be called directly on the perl interpreter object, but on the appropriate property (array or hash).
Example 4 (test4.php)
<?php $perl = new Perl(); var_dump($perl->eval('("a","b","c")')); // eval in scalar context var_dump($perl->array->eval('("a","b","c")')); // eval in array context var_dump($perl->hash->eval('("a","b","c")')); // eval in hash context /* output: string(1) "c" array(3) { [0]=> string(1) [1]=> string(1) [2]=> string(1) } array(2) { ["a"]=> string(1)
"b"
["c"]=> NULL } */ ?> This example evaluates the same data - a list - in different contexts, and as you can see, there are three different results from that data. Perl has several scopes of global variables (scalars $x, arrays @x, hashes %x and code &x). PHP's perl extension allows you to access global scalar, array and hash variables. To access scalar perl variables, just use the property with the same name. To access array and hash variables, use the same trick as for selecting the evaluation context.
Example 5 (test5.php)
<?php $perl = new Perl(); $perl->eval('$x = 1; @x = 1..4; %x var_dump($perl->x); var_dump($perl->array->x); var_dump($perl->hash->x); /* output: int(1) array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) } array(2) { [1]=> int(2) [3]=> int(4) } */ ?> As you see, here we have three variables with the same name but in different scopes, and of course all three have different values. The perl extension allows not only reading but also writing to perl variables. You can do this by assigning a new value to the corresponding property; however, you cannot modify part of a perl array or hash. (The modification will not take effect.) Evaluating perl variables is just one simple interaction between PHP and perl. More often we need = 1..4');
to call a single perl function. PHP's perl extension provides a simple and elegant way to do this. You just need to call the method with the corresponding name via the interpreter, and pass parameters to it:
Example 6 (test6.php)
<?php $perl = new Perl(); $perl->eval(' sub sum { my $x = shift(@_); foreach my $y (@_) { $x += $y; } return $x; } '); print $perl->eval("sum(1, 2, 3, 4, 5, 6, 7, 8, 9)")." "; print $perl->sum(1, 2, 3, 4, 5, 6, 7, 8, 9)." "; ?> The function can receive parameters and return a scalar or complex value. As with eval(), any function call can be made in one of three different contexts (scalar, array or hash), and the context can be specified in the same way. Perl uses packages to limit the name scope of variables and functions, and sometimes we need to call functions or access variables from these packages using qualified names. Such names doesn't confirm to PHP syntax, but they can be used with the special construct ->{}.
Example 7 (test7.php)
<?php $perl = new Perl(); $perl->eval('use Digest::MD5 qw(md5_hex);'); echo "PHP: "; var_dump(md5('Hello')); echo "perl: "; var_dump($perl->eval('md5_hex("Hello");')); var_dump($perl->md5_hex("Hello")); var_dump($perl->{"Digest::MD5::md5_hex"}("Hello")); ?> This example uses the external perl module md5, which is loaded during runtime. If you have a full perl installation, downloading and installing CPAN modules is as easy as downloading a tarball, extracting it to the perl top-level directory and typing: cd perl perl makefile.pl
make make test make install at the command prompt. On Windows systems you will need to replace make with nmake; however, this will only work if you have MSVS tools installed. If you don't have a full perl installation - i.e. you're running perl as a shared object - it is still possible to run perl modules once they have been built elsewhere. The minimal environment necessary for running them consists of the entire set of perl package management (*.pm) files from perllib, and the full perllibauto and perllibDigest directories. The PHP Perl extension cannot call internal perl functions (print, read, etc); you will need to use Perl::eval() in order to access these. For example, in order to include the minimal module environment outlined above you would need to call: $perl->eval("BEGIN {unshift( @INC, 'perlenv_dirpath'); }");
Example 8 (test8.php)
<?php $perl = new Perl();
$perl->eval(' package Point; sub new { my $this = shift; my $type = ref($this) || $this; my $self = {}; $self->{x} = 0; $self->{y} = 0; bless $self, $type; return $self; } sub Point { my $this = shift; my $type = ref($this) || $this; my $self = {}; $self->{x} = shift; $self->{y} = shift; bless $self, $type; return $self; } sub move { my $self = shift; $self->{x} += shift; $self->{y} += shift; } sub get { my $self = shift; if (wantarray) { return ($self->{x}, $self->{y}); } else { return $self->{x} . "x" . $self->{y}; } } '); // create perl object "Point" with constructor "new" $p1 = new Perl("Point"); var_dump($p1); $p1->x += 100; // modify property unset($p1->y); // undefine property var_dump($p1); // create perl object "Point" with constructor "Point" $p2 = new Perl("Point", "Point", 100, 200); var_dump($p2); $p2->move(200,200); // call method "move" var_dump($p2->get()); // call method "get" in scalar context var_dump($p2->array->get()); // call method "get" in array context echo $p2->x . "." . $p2->y . " "; // print perl object properties ?>
Error handling
The perl extension uses the PHP exception mechanism to report perl errors. A special exception class, PerlException, is used for this. The following example tries to evaluate invalid perl code, and as a result Perl::eval() throws a PerlException:
Example 9 (test9.php)
<?php $perl = new Perl(); try { var_dump($perl->eval('$a = $s{$d}.')); echo "ok "; } catch (PerlException $exception) { echo "Perl error: " . $exception->getMessage() . " "; } ?> Exceptions can be thrown by Perl::eval(), Perl::require(), or a call to a perl function, object method or constructor.
Summary
The PHP perl extension is a simple one-way binding from PHP to perl. It allows you to execute perl code from PHP, and has the ability to access perl variables, call perl functions, and instantiate perl objects. Note that the extension is still marked EXPERIMENTAL, so your ideas and suggestions can help to make it stable and usable. Please report any problems you find with the extension to http://bugs.php.net/. [1] - Perl defines the scalar and array (list) contexts. The hash context is the same as the array (list) context, but the result is converted to an associative PHP array (hash array).
8:02PM GMT Robert Buzink [unregistered] I installed PHP's perl extension on debian. Everything installed without any errors. I checked whether PERL is properly installed by doing 'apt-get install perl'. To be completely sure, I copied the perl.so file in the usr/lib/php5 directory. When I try to use the extension within a php script ($perl = new Perl();),I get a php error that the class cannot be found. Any ideas? Tuesday, April 22, 2008 LOAD PERL.SO 2:48PM GMT Ala'a Ibrahim [unregistered] add extention=perl.so to your php.ini file Monday, June 2, 2008 WHAT ABOUT USING ANOTHER PERL 2:01PM GMT Anonymous User [unregistered] $perl = New Perl() points to /usr/bin/perl or what default perl is. What if I want to use /usr/local/bin/perl? Do I have to decide this at pecl compile time? Saturday, October 25, 2008
PASSING VARIALBE FROM PHP TO PERL 10:57AM GMT strahinja I`m trying to pass variable from PHP file to perl script in code bellow. If someone has an example to post that would be great, btw. everything else works great. Sunday, January 25, 2009
BUG(( 10:18PM GMT ssg0 Do somebody know how to fix this bug? http://www.pecl.php.net/bugs/bug.php?id=14644 Monday, May 18, 2009 AVOIDING SENDING HEADER? 10:36PM GMT Anonymous User [unregistered] Hello, I notice that doing a $perl->require() or $perl->eval(), will send the header even if using output buffering. Once that happens, I can no longer set cookies, etc. Has anyone been able to use perl without it sending a header? Thanks!