Home / PHP WURFL API

PHP WURFL API
Introduction


SourceForge.net Logo
 

New WURFL PHP API
by Luca Passani
passani at eunet dot no

The introduction of the new WURFL heuristics requires the introduction of a new PHP API, which is presented here.

The new code is more object-oriented and is closer to its Java counterpart.

Downloading and Installing
Getting the new PHP API to run on your server is not difficult.
We recommend that you have support for zip archives in your PHP installation (please refer to the PHP documentation for this). Technically, this is not a strict requirement, but not having to move around those 12-Meg wurfl.xml file is not a bad idea.

In addition, to this, you do need the Log library. Assuming you have PEAR installed (and if you don't, you should), this is as simple as:
$ pear install log
With this basic PHP installation in place, you can install the WURFL API with these easy steps:
  • Download the new WURFL API package.
  • Unpack it in any directory where your PHP-enabled web server can pick it up.
  • Edit the wurfl-config.xml which you find in the examples/demo/resources/ sub directory.
  • Point your web browser at:
    http://yourserver/yourdir/wurfl-{v.v}/examples/demo/


Checking that Everything Looks Alright
At this point, your browser may hang for a while, while your disk becomes busy with a lot of activity. All is good. The new API is building a cache on disk to make sure that your future WURFL queries are mega fast.
After a few seconds (or many, on a slow system), you will see something like this:



This is the PHP API recognizing your User-Agent.

Note: This example is taken with the wurfl.xml used for regression testing. A fully-fledged deployment which includes the web browser patch would correctly recognize the client in the picture as Opera for Windows

From this moment, your server is set to run application that take advantage of the new API and the new heuristics.

The main configuration file is resources/wurfl-config.xml.
wurfl-config.xml will tell the API where to find the wurfl.xml repository, which may also be provided as an archive (wurfl.zip) to the new API (a welcome addition, I am sure).
In addition to the WURFL repository, the config file can also be used to add patch files (more than one patch file is allowed in the new API, another long overdue feature).
You can also use wurfl-config.xml to point to a different directory for the cache.

Important Note: You may use the default "cache" directory for storing your cache files, but you will still need to make sure that this directory is writable by PHP, or PHP won't be able to produce the cache. Please observe that a disk cache must be present or the WURFL API won't work. The disk cache should not be confused with additional in-memory caching mechanisms such as MEMCache which you may also want to adopt for better performance.


(Simple) Sample Configuration file wurfl-config.xml:
    <wurfl-config>
    <wurfl>
        <main-file>data/wurfl.zip</main-file>
        <patches>
            <patch>data/patch_01.xml</patch>
        </patches>
    </wurfl>
    <!-- 
        cache-dir specifies the directory used for caching. 
        Make sure PHP has write access
    -->
    <cache-dir>cache/</cache-dir>
    </wurfl-config>
Click here for a fully-fledged wurfl-config.xml, which includes some extra details.

Using the API
Time to take a look at how the API is used. Just like the old API, you will need to make sure that WURFL has been initialised and the cache on disk has already been created.

This is easily achieved with the following:
    <?php

    require_once "WURFL_Installation/WURFL/WURFLManagerProvider.php";

    $wurflConfigFile = "...": //provide the absolute or
                              //relative path to the config file.
 
    $wurflManager = WURFL_WURFLManagerProvider::getWURFLManager($wurflConfigFile);
		
    ?>
Now, you have all you need to start retrieving device profiles and capabilities.

$wurflManager -> getDeviceForUserAgent(string $userAgent)
This method will take a user-agent string as a parameter, and return a Device object, i.e. the object that represents a device profile.

$wurflManager -> getDeviceForHttpRequest($_SERVER)
Similar to the previous method, but using the complete HTTP request as the key. Typically, you will use this method.

$wurflManager -> getDeviceForRequest(WURFL_Request_GenericRequest $request)
where WURFL_Request_GenericRequest encapsulates a few relevant HTTP headers such as: userAgent, x-wap-profile.
This is useful for advanced cases: imagine you want to create a fake HTTP request programmatically, and throw it at the API. With this method, you can do it.

$wurflManager -> getDevice(string $deviceID)
Retrieve a Device from its WURFL ID.

$wurflManager -> getDevice(string $deviceID)
Retrieve a Device from its WURFL ID.

$wurflManager -> getAllDevicesID()
Return all the device IDs in WURFL as an Array.

In addition to these, the following utility methods are worth mentioning:

$wurflManager -> getListOfGroups()
Returns an Array of WURFL group names.

$wurflManager -> getCapabilitiesNameForGroup($groupID)
Return all the capability names for a given group ID (all the capabilities for that group in WURFL, not in any given device).

$wurflManager -> getFallBackDevices($deviceID)
Return the whole "chain" of WURFL IDs that the API can collect on its way to "generic".

A few details about the implementation

With the old API, you needed an external script to initialize the repository (mainly generating the file-system based cache). The new API makes this task unnecessary. If the cache is not there, it will be created for you the first time you invoke the API.
This initialization part consists of two phases: cache creation represents the first phase. Cathegorizing the device profiles in families according to the user-agent is the second phase. Thanks to this cathegorization, actual UA matching will happen according to the new two-step analysis outlined in the introduction.

You will not need to understand these datails to use the API, unless you want to modify the way the API works. In the rest of the document, we will give you a quick overview of the classes. Please refer to the included documentation for more specific information, or just look at the code itself.

XML parsing
The PHP classthat matters to you is WURFL_Xml_XMLResourceManager: it coordinates the parsing and patching of the profiles defined in WURFL. It "persists" the resulting data structures (see ahead for pluggable persistence strategies).

Package: User-Agent String Handlers
The two-step analysis we mentioned are implemented by multiple classes (one per family) which you can find in the WURFL/Handlers directory. We won't name any of these classes specifically, but just mention that each one of them implements the WURFL_Handlers_Handler abstract class (if you don't know what it is, don't worry: it's not part of the required training for PHP programmers).

The filter($userAgent, $deviceID) method will decide whether a given UA string belongs to a particular family (for example, NokiaHandler.php is the handler which, among other things, decides whether a given UA belongs to the Nokia family).
Handlers are also responsible for matching the family for actual requests (HTTP requests, actually something derived from them: WURFL_Request_GenericRequests).

Caching (File-System, Memcache, APC, EAccelerator, RDBMS)
PHP was not initially devised to persist anything in memory between two subsequent requests.
This always made implementors of WURFL APIs particularly unhappy, because of the requirement of persisting data on the file-system. This is still the default behaviour of this API out of the box, but by no means the only one possible: such popular caching libraries such as Memcache, APC, EAccelerator and others are also supported.

For example, if you already have MEMCache installed, enabling this WURFL API to take advantage of it is easily done by acting on the aforementioned wurfl-config.xml alone.

Just change the provider and specify the parameter. In the case of Memcache, you'll need to specify the IP number of a separate server running Memcache:
    <cache>
    	<provider>memcache</provider>
    	<params>serverIp=127.0.0.1</params>
    </cache>
Implementing support for more caching libraries would also be possible with relative little ewffort (just look at the WURFL_Cache_CacheProvider and all of the other classes in the same package/directory).

Conclusions
We did not go too deep with the details, but hopefully this is enough to get you started with the new API.
Please give it a spin and if you have questions feel free to ask at the usual place: WMLProgramming at YahooGroups.



Enjoy!
Luca Passani


Copyright © 2007-2009, Luca Passani