Getting Perl, MySQL and Apache to all work together on Mac OS/X
So, I've been running this blog for a few years now; over time I've been adding bits and pieces
of dynamic functionality - not the least of which is a comment section. A little while ago, a reader pointed out
that the comment section doesn't allow for formatted source code, which is something I wanted to
fix. Before I did so, though, I wanted to set up a local test bed on my computer that I could
verify my fixes against. The comments section (and other dynamic functionality) of my miniature
content-management system is built on Perl and MySql,
so to create a local instance, all I ought to need is Apache, Perl & MySql.
As it turns out, Mac OS/X comes with Apache, MySql, and Perl all pre-installed... so it should be a simple matter
to create a "dev" environment copy of my blog and get them all working together, right? Well, as it turned out, not quite. It was easy enough
to use mysqldump
to get a copy of my simple database schema and replicate that on
my local MySQL instance. I had Perl also, but didn't have DBI or the DBD::MySQL module that Perl
requires to access a MySQL database. Both were easy
enough to download, install and test; I was able to verify that I could run a Perl script
and retrieve and insert data into my local MySQL instance. My next step was to grab all of my
CGI scripts and copy them into /Library/WebServer/CGI-Executabes
. When I tried to
run it, though, I got a blank page and this error in /var/log/apache2/error_log
:
[Fri Jul 24 10:49:11.776642 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: install_driver(mysql) failed: Can't locate DBD/mysql.pm in @INC
(you may need to install the DBD::mysql module)
(@INC contains: /Library/Perl/5.18/darwin-thread-multi-2level /Library/Perl/5.18 /Network/Library/Perl/5.18/darwin-thread-multi-2level /Network/Library/Perl/5.18
/Library/Perl/Updates/5.18.2 /System/Library/Perl/5.18/darwin-thread-multi-2level /System/Library/Perl/5.18 /System/Library/Perl/Extras/5.18/darwin-thread-multi-2level
/System/Library/Perl/Extras/5.18 .) at (eval 5) line 3.
[Fri Jul 24 10:49:11.776802 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: Perhaps the DBD::mysql perl module hasn't been fully installed,
[Fri Jul 24 10:49:11.783131 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: or perhaps the capitalisation of 'mysql' isn't right.
[Fri Jul 24 10:49:11.783192 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: Available drivers: DBM, ExampleP, File, GetInfo, Gofer, Proxy, SQLite, Sponge.
[Fri Jul 24 10:49:11.783227 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: at /Library/WebServer/CGI-Executables/showarticle.cgi line 76.
However, MySQL DBD was installed and worked just fine:
use DBI();
my $dbh = DBI->connect("DBI:mysql:blog", "user", "password");
my $sth = $dbh->prepare("SELECT count(*) FROM comment");
my $count = $sth->execute();
print $count . "\n";
$sth->finish();
$dbh->disconnect();
Apparently, the Perl I use has a different search directory than the one that the web server uses:
$ perl -e 'print "@INC" . "\n"'
/opt/local/lib/perl5/site_perl/5.16.3/darwin-thread-multi-2level /opt/local/lib/perl5/site_perl/5.16.3
/opt/local/lib/perl5/vendor_perl/5.16.3/darwin-thread-multi-2level /opt/local/lib/perl5/vendor_perl/5.16.3
/opt/local/lib/perl5/5.16.3/darwin-thread-multi-2level /opt/local/lib/perl5/5.16.3 /opt/local/lib/perl5/site_perl /opt/local/lib/perl5/vendor_perl .
My first thought, because I'm lazy, is to just take my working DBD::MySQL
installation
and force it into one of the directories listed in the @INC
path that Apache is
reporting. I can download and build the DBD::MySQL distribution (that's how I got it installed
in the first place); so you'd think I could just say, "Install it here, instead of there." You
would think... however, after an hour of examining the install script, I couldn't find a way to
force it to install itself into, say /Library/Perl/5.18/darwin-thread-multi-2level
.
Just so you know, the really brute force approach of copying the files themselves doesn't work (although you had probably already guessed that...)
So, I figure one of two things is happening — either my login is overwriting some default
Perl include search path, or, inexplicably, I have two Perl instances installed and my ordinary
login was loading one Perl instance and Apache was loading the other. So... how to figure out
where Apache was finding its Perl search path? For one thing, mod_perl isn't installed; I'm
running perl as scripts. I considered that a perfectly reasonable tradeoff since I'm just
testing. Given that, I should be able to assume the identity of the web server user and find his Perl
instance by which perl
. I can become root and verify that his Perl is the
same as mine. httpd
doesn't run as root, though, it runs as:
# ps -fe | grep http
0 77 1 0 8:42AM ?? 0:00.58 /usr/sbin/httpd -D FOREGROUND
70 315 77 0 8:42AM ?? 0:00.02 /usr/sbin/httpd -D FOREGROUND
70 3277 77 0 11:09AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND
70 3278 77 0 11:10AM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND
70 3279 77 0 11:10AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND
70 3280 77 0 11:10AM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND
70 3281 77 0 11:10AM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND
70 3282 77 0 11:10AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND
70 3283 77 0 11:10AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND
# grep ":70:" /etc/passwd
_www:*:70:70:World Wide Web Server:/Library/WebServer:/usr/bin/false
Who, of course, you can't log in as: shell is /usr/bin/false
. So what is his search path, and
how do I change it?
I can "cheat" by running this CGI script:
#!/usr/bin/perl
print "Content-type: text/html; charset=iso-8859-1\n\n";
print "<html>";
print "<body>";
print "$ENV{'PATH'}";
print "</body>";
print "</html>";
This informs me that _www has the simplest path: /usr/bin:/bin:/usr/sbin:/sbin
.
And, sure enough, there's another perl instance install under /usr/bin
that my
ordinary user never sees, because /opt/local/bin
is further up in his search path
than /usr/bin
.
At this point, I can do one of two things - I can reinstall DBI::Mysql under /usr/bin/perl (i.e. 5.18) or change
the default path to find /opt/local/bin/perl (5.16). Changing the default path is a little
disconcerting; I don't know what else might rely on this path configuration. However, by just
temporarily changing my current path to put /usr/bin
first and reinstalling DBI
& DBD::MySQL:
$ export PATH=/usr/bin:$PATH
$ perl Makefile.PL
$ make
$ sudo make install
I can get DBD::mysql to load... almost. Now it fails with:
[Wed Aug 19 13:01:02.582506 2015] [cgi:error] [pid 3281] [client ::1:52522] AH01215: install_driver(mysql) failed: Can't load
'/Library/Perl/5.18/darwin-thread-multi-2level/auto/DBD/mysql/mysql.bundle' for
module DBD::mysql: dlopen(/Library/Perl/5.18/darwin-thread-multi-2level/auto/DBD/mysql/mysql.bundle, 1): Library not loaded: libmysqlclient.18.dylib
Because the mysqlclient libraries are not in _www
's `DYLD_LIBRARY_PATH
.
The simplest fix for this is to create a symlink to it:
$ sudo ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib/libmysqlclient.18.dylib
And voila! I have a working copy of my blog's CMS with which I can test out new functionality, like code-formatted comments — which, if you look below, you can now leave at the bottom of this post!
After doing a bit of research, I believe that the reason I have two Perl installations is because I used MacPorts to install some third-party software that itself was dependent of Perl. It appears that I'm not the only person to have been surprised by mismatched Perl installations.
Add a comment:
Also at some point my MySQL scripts errored out similar to yours. Looking at the DBI & DBD module library I discovered the .pm file was NOT EVEN THERE! HUH? After a few attempts at trying to sort this out over a few OS upgrades I figured that Oracle has somehow stopped providing that support to Apple. Since then (a few years now) I've been using SQLite at home and on my host. And every day I'm pleasantly surprised with it.
--
www.softouch.on.ca