WEB Advent 2009 / PHP in Odd Places

PHP has traditionally been used to solve web problems, and for this, it excels. Over the past year and a half, I have been doing some unusual things with PHP in a completely new environment, my phone. In this article, I will explain the perils I encountered while exploring the technical depths of making apps for mobile platforms.

The Phone

My phone — an OpenMoko — consists of open hardware and runs Linux. The phone is just a normal ARM platform; you can even install Debian if you are so inclined. Most of the GUI software is written in PyGTK, although they are moving away from that. The phone’s software is rather unstable and not very user friendly, but because it is a completely open platform, you can run anything you want, including PHP. I set out to see whether it was viable to write my own apps for the phone and turn it into a phone that I can use on a daily basis without problems.

PHP

The first task was to get PHP compiling on the phone. The fastest way to compile something for an embedded device is to use a cross compiler — a compiler running on one platform (usually Linux i386) compiling for a different platform, in my case Linux ARM.

With a complicated cross compiler setup, I managed to get PHP compiled, but extensions were awkward, because PHP’s configure system doesn’t support cross compiling. So, I resorted to compiling extensions on the phone itself.

Compiling on the phone opened a whole new can of worms. Although the phone comes with a compiler, almost none of the other tools for building are available. Tools such as Automake, Libtool, and other compiling and linking tools were either not working or broken.

I also learned that compiling on the phone is very slow. There’s not a lot of memory, and the SD card reading speed isn’t great. It took 3 hours to compile PHP 5.2.6 on the phone, and to achieve this, I had to modify the makefile, because some C files — the PHP language parser and ext/date’s string-to-time parser — require so much memory when optimization levels are enabled that the device runs out of memory. The only solution is to turn off optimizations for those files.

Once PHP is compiled, its performance is quite reasonable for a 400 MHz processor. The result:


php -i | head -n 4
phpinfo()
PHP Version => 5.2.6

System => Linux om-gta02 2.6.29-rc3 #1 PREEMPT Sun Aug 2 12:17:54 CEST 2009 armv4tl

PHP-GTK

Although the OpenMoko has a terminal, using PHP on the command line is not very convenient due to the small size of the on-screen keyboard. The predictive view of the keyboard is good, but the terminal and number views are limited in usability and size, so in order to do something useful with the phone, a GUI toolkit is a must. PHP’s only really workable toolkit is PHP-GTK; luckily, the OpenMoko already has all the GTK libraries available. Compiling PHP-GTK for the phone was a bit tricky, but three hours later, I had a working PHP-GTK extension:


php-gtk

GTK+ support => enabled
GTK+ v => 2.14.2

In order to enable UTF-8 support, I had to set php-gtk.codepage to UTF-8.

My next obstacle was to actually figure out how to use PHP-GTK. Although I have been working with PHP for ages, PHP-GTK was unfamiliar. It’s event-driven, so things are triggered when you click something. PHP-GTK’s approach to interface design also created some obstacles.

After dabbling with some test interfaces and simple apps, I found that PHP-GTK apps were actually faster than similar PyGTK apps.

Interface

Because the phone’s touch screen is the only interface, you need to pay special attention to the size and placement of buttons, else it’s hard to avoid pressing the wrong one. It’s not a problem when you tap the wrong key on the keyboard, but it is when you accidentally tap a submit button instead of a delete button. It’s best to create buttons that are plenty large and place dangerous buttons away from the others. Asking for confirmation can also help users avoid disaster.

Although the predictive keyboard on the phone is pretty good, it is not nearly as fast as my old Nokia’s T9 system. Just for fun, I implemented T9 as a GTK window. There are still a few issues — like the order of letters on the “pqsr” button — but this T9 clone is still faster for text entry than the standard keyboard.

Talking to hardware

In order to actually do something useful, like make a phone call, you need to talk to the hardware. There is a whole framework being developed as part of the FreeSmartPhone project. It works on many open phones, including mine. The FreeSmartPhone framework provides an abstraction layer, so apps can be platform-independent. All the functionality is available through a D-BUS interface, which means I had to write a D-BUS extension.

This extension lets PHP talk to any exposed D-BUS interface, and it also lets PHP apps export servers through D-BUS. On the OpenMoko, D-BUS allows you to talk to the SIM card, the GSM network, the address book services on the phone, as well as to the GPS chip. There are both higher- and lower-level services available, but not all the specified methods are implemented yet.

A good example of an exposed method is SendTextMessage() from the SMS interface, which allows a message of arbitrary length to be sent without having to break the message up into 160- and 140-character chunks. Unfortunately, this method is not yet implemented, so I did this by hand and include it here as an example. I use this to send SMS messages when I have the phone connected to my laptop. It is much faster to use my full keyboard than the phone’s touch screen:

<?php
    $nr = $argv[1];
    $text = $argv[2];
 
    $d = new DBus( DBus::BUS_SYSTEM );
    $smsInterface = $d->createProxy(
        'org.freesmartphone.ogsmd',
        '/org/freesmartphone/GSM/Device',
        'org.freesmartphone.GSM.SMS'
    );
 
    if ( strlen( $text ) <= 160 ) {
        $smsInterface->SendMessage(
            $nr,
            $text,
            new DBusDict( Dbus::VARIANT, array() )
        );
        echo "Sending: $text\n";
    } else {
        $textParts = chunk_split( $text, 140, "\n" );
        $textParts = explode( "\n", trim( $textParts ) );
        $id = mt_rand( 0, 255 );
        $cnt = count( $textParts );
        $c = 1;
        foreach( $textParts as $textPart ) {
            $smsInterface->SendMessage(
                $nr,
                $textPart,
                new DBusDict( Dbus::VARIANT,
                    array(
                        'csm_id' => new DBusVariant( $id ),
                        'csm_num' => new DBusVariant( $cnt ),
                        'csm_seq' => new DBusVariant( $c )
                    )
                )
            );
            $c++;
            echo "Sending: $textPart\n";
        }
    }
    ?>

Resource limitations

Next, I started working on a Twitter client. Twitter clients are the new “Hello World“ after all. The cool thing about PHP-GTK is that apps can be developed on your desktop, then you can simply transfer the app to the phone. The only issues I ran into had to do with GTK themes and resolution inconsistencies.

Memory

Desktops have significantly more memory than phones. My desktop has 4 GB of memory, whereas my phone only has 128 MB. So, although you can easily run one PHP-GTK app, running two or three — or running them alongside other memory-hungry apps — is simply not going to work well.

There are a few tricks that can mitigate this problem. PHP-GTK allows multiple top-level windows, so a very obvious trick is to just launch multiple virtual apps from one actual app. This cuts down on start-up time as well as memory usage, because only one PHP binary is running. I also found that PHP 5.3 — with its new garbage collector — was quite an improvement, because it cleans up memory so much more efficiently.

Bandwidth

After the Twitter experiment, I continued to write yet another application — one that shows the status of the London Underground. Unfortunately, there is no proper API for it, so I had to resort to scraping. The page I needed to scrape is about half a megabyte, and I really only needed a few status messages. The first iteration of the app downloaded the whole page and used regular expressions to populate a GUI showing the status. Downloading the whole page took so long that the app was mostly useless.

In order to conserve bandwidth, I modified the app to talk to a simple web service I made. This web service provided a tiny JSON response, which is all the phone had to download; the real work was done by the web service. My server had plenty of bandwidth and processing speed, and by moving the processing away from the phone, I had a nice app that polled the status every minute to get up-to-date information. If the format of the pages ever changes, the only thing I have to do is update the web service, not the phone app.

Conclusion

This concludes the account of my quest to write PHP apps on phones. So far, it is been an interesting journey, and I have definitely run into issues that I have never had to deal with for normal web apps. The Christmas holiday is my traditional time to work on personal projects, so I should have more to report soon. Merry Christmas!

Other posts