LL      IIIII NN   NN KK  KK EEEEEEE RRRRRR  RRRRRR   OOOOO  RRRRRR 
LL       III  NNN  NN KK KK  EE      RR   RR RR   RR OO   OO RR   RR
LL       III  NN N NN KKKK   EEEEE   RRRRRR  RRRRRR  OO   OO RRRRRR 
LL       III  NN  NNN KK KK  EE      RR  RR  RR  RR  OO   OO RR  RR 
LLLLLLL IIIII NN   NN KK  KK EEEEEEE RR   RR RR   RR  OOOOO  RR   RR
                                                           ramblings
____________________________________________________________________

One thing that seems to happen a lot on FreeBSD with php is that it tends to segfault when some wrong combination of modules is installed, or you have a module from a previous version of php installed that doesn’t play nice with your newly upgraded version…

You’ll usually notice things like this in your daily security mails:

+pid 44994 (httpd), uid 80: exited on signal 11
+pid 44992 (httpd), uid 80: exited on signal 11
+pid 50351 (httpd), uid 80: exited on signal 11
+pid 51432 (httpd), uid 80: exited on signal 11
+pid 89423 (httpd), uid 80: exited on signal 11
... etc...

In the case of mismatched modules with the current php version I once came up with this super overkill script that completely wipes anything php from the system and reinstall’s it. That works fine in most cases, but won’t save you if you select two modules that don’t play nice together.

So I wrote this little perl script that will detect a malfunctioning module by enabling modules one by one in extensions.ini and testing them. You could just comment them all out and uncomment one by one, but that is a pain, especially if you have to do it on multiple servers.

Sample output:

# php_module_detective.pl

Note: A backup of your extensions.ini was created as /usr/local/etc/php/extensions.ini.bak ...

Testing extension=bcmath.so ... 
Testing extension=bz2.so ... 
Testing extension=calendar.so ... 
Testing extension=ctype.so ... 
Testing extension=curl.so ... 
Testing extension=dba.so ... 
Testing extension=pcre.so ... 
Testing extension=simplexml.so ... 
Testing extension=spl.so ... 
Testing extension=dom.so ... 
Testing extension=exif.so ... 
Testing extension=filter.so ... 
Testing extension=gd.so ... 
Testing extension=gettext.so ... 
Testing extension=gmp.so ... 
Testing extension=hash.so ... 
Testing extension=iconv.so ... 
Testing extension=json.so ... 
Testing extension=mbstring.so ... 
Testing extension=mcrypt.so ... 
Testing extension=mhash.so ... 
Segmentation fault (core dumped)


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
extension=mhash.so is broken.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Backup restored.

Died at /usr/local/bin/php_module_detective.pl line 69.

Here’s the script:

#!/usr/local/bin/perl

use strict;
use File::Copy;

# Settings --------------------------------------------------------------------

# Where to find extensions.ini ...
my $module_ini_file = '/usr/local/etc/php/extensions.ini';

# Globals ---------------------------------------------------------------------

# Holds a list of all modules found in the ini file.
my @modules;

# Functions -------------------------------------------------------------------

# Creates a backup of the ini file.
sub make_backup()
{
  copy($module_ini_file,"$module_ini_file.bak") or 
    die ("Could not create a backup.");
  print "Note: A backup of your extensions.ini was created as $module_ini_file.bak ...\n\n"
}

# Restores backup.
sub restore_backup()
{
  copy("$module_ini_file.bak","$module_ini_file") or
    die ("Failed to restore backup.");
  print "Backup restored.\n\n"
}


# Reads the ini file and fills the modules array.
sub read_ini()
{
  open(FH,$module_ini_file) or 
    die "Could not open $module_ini_file" ;
  while ()
  {
    chomp($_);
    push(@modules,$_);
  }
  close(FH);
}

# Tries the modules one by one
sub test_modules()
{
  my $module_list = "";
  my @args = ("php -r '\$a=\$a;'"); 
  foreach(@modules)
  {
    my $current_module = $_;
    print "Testing $current_module ... \n";
    $module_list .= "$current_module\n";
    open(FILEOUT,">$module_ini_file") or
      die "Could not open $module_ini_file for writing.";
    print FILEOUT "$module_list\n";
    close(FILEOUT);    
    my $retval = system(@args);
    if ($retval != 0)
    {
      print "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
      print "$current_module is broken.\n";
      print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n";
      restore_backup();
      die('');
    }   
  }
}

# Functions -------------------------------------------------------------------

make_backup();
read_ini();
test_modules();
restore_backup();


 
____________________________________________________________________