Building a Mac OS X Server 10.6: Step 1, Adventures With PHP [Updated 1/24/10 and 1/30/10]

| | Comments (5)

OK, folks, as you may recall, I got a new server capable of running Mac OS X Server 10.6. Problem is, it doesn’t know jack about my custom PHP or Perl installations on my 10.5 server, so I have to figure out what to do to setup these things again. Let’s go!

What did I do before?

First, what did I have installed last time? Well, let’s start with the applications I use. First, there’s Gallery. Then there’s Moveable Type, which is what you’re using right now to read this ‘blog. And I have a weather collection app that runs in PHP. Each of these has its own requirements:

Gallery requires a bit of stuff:

  • a database—check! That’s MySQL.
  • an image processing library—check? Previously, I used ImageMagick, but I note that Gallery 2 now supports GD, and, as we’ll see later, I’m using GD for other things. So perhaps there’s some (ahem) synergy to be had here. Keep GD at the top of the list, ImageMagick if required.
  • mod_rewrite—should be a checkbox in Server Admin, so let’s hope it is.
  • ffmpeg
  • dcraw
  • jhead
  • infozip—I’ll skip this one.
  • zip—probably check?

MT requires no extra PHP goodies, but has a pretty good list of Perl modules that are optional in addition to a few that are required. From the requirements page, we get this list:

Required Perl modules

  • CGI
  • Image::Size
  • File::Spec (Version 0.8 or higher)
  • CGI::Cookie One of the following Database Perl Modules is required:

  • DBD::mysql (version 2.9005 or higher) - When using MySQL database

(This is what I’ll use, so I ignore the others.)

WARNING: DBD::mysql 2.9004 is not recommended nor supported by Six Apart due to the error: “Statement has no result columns to bind”. Later versions of DBD::mysql are recommended.

Optional Perl Modules

The following Perl modules support option functions. Use these modules for even greater functionality with Movable Type.

Archive::Tar Archive::Zip Crypt::DSA Crypt::SSLeay Digest::MD5 Digest::SHA1 File::Temp GD HTML::Entities HTML::Parser Image::Magick IO::Compress::Gzip IO::Socket::SSL - New in MT5 IO::Uncompress::Gunzip IPC::Run List::Util LWP::UserAgent Mail::Sendmail MIME::Base64 Net::LDAP - New in MT5 Safe Scalar::Util SOAP::Lite (Version 5.0 or higher) Storable Text::Balanced (Necessary for searches within a blog) XML::Atom XML::Parser XML::SAX

And my own weather application requires only JpGraph, but it needs

  • GD
  • FreeType 2.x and
  • the fonts for FreeType to use.

The big, burning question in my mind is, What has Apple enabled in the default PHP installation? Used to be that GD was off by default, as was FreeType. Let’s issue a php -i to find out:

$ php -i

Holy crap. In the output on this 10.6.2 box, we find

gd

GD Support => enabled
GD Version => bundled (2.0.34 compatible)
GIF Read Support => enabled
GIF Create Support => enabled
JPEG Support => enabled
libJPEG Version => 6b 
PNG Support => enabled
libPNG Version => 1.2.37

Amazing! This was a long-standing gripe I had, and the result is that I don’t need to do anything fancy… just yet. But is everything else there?

In any case, first step: grab Xcode and install it. Then don’t forget to turn on CGI execution and the php5_module in Server Admin.

Check!

Now let’s do something simple and make JpGraph work. (A few hours of frustration pass… and I’m not kidding. It’s so simple, and yet sometimes, so hard.) It’s really rather simple.

JpGraph

First, grab the tarball for JpGraph. Extract it. In my other installation, I had decided (for some odd reason) to put the scripts in the root directory of the weather site, but upon reading the installation notes, I decided to locate them a little more sensibly. So I moved/renamed src to /Library/WebServer/CGI-Executables/jpgraph like this:

$ cd jpgraph-3.0.7
$ mv src /Library/WebServer/CGI-Executables/jpgraph

and changed the ownership and permissions so that it can be used by the webserver user (which is in the group _www):

$ cd /Library/WebServer/CGI-Executables/
$ sudo chown -R admin:_www jpgraph
$ sudo chmod -R 755 jpgraph
$ xattr -dr com.apple.quarantine jpgraph

Then I moved the Examples folder to the root Documents folder (because I have no sites up at this point):

$ cd jpgraph
$ mv Examples ../Documents/

And then had to make a symbolic link in the Examples folder so that the examples can find the jpgraph directory.

$ cd ../Documents/Examples
$ ln -s  ../../CGI-Executables/jpgraph/ jpgraph

I then pointed my webbrowser to http://localhost/Examples/testsuit.php and, Yes! I have graphs! There are some gripes about PHP with no support for TTF. And this is where things get interesting because what we have to do now is rebuild PHP from scratch, ensuring that we get TTF—as well as all of the other things that Apple includes, plus the stuff we need for other applications—built into it.

That’s a bit tricky, and we have to break down the configure line that Apple used in order to see what libraries we have to make.

PHP, Just Like Apple

Let’s try to build PHP just the way Apple builds it, with their configurations ‘n’ all. If you look at the output of php -i, you can see what Apple used to build the PHP installation distributed with Mac OS X Server 10.6.

Configure Command =>  '/var/tmp/apache_mod_php/apache_mod_php-53~1/php/configure'  '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--disable-dependency-tracking' '--sysconfdir=/private/etc' '--with-apxs2=/usr/sbin/apxs' '--enable-cli' '--with-config-file-path=/etc' '--with-libxml-dir=/usr' '--with-openssl=/usr' '--with-kerberos=/usr' '--with-zlib=/usr' '--enable-bcmath' '--with-bz2=/usr' '--enable-calendar' '--with-curl=/usr' '--enable-exif' '--enable-ftp' '--with-gd' '--with-jpeg-dir=/BinaryCache/apache_mod_php/apache_mod_php-53~1/Root/usr/local' '--with-png-dir=/BinaryCache/apache_mod_php/apache_mod_php-53~1/Root/usr/local' '--enable-gd-native-ttf' '--with-ldap=/usr' '--with-ldap-sasl=/usr' '--enable-mbstring' '--enable-mbregex' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/var/mysql/mysql.sock' '--with-iodbc=/usr' '--enable-shmop' '--with-snmp=/usr' '--enable-soap' '--enable-sockets' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-xmlrpc' '--with-iconv-dir=/usr' '--with-xsl=/usr' '--with-pcre-regex=/usr'

Before I forget—we won’t be doing the standard make/make install without first backing up the php binaries. I had problems making sure that the architectures of my Apache server and the PHP binaries matched, and if they don’t, Apache won’t load them. And then Apache won’t load and your webserver is borked pretty good until you get PHP working perfectly. With that in mind, onward!

The first thing to do is, of course, grab the PHP tarball from its source and unsmoosh it. I tend to keep all of this stuff in a new folder, Installed, in my home directory, by the way.

Ideally, we’d just do the configure command just like Apple. Given that it’s easy to download Xcode and PHP and try it all out on the laptop as I’m writing this, I decided to just dive right in and try the configure command as Apple did it and see what it gripes about. (Copy and paste the original Apple configure command to your command line, then edit out the /var/tmp/Apache… bit so that it’s just ./configure.)

The first thing it gripes about is not being able to find the PCRE headers file.

checking for PCRE headers location... configure: error: Could not find pcre.h in /usr

That’s because this option

'--with-pcre-regex=/usr'

is telling Configure to look for pcre.h where it just won’t find it. I Googled it and discovered that there are all kinds of fixes out there that involve copying a file that doesn’t seem to exist into somewhere else so that it can be found. Hmm. That doesn’t sound like the right approach. And Apple has a patch that doesn’t seem to work, either because it’s targeted at an older version of PHP (5.3.0) or because they place a libpcre somewhere that we don’t have it in a clean installation.

After a while of digging, I realized that some of the advice out there on the web is merely to copy the header file from php-5.3.1/ext/pcre to /usr/somewhere. Wha…? Why copy this file if it seems like the normal PHP installation has PCRE built in as an extension, i.e., no library needed, it’s self-contained in the installation? Then all we have to do is something like we do with GD, namely just say “Yes! I want PCRE!” and don’t worry about where it comes from.

(By the way, downloading and installing libpcre also works. But that’s overkill at this point, and it may introduce problems with PHP because the current PCRE is 8.0 and the one installed with PHP is 7.8, I think.)

So if you change the flag above to this:

'--with-pcre-regex'

the problem goes away and configure reports

checking which regex library to use... php

Whew. Now, on to other problems, because there are some, specifically:

configure: error: libjpeg.(a|so) not found.

These flags cause that particular problem:

'--with-jpeg-dir=/BinaryCache/apache_mod_php/apache_mod_php-53~1/Root/usr/local'
'--with-png-dir=/BinaryCache/apache_mod_php/apache_mod_php-53~1/Root/usr/local'

There’s a big problem: we don’t have the mythical /BinaryCache/apache_mod_php... directory, so we have to make our own jpeg lib and png lib. Ready for that? Thought so! Let’s go!

libjpeg

First, grab the libjpeg tarball from its source. Then extract it and throw it into your Installed directory or wherever you’re keeping all this stuff, and it’s important to keep it because as often as Apple wrecks custom PHP installations, you are going to have to do it all again someday.

Things have gotten a bit easier since I did this last time, about five years ago, and all you have to do is the standard configure/make/make install with one option, like this:

$ ./configure --enable-shared

8< snip!

$ make

8< snip!

$ sudo make install

All we have to do now is keep in mind that libjpeg is now located in /usr/local/lib according to make and can edit the flag appropriately.

'--with-jpeg-dir=/usr/local'

libpng

Again, grab the source for libpng from its source and unpack it. Let’s see if anything’s changed since I last did this with v1.2.8.

$ ./configure
-bash: ./configure: /bin/sh^M: bad interpreter: No such file or directory

Harumph. Well, according to the INSTALL file, we might want to copy the makefile that lives in scripts and use that. Problem is, after I tried it, I noticed that libpng wants to find libz at ../zlib, where it certainly isn’t. And according to my notes, that’s a problem I ran into before. Here’s how to fix all that:

$ cp scripts/makefile.darwin makefile
$ emacs makefile

(or pico or nano or vi or whatever…)

Change this

# Where the zlib library and include files are located                                                                                                            
#ZLIBLIB=/usr/local/lib                                                                                                                                           
#ZLIBINC=/usr/local/include                                                                                                                                       
ZLIBLIB=../zlib
ZLIBINC=../zlib

to this

# Where the zlib library and include files are located                                                                                                            
ZLIBLIB=/usr/lib
ZLIBINC=/usr/include
# ZLIBLIB=../zlib                                                                                                                                            
# ZLIBINC=../zlib

and save it. You have to do this because Apple has started to include (or has always included?) the zlib library, and it’s not in the /usr/local directory but is with the rest of the Apple-provided stuff in /usr. Then

$ make
$ sudo make install
$ ./pngtest pngtest.png

which should produce a bunch of lines with r’s and w’s. If it does, then, Yay! Continue onward.

The libraries end up in /usr/local/lib, just like libjpeg, so its options look similar:

'--with-png-dir=/usr/local'

And now let’s hope for the best.

Back to PHP

If you try again, things should work just fine with the exception of this error:

Notice: Following unknown configure options were used:

--disable-dependency-tracking

Check './configure --help' for available options

We can ignore that one, unless you’re particularly retentive and decide to eliminate it. Otherwise, the complete configure command looks like this:

./configure  '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--disable-dependency-tracking' '--sysconfdir=/private/etc' '--with-apxs2=/usr/sbin/apxs' '--enable-cli' '--with-config-file-path=/etc' '--with-libxml-dir=/usr' '--with-openssl=/usr' '--with-kerberos=/usr' '--with-zlib=/usr' '--enable-bcmath' '--with-bz2=/usr' '--enable-calendar' '--with-curl=/usr' '--enable-exif' '--enable-ftp' '--with-gd' '--with-jpeg-dir=/usr/local' '--with-png-dir=/usr/local' '--enable-gd-native-ttf' '--with-ldap=/usr' '--with-ldap-sasl=/usr' '--enable-mbstring' '--enable-mbregex' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/var/mysql/mysql.sock' '--with-iodbc=/usr' '--enable-shmop' '--with-snmp=/usr' '--enable-soap' '--enable-sockets' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-xmlrpc' '--with-iconv-dir=/usr' '--with-xsl=/usr' '--with-pcre-regex'

If configure runs OK, then try make. (If you’ve been trying make at various points along the way, don’t forget to make clean.)

It’ll fail. Don’t ask me how I know, I just know. My sources tell me you’ll see:

Undefined symbols:
  "_libiconv", referenced from:
      __php_iconv_strlen in iconv.o
      _php_iconv_string in iconv.o
      _php_iconv_string in iconv.o
      __php_iconv_strpos in iconv.o
      __php_iconv_appendl in iconv.o
      __php_iconv_appendl in iconv.o
      _zif_iconv_substr in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _php_iconv_stream_filter_append_bucket in iconv.o
      _php_iconv_stream_filter_append_bucket in iconv.o
ld: symbol(s) not found

Apparently, the only way to fix the problem that exists in PHP5.3.1 is to edit the file ext/iconv/iconv.c from this (which is down on line 185 or so—don’t mix it up with the first one in the file!)

#ifdef HAVE_LIBICONV
#define iconv libiconv
#endif

to this:

#ifdef HAVE_LIBICONV
#define iconv iconv
#endif

Now try make and see what happens. I think you’ll be pleasantly surprised.

The real litmus test will be to install it. Let’s first backup the Apple PHP and then install ours.

$ php -i > ~/php-config-2010.01.17
$ sudo cp /usr/libexec/apache2/libphp5.so /usr/libexec/apache2/libphp5.so.apple
$ sudo cp /usr/bin/php /usr/bin/php.apple

(When I did the php -i above, it griped with

PHP Warning:  Unknown: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/New_York' for 'EST/-5.0/no DST' instead in Unknown on line 0

so I edited /etc/php.ini to read

[Date]
; Defines the default timezone used by the date functions                                                                                                         
; http://php.net/date.timezone                                                                                                                                    
date.timezone = America/New_York

All of the choices for date.timezone are at the URL shown in the .ini file.)

Now to Add FreeType…

…tomorrow. That’s enough for one day.

Updated! Here’s how to add FreeType (and fonts)

It turns out that adding FreeType support is very easy. First, make sure you install X11 support when you install Mac OS X Server. Then all we have to do is change our configure command with one additional switch. It ends up looking like this:

./configure  '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--disable-dependency-tracking' '--sysconfdir=/private/etc' '--with-apxs2=/usr/sbin/apxs' '--enable-cli' '--with-config-file-path=/etc' '--with-libxml-dir=/usr' '--with-openssl=/usr' '--with-kerberos=/usr' '--with-zlib=/usr' '--enable-bcmath' '--with-bz2=/usr' '--enable-calendar' '--with-curl=/usr' '--enable-exif' '--enable-ftp' '--with-gd' '--with-jpeg-dir=/usr/local' '--with-png-dir=/usr/local' '--enable-gd-native-ttf' '--with-ldap=/usr' '--with-ldap-sasl=/usr' '--enable-mbstring' '--enable-mbregex' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/var/mysql/mysql.sock' '--with-iodbc=/usr' '--enable-shmop' '--with-snmp=/usr' '--enable-soap' '--enable-sockets' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-xmlrpc' '--with-iconv-dir=/usr' '--with-xsl=/usr' '--with-pcre-regex' '--with-freetype-dir=/usr/X11R6'

Sure enough, after a make clean/make/make install (and restarting Apache), you get TTF support enough for the JpGraph to acknowledge that it is installed, but it will gripe that Arial and Verdana aren’t installed. Which they aren’t. So it’s right.

So how do we go about installing these fonts? Simple! Since we’re using a Windows machine, all we have to do is copy them from Microsoft… oh… wait… that’s a problem, now, isn’t it?

Well, now… all we have to do (for real) is get the core web fonts, which include Arial and Verdana, from Microsoft or somewhere else and put them where Jp Graph can find them. There are two ways that I know of to do this.

  1. Go to the Internet Archive and download each individual file as Microsoft used to distribute them, circa 2002. The page you’re looking for is here. Apparently, that’s how I found them about eight years ago, because I don’t have any knowledge of how to do:

  2. Download the fonts from the Corefonts project. This technique involves downloading a “cab” file (which Microsoft seems OK with) and extracting the contents using some utilities. You might want to just copy the .ttf fonts from some conveniently-available PC.

JpGraph would like to see the fonts in /usr/share/fonts, so all we need to do is create that directory and stick the font files there. I have mine in a folder in my Installed directory, so here’s what I did.

$ sudo mkdir /usr/share/fonts         
$ sudo mkdir /usr/share/fonts/truetype
$ sudo cp * /usr/share/fonts/truetype/
$ ls /usr/share/fonts/truetype/

After that, if all goes well, you’ll be able to load the JpGraph examples and see all the fonts working just fine.

Really, that’s all there is to it…

Updated! Compiling PHP with libpng 1.4.x

Art Fisher of In Color commented below that he had problems with this error during the make when he tried my instructions:

Undefined symbols:
  "_png_check_sig", referenced from:
      _php_gd_gdImageCreateFromPngCtx in gd_png.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [libs/libphp5.bundle] Error 1

I had run into that problem, too, and filed a bug against PHP 5.3.1. I guess the guys at PHP.net consider a bug that they found and fixed in a not-so-public version of PHP (a nightly build of about a month ago) “bogus,” so they marked my bug as “bogus.” I’d have preferred “closed,” but semantics aside, the problem above is caused by the removal of the long-deprecated _png_check_sig from libpng as described in the release notes, here.

Art and I worked together to figure out what was going on and discovered that if you edit line 148 of ext/gd/libgd/gd_png.c from

       if (!png_check_sig (sig, 8)) { /* bad signature */
                return NULL;
        }

to

       if (!png_sig_cmp (sig, 0, 8) == 0) { /* bad signature */
                return NULL;
        }

PHP will compile fine.

He then found some other problems, one of which you’re most likely encountering and for which I’ll share the solution below.

Updated! PHP not installing a CLI binary

After you’ve done all of that stuff above, you’ve probably fired up your web browser and run a simple phpinfo() script and discovered that you did indeed succeed.

To show off your command-line prowess to you spouse (who will be suitably impressed when you say, “Look, Dear! I successfully compiled and installed PHP version 5.3.1!”), you do a php -i which shows that you didn’t succeed at all! Instead, php -i reports that the old version, compiled by Apple, remains! I looked, and sure enough, the old version of php remained untouched, but there was a strange, and very functional, php.dSYM file sitting right next to it in /usr/bin.

Huh?

After Googling a bit, I discovered this web page which describes an esoteric problem that the libtool has in Leopard, and now in Snow Leopard, where gcc can’t seem to fully optimize PHP without mis-generating a .dSYM file. Or something like that. That guy on that page describes a way to not-quite-fully-optimize PHP and avoid the problem. Others have described a simpler way to solve the problem which yields a fully-optimized PHP. All you have to do is symlink php to the php.dSYM file.

In case you haven’t moved the old php out of the way yet (in which case that php -i above wouldn’t have worked in the first place), do this

$ sudo mv /usr/bin/php /usr/bin/php.apple

then this to make the symlink:

$ sudo ln -s /usr/bin/php.dSYM /usr/bin/php

That way, if you reinstall PHP again (as Apple has a tendency to step on our custom PHP installs, you’re certain to do so…) the newly-created php.dSYM will still link to php commands. Furthermore, if Apple does decide to fix the libtool/gcc problem, then php will be replaced and the problem goes away anyway.

Another Error: Warning! dlname not found in /usr/libexec/apache2/libphp5.so.

If you see this

Warning!  dlname not found in /usr/libexec/apache2/libphp5.so.

in the middle of the make install step, and yet PHP seems to work fine on both the command line and via Apache, as best Art and I can figure out, it’s OK. Don’t worry.

Updated! Libpng Header Version Problems

If you did what I did and installed libpng 1.4.x, then you have had this problem and probably don’t realize it. When you compile PHP and point it at /usr/X11R6/inclde to pick up the FreeType headers, it also picks up an old, 1.2.x, version of the libpng headers, but still builds PHP with the new version of the library itself, which is in /usr/include. And that’s a problem.

I’ve not been able to figure out how configure decides where to find what, nor how it could even be directed to do otherwise, but my workaround was to do

$ sudo mv /usr/X11R6/include/png.h /usr/X11R6/include/png.h_old

on a temporary—or maybe permanent—basis. I’m not sure I’ll ever need to do anything “real” with X11, so I think it’s OK to leave it that way. But, if you’re, er, retentive about things, you’ll want to put it back when you’re done making a new PHP.

By the way, I will be creating a new entry real soon now that summarizes all of these steps because as I’m doing it fore real, I realized it’s a real pain to read through the narrative to get to the heart of the process.

5 Comments

incolor said:

Thanks for the great step-by-step guide. I really need Freetype bundled with my GD library.

I make it all the way through just as you've documented, until I get to the last make. I looks like it succeeds compiling freetype2, then a little bit after libtool, I get this error:

Undefined symbols:
  "_png_check_sig", referenced from:
      _php_gd_gdImageCreateFromPngCtx in gd_png.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [libs/libphp5.bundle] Error 1

Could this possibly be because I had previously phpized with memcached and mcrypt?

Tim Strehle said:

Thanks for writing all this stuff down! I just played with PHP and MySQL on a Mac mini Server for the first time (see http://blog.digicol.de/2010/01/20/running-dc-x-on-mac-mini-server/) and ran into a few problems as well…

I installed quite a few things via MacPorts and built the missing PHP extensions separately, keeping the preinstalled PHP 5.3.0. I'll try some of your tricks when it's time to compile 5.3.1.

Why did you keep --prefix=/usr? You probably know that if you leave this out, PHP will be installed into /usr/local/bin instead of /usr/bin and not conflict with Apple's PHP binary (the PATH environment variable will make sure that you're using your own binary).

David said:

I really enjoyed reading through this post.Thanks.

Arthur Nisnevich said:

Thank you! Was tremendously helpful, even for PHP 5.3.4 and later versions of the various libraries.

Anton E. said:

Hi, I ve been trying to go through several different compilation methods with PHP-5.3.3 on OS X 10.6.5 Server but most of them returned errors and nothings helped untill I found this updated version of entropy http://taracque.hu/php5/

PHP 5.3.3-4 (previous build) worked for me Anton.