Lately I've been experimenting with using PHP and perl together, and I've started using PHP::Interpreter. It is a very cool module that allows both embedding perl code in PHP and vica verca. It has an interesting history being sponsored by Portugal Telecom (kudos to them).

I initially found the module difficult to install (and others with me, e.g. here, and here). PHP::Interpreter obviously depends on having both PHP and the PHP sources installed, and some of the difficulty lays in how to locate the local PHP binaries (if at all present).

PHP is renowned for its' low barrier of entry, so I figured a PHP interface to perl should install as easily as possible. This motivates the attempt of making PHP::Interpreter easier to install.

The current Makefile.PL has a number of unfortunate properties:

The module PHP uses another approach to determine the underlying PHP install: It's Makefile.PL calls `php-config` and simply dies if it's not in path. I like this die hard approach, since it makes it very clear what is missing as soon as a (possible) problem is detected.

Please comment the below attempt to improve on Makefile.PL. I'll probably contact the maintainer later on.

use strict; use warnings; use ExtUtils::MakeMaker; use Config; use File::Spec::Functions qw(catdir); # Check if File::Find is present eval { use File::Find; }; my $filefind = (!$@) ? 1 : 0; # These header files must be present for PHP::Interpreter to compile my %headers = (); $headers{$_}++ for qw ( php_config.h php.h php_ini.h php_main.h zend.h zend_API.h zend_compile.h zend_ini.h SAPI.h TSRM.h ); # Return true if files in headers hash are found, otherwise die sub check_headers { my $inc = shift; die "Need an argument" if !$inc; print "Checking header files...\n"; # Replace -I at beginning of string and chop of newline character my @incdirs = map { s/^-I//g; chomp; $_ } split(/ /, $inc); for (@incdirs) { die "No such directory: '$_'" if (!-d); print "using incdir '$_'\n"; } # Make sure header files are present my $finder = sub { return if (!-f $_ or !exists($headers{$_})); print "Found $File::Find::name\n"; delete $headers{$_}; }; # Try to find all files in headers - delete hash entries when found. # Any remaining hash key indicates a necessary file is missing. find(\&$finder, @incdirs); die "Missing header files: " . join(q{, }, keys %headers) if (keys % +headers); return 1; } # Execute 'php-config' for each variable. Dies if executable is not # in path. my %conf = map { my $a = `php-config --$_`; die "Error: php-config --$_ failed\n" unless $a; chomp $a; $_ => $a; } qw(includes prefix version ldflags); # Get php version print "using php version $conf{version}\n"; $conf{version} =~ s/^(\d+).*/$1/; # Need major version only die "Unsupported PHP version" if ($conf{version} != 5); # Get prefix. Use script argument as prefix, otherwise use value from # 'php-config' my $prefix = shift @ARGV || ($conf{prefix}); die "Failed to find php root" if (!defined($prefix) or !-d $prefix); print "using prefix $prefix\n"; # Get include directories my $includes = "-I" . catdir($prefix, 'include') . " " . $conf{include +s}; print "using includes $includes\n"; # Get libraries my @lddlflags = ($Config{lddlflags}, $conf{ldflags}); push @lddlflags, "-L" . catdir $prefix, "lib"; my $php_embedlib_path = "-L" . catdir $prefix, "lib"; push @lddlflags, $php_embedlib_path; print "using lddlflags " . join(q{ }, @lddlflags) . "\n"; # Libs = lddlflags + php-version my @libs = ("$php_embedlib_path"); push @libs, "-lphp$conf{version}"; print "using libs " . join(q{ }, @libs) . "\n"; my @ofiles = ('PHP.o', 'phpinterp.o', 'phpfuncs.o'); # Check that header files are present if File::Find is installed ($filefind) ? check_headers($includes) : print "Module File::Find not installed. Header files check skipped +.\n"; WriteMakefile( CCFLAGS => '-g', OBJECT => join(' ', @ofiles), NAME => 'PHP::Interpreter', LIBS => join(' ', @libs), LDDLFLAGS => join(' ', @lddlflags), INC => $includes, VERSION_FROM => 'lib/PHP/Interpreter.pm', PREREQ_PM => { # Just required for testing. 'Test::More' => 0, 'IO::File' => 0 }, ); __END__ =pod =head1 NAME Makefile.PL - Makefile for PHP::Interpreter =head1 SYNOPSIS perl Makefile.PL [prefix] =head1 OPTIONS prefix - directory root for PHP install, e.g. /usr/local or C:\\Program Files\\PHP =head1 DESCRIPTION This creates a makefile for PHP::Interpreter. PHP::Interpreter depends on having both PHP and PHP sources installed. This script uses the executable I<php-config> to determine how PHP is configured. This script will die unless I<php-config> is installed. PHP::Interpreter works with PHP5 only. This script will perform header files check if module I<File::Find> is installed =head1 SEE ALSO php php-config =cut
Fri Nov 7 10:11:48 CET 2008: Committed changes to the PHP::Sandwich repository.

Tue Nov 11 21:51:28 CET 2008: See also Re: use PHP::Interpreter throws undefined symbol: zend_ce_traversable for PHP installation notes.

--
No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]

Replies are listed 'Best First'.
Re: Making PHP::Interpreter easier to install
by almut (Canon) on May 07, 2008 at 12:54 UTC

    I absolutely agree with your position that it's better to die early on if some vital requirement cannot be met — rather than fail later with a bunch of compile errors which are likely harder to make sense of for the uninitiated...

    Your Makefile.PL looks fine to me.  IOW, this is mainly just to say thanks to you for doing the hard work to make things easier for others :)

Re: Making PHP::Interpreter easier to install
by olus (Curate) on May 07, 2008 at 14:21 UTC

    Good work ++

    It makes me proud that you mention PT's sponsorship for the development. As part of the module's history, its announcement can be found here. You'll find there what was the motivation for its development.

Re: Making PHP::Interpreter easier to install
by dk (Chaplain) on May 11, 2008 at 21:22 UTC
    May I ask why haven't you used PHP, that in my selfishly subjective opinion is a more straightforward and powerful module?
      PHP allows embedded php code in perl code. PHP::Interpreter allows allows to embed php code in perl code and embedded perl code in php code. I'm particularly attracted by the latter, e.g. exposing a large perl-based library through a php front end.
      --
      No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
        I've spent the last four days trying to install PHP::Interpreter and now I just found this comment that leads me to believe I might not need it at all.

        I don't know if you have experience with Bricolage (I've seen your name in their mail archives), but does your comment mean that if we use PHP code in our Bric templates, that we do NOT need PHP::Interpreter as long as we have PHP installed?

        Your comment seems to indicate that PHP::Interpreter is ONLY needed if you want to embed Perl code within PHP code.

        Thanks,
        Mike

Re: Making PHP::Interpreter easier to install
by Theory (Beadle) on Oct 29, 2008 at 18:56 UTC

    Hi andreas1234567,

    Do you have a perl.org/Bitcard account? If so, I'd love to give you a commit bit for PHP::Interpreter. It could definitely use a bit of love, and your improvements would be most welcome. Just send your perl.org username to me at david AT kineticode.com.

    Thanks!

    —Theory