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.

Monday, January 17, 2011

Reading the PlayStation 3 registry with PHP

Sony Brasil took way too long to release the PS3 console on my country (something around august 2010). A long time before that happened, many foreign versions of the console (mostly of them american) were already available all around the country. So when I bought mine, I had no choice but a DVD region 1 PS3.

Brazil and United States shares the same Blu-ray region, so I am fine on that matter. DVD playback wasn't an issue for me either as I used to play them on my MacBook. But I have recently replaced it with the new MacBook Air 11" which has no DVD drive built-in, and now I am left with only the PS3 to watch my DVD movies.

Even though Brazil is DVD region 4 and my console is region 1, most recent DVDs play fine on it - it seems that region lock has been removed from those discs on factory. But a recent purchase showed an exception: my 40 DVDs box of the complete series of "Friends" (from Warner) just won't play on my PS3. Now that is bothering me.

I have been searching for weeks on how to watch my original, and expensive, DVDs region 4 on my console region 1, bought on a region 4 country at a time when only region 1 console was available. I couldn't overcome that limitation, I couldn't even find a way to opt for a region change (like my old MacBook let me do). But still, I found out about a really interesting stuff: the PS3 has a registry file with all of its settings - including the DVD region.

The registry file is called xRegistry.sys and can not be obtained by normal ways - you have to jailbreak your console to have access to it. It is a binary file, but a few guys managed to reverse engineer it here and here.

A GUI editor is available at the last link above, but it is target on a platform I have no access to. So I wrote a small piece of PHP code to help me with the task of manually editing the registry file - based on the specifications on the PS3 wiki and also on the code by stoker25.



A sample output is:

Array
(
...
[3933] => Array
(
[0] => /setting/bddvd/mnrForDvdRom
[1] => Array
(
[flags] => 0
[xxx] => 27415
[length] => 4
[type] => 01
[data] => 0x00000000
)

)

[3966] => Array
(
[0] => /setting/bddvd/dvdRegionCode
[1] => Array
(
[flags] => 0
[xxx] => 35494
[length] => 4
[type] => 01
[data] => 0x00000001
)

)
...


Which tells me, for instance, that at the decimal offset 3966 (0xF7E) I have the setting /setting/bddvd/dvdRegionCode which holds a value of 0x1. With that information in hand I can open xRegistry.sys with my favorite HEX editor and change that value to 0x4, for instance, and then upload the file back to my PS3.

Note that the registry file is divided in two sections: settings and data. The outer array keys on the output above are offsets to the settings. The data section is located below the settings, and points directly (with a delta of 0x10) to its parent setting. So in the example above I would search for 0x0000076E (which is 0x7E - 0x10) and hopefully I would end up on the value of the dvdRegionCode setting. To make sure you are on the right place, check the other fields as well - flags, length, type and the unknown field "xxx".

For more information on the structure of the registry file, please check the PS3 wiki.

Note that I have successfully changed my dvdRegionCode setting from 0x1 to 0x4 using the method above, but it had no real effect. I still can not play region 4 DVDs. But other people reported it worked for them - perhaps my american console is doing hardware checks while other versions don't.