Friday, September 16, 2011

Mac OS X 10.7 Lion and PHP

Since Lion upgrade, I have noted that sometimes the pager utility less was misbehaving. That's what happens when I try php -i | less:


th-png-dir=/BinaryCache/apache_mod_php/apache_mod_php-66.1~51/Root/usr/local' '--enable-gd-native-ttf' '--with-icu-dir=/usr' '--with-iodbc=/usr' '--with-ldap=/usr' '--with-ldap-sasl=/usr' '--with-libedit=/usr' '--enable-mbstring' '--enable-mbregex' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--without-pear' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/var/mysql/mysql.sock' '--with-readline=/usr' '--enable-shmop' '--with-snmp=/usr' '--enable-soap' '--enable-sockets' '--enable-sqlite-utf8' '--enable-suhosin' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-tidy' '--enable-wddx' '--with-xmlrpc' '--with-iconv-dir=/:j
usr' '--with-xsl=/usr' '--enable-zend-multibyte' '--enable-zip' '--with-pcre-regex=/usr' '--with-pgsql=/usr' '--with-pdo-pgsql=/usr'
:j
Server API => Command Line Interface
Virtual Directory Support => disabled
:j
Configuration File (php.ini) Path => /etc
Loaded Configuration File => /private/etc/php.ini
:j
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)
:j
PHP API => 20090626
PHP Extension => 20090626
:

And that's what I would expect:


Build Date => Sep 16 2011 21:54:05
Configure Command =>  './configure'  '--prefix=/opt/php536' '--enable-cli' '--with-libxml-dir=/usr' '--with-openssl=/usr' '--with-kerberos=/usr' '--with-zlib=/usr' '--enable-bcmath' '--with-bz2=/usr' '--enable-calendar' '--with-curl=/usr' '--enable-dba' '--enable-exif' '--enable-ftp' '--with-iodbc=/usr' '--with-ldap=/usr' '--with-ldap-sasl=/usr' '--enable-mbstring' '--enable-mbregex' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--without-pear' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/var/mysql/mysql.sock' '--enable-shmop' '--with-snmp=/usr' '--enable-soap' '--enable-sockets' '--enable-sqlite-utf8' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-tidy' '--enable-wddx' '--with-xmlrpc' '--with-iconv-dir=/usr' '--with-xsl=/usr' '--enable-zend-multibyte' '--enable-zip' '--with-pcre-regex' '--with-pgsql=/usr' '--with-pdo-pgsql=/usr' '--enable-pcntl' '--with-gmp'
Server API => Command Line Interface
Virtual Directory Support => disabled
Configuration File (php.ini) Path => /opt/php536/lib
Loaded Configuration File => /opt/php536/lib/php.ini
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)
PHP API => 20090626
PHP Extension => 20090626
Zend Extension => 220090626
Zend Extension Build => API220090626,NTS
:

In both cases I tried to go down by pressing the key j five times.

At first I thought it was some change in a newer version of less so I was missing some command line option to make it behave like the old good way. But after spending an hour reading its manual, I was convinced it was not a feature - but a bug somewhere.

It turns out that Mac OS X 10.7 Lion (and other operating systems as well) comes with a borked libedit version. Unfortunately in that case Lion's PHP is shipped with libedit enabled, as we can see below:


$ otool -L `which php` | grep libedit
	/usr/lib/libedit.3.dylib (compatibility version 2.0.0, current version 3.0.0)

So when you try to output PHP's stdout to less, libedit and less starts fighting for stdin in a not very healthy way - so you get a bad user experience (i.e. screen doesn't redraws well).

The first way I found around it is :


$ php -i < /dev/null | less

which is not practical in my opinion. The second way is to custom build PHP yourself:


cd /usr/src

# download and extract php 5.2.6
wget http://museum.php.net/php5/php-5.3.6.tar.bz2
tar -jxf php-5.3.6.tar.bz2

# go to source dir
cd php-5.3.6

# configure
CFLAGS='-arch x86_64' \
CXXFLAGS='-arch x86_64' \
LDFLAGS='-arch x86_64' \
'./configure'  '--prefix=/opt/php536' '--enable-cli' '--with-libxml-dir=/usr' '--with-openssl=/usr' '--with-kerberos=/usr' '--with-zlib=/usr' '--enable-bcmath' '--with-bz2=/usr' '--enable-calendar' '--with-curl=/usr' '--enable-dba' '--enable-exif' '--enable-ftp' '--with-iodbc=/usr' '--with-ldap=/usr' '--with-ldap-sasl=/usr' '--enable-mbstring' '--enable-mbregex' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--without-pear' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/var/mysql/mysql.sock' '--enable-shmop' '--with-snmp=/usr' '--enable-soap' '--enable-sockets' '--enable-sqlite-utf8' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-tidy' '--enable-wddx' '--with-xmlrpc' '--with-iconv-dir=/usr' '--with-xsl=/usr' '--enable-zend-multibyte' '--enable-zip' '--with-pcre-regex' '--with-pgsql=/usr' '--with-pdo-pgsql=/usr' '--enable-pcntl' '--with-gmp'

# build and install
make
make install

I usually do this as a regular user. You might want to give yourself permissions over /usr/src and /opt.

Also, note that Lion's PHP comes with a few improvements such as suhosin patch which we are not contemplating here.