C H A P T E R  3

Mobile PHP

Mobile development is receiving more and more attention every year. The iPhone, Android, and BlackBerry are not just powerful smartphone devices, but also valuable brands competing for a lucrative piece of the market share. Every smartphone manufacturer wants applications for its product in hopes of attracting users. In addition to smartphones, we have tablets, such as the iPad, the PlayBook, and Galaxy, and reading devices, such as the Kindle and Nook. Even standard cellphones have improved browser support and features.

Every mobile device with access to the Internet can view online content or applications which are powered on the server side by PHP. For this reason, we need a way to meaningfully represent our content on smaller screens. In this chapter, we will cover device detection through the HTTP request user-agent string, WURFL, and Tera-WURFL, all of which will be defined later on in the chapter.

Thousands of mobile devices presently exist, each with varying capabilities. If you thought developing web applications for older browsers was fragile, mobile devices are much less standard. Luckily for us there are systems in place to aid us in our quest. To render on mobile devices we will show how to abstract markup with WALL, automatically resize images, and make CSS more fluid.

We will also introduce device emulators, developing PHP on an Android powered device, and Flash Builder for PHP. Finally, we will present Quick Response (QR) codes and how to generate them.

Mobile Variance

When dealing with mobile development, one of the great challenges is getting a website to be readable when rendered. With desktop web development, we check major browsers, such as Chrome, Firefox, Safari, Opera, and Internet Explorer, and possibly different operating systems (OS), such as WinXP, Windows 7, Linux, and Mac OS X. Catering for the different possible combinations of browsers, browser versions, and OSes can be quite a chore.

With mobile devices, the rendering capabilities are much less standard. This makes mobile rendering much more complex. For instance, almost all modern desktop computers support thousands of colors and a screen resolution of at least 800 by 600 pixels. However, cellphones, smartphones, tablets, e-readers, and other mobile devices might only support grayscale or a limited color palette. Physical sizes also vary considerably. These are only three capabilities. There are hundreds of different capabilities that devices could differ in. We will go over some of these capabilities later in the chapter.

Unlike with desktop web development, naively trying to program for each possible mobile variation by hand is impossible, or at least would take far too much time and effort than anyone should be willing to spend. Instead we will discuss systems to determine the device being used and then render the content dynamically and adjust the CSS fluidly.

Detecting Devices

The first step to customizing content is knowing what device we are rendering on. We will examine several techniques to determine the active device.

The User-Agent

At the heart of any device detection system is the user-agent header string sent in a standard HTTP request. With PHP, we can access the user agent string in the $_SERVER['HTTP_USER_AGENT'] superglobal server variable. The user agent header can contain information about the browser, rendering engine and operating system. The user-agent string will look similar to this one, which is for Firefox 4:

Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0

From this string, we can see that the operating system of the client is Windows, the rendering engine is Gecko, and the browser version is Firefox 4.0.

images Note Detecting devices is not foolproof. Although rare, user-agent strings may not be unique for two distinct devices. As well, the header can be spoofed, as discussed in the chapter on security.

Built-in PHP Support

PHP has the get_browser function, which tries to attain information about the browser used. It does this by referring to information in a file, browscap.ini. In this respect it is like a simpler, more limited version of the WURFL system, which we will later cover.

images Note This function relies on having the browscap.ini file installed on your system and setting where the file is located in your php.ini file, such as:

browscap = "C:yourpath orowscap.ini"

More information on get_browser is available at http://php.net/manual/en/function.get-browser.php, and updated browscap.ini files are available at http://browsers.garykeith.com/downloads.asp

If we set the first parameter to null or pass in the actual user agent, then we will get information about the current client being used. We can also pass in a different user-agent string to learn information about it. The second parameter is optional. By setting the parameter to true, we request the information back as an array instead of a default object. See Listings 3-1 and 3-2.

Listing 3-1. Using the PHP get_browser Function

<?php
echo $_SERVER ['HTTP_USER_AGENT'] . " ";

var_dump ( get_browser ( null, true ) );

//equivalently,  we could have passed in the user agent string into the first parameter
//var_dump ( get_browser ( $_SERVER ['HTTP_USER_AGENT'], true ) );
?>

Listing 3-2. Output in the Chrome Browser

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24
array
  'browser_name_regex' => string '§^.*$§' (length=6)
  'browser_name_pattern' => string '*' (length=1)
  'browser' => string 'Default Browser' (length=15)
  'version' => string '0' (length=1)
  'majorver' => string '0' (length=1)
  'minorver' => string '0' (length=1)
  'platform' => string 'unknown' (length=7)
  'alpha' => string '' (length=0)
  'beta' => string '' (length=0)
  'win16' => string '' (length=0)
  'win32' => string '' (length=0)
  'win64' => string '' (length=0)
  'frames' => string '1' (length=1)
  'iframes' => string '' (length=0)
  'tables' => string '1' (length=1)
  'cookies' => string '' (length=0)
  'backgroundsounds' => string '' (length=0)
  'cdf' => string '' (length=0)
  'vbscript' => string '' (length=0)
  'javaapplets' => string '' (length=0)
  'javascript' => string '' (length=0)
  'activexcontrols' => string '' (length=0)
  'isbanned' => string '' (length=0)
  'ismobiledevice' => string '' (length=0)
  'issyndicationreader' => string '' (length=0)
  'crawler' => string '' (length=0)
  'cssversion' => string '0' (length=1)
  'supportscss' => string '' (length=0)
  'aol' => string '' (length=0)
  'aolversion' => string '0' (length=1)

As you can see, the information obtained by the get_browser function returns nothing for this newer browser. This is because the browscap.ini file that was included with my WAMP (Windows, Apache, MySQL, PHP) bundle was over a year old. The solution is to download an up to date version. We may also need to restart the Apache server if the file is cached. After updating, we get some more useful information, shown in Listing 3-3.

Listing 3-3. Output in the Chrome Browser with Updated browscap.ini

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24
array
  'browser_name_regex' => string '§^mozilla/5.0 (.*windows nt 6.1.*wow64.*) applewebkit/.* (khtml, like gecko).*chrome/11..*safari/.*$§' (length=108)
  'browser_name_pattern' => string 'Mozilla/5.0 (*Windows NT 6.1*WOW64*) AppleWebKit/* (KHTML, like Gecko)*Chrome/11.*Safari/*' (length=90)
  'parent' => string 'Chrome 11.0' (length=11)
  'platform' => string 'Win7' (length=4)
  'win32' => string '' (length=0)
  'win64' => string '1' (length=1)
  'browser' => string 'Chrome' (length=6)
  'version' => string '11.0' (length=4)
  'majorver' => string '11' (length=2)
  'frames' => string '1' (length=1)
  'iframes' => string '1' (length=1)
  'tables' => string '1' (length=1)
  'cookies' => string '1' (length=1)
  'javascript' => string '1' (length=1)
  'javaapplets' => string '1' (length=1)
  'cssversion' => string '1' (length=1)
  'minorver' => string '0' (length=1)
  'alpha' => string '' (length=0)
  'beta' => string '' (length=0)
  'win16' => string '' (length=0)
  'backgroundsounds' => string '' (length=0)
  'vbscript' => string '' (length=0)
  'activexcontrols' => string '' (length=0)
  'isbanned' => string '' (length=0)
  'ismobiledevice' => string '' (length=0)
  'issyndicationreader' => string '' (length=0)
  'crawler' => string '' (length=0)
  'aolversion' => string '0' (length=1)Using Regex

If you are only concerned with detecting a few major mobile devices, then you can use a regular expression to search the user-agent string. In Listing 3-4, we check for a few phones in the user-agent string. If a match is found, then we redirect to a separate mobile page and load an alternate template and stylesheet. The /i option in the regular expression (regex) makes our search case insensitive. The | means “or” so both “iPhone” and “iPod” would be matched, but not “iPod.” Similarly, “windows ce” and “windows phone” would be matched, but not “windows xp.” Refer to the index for more on regular expressions.

Listing 3-4. Using Regex to Check for Specific Mobile Devices

<?php
  if (preg_match ( '/i(Phone|Pad)|Android|Blackberry|Symbian|windows (ce|phone)/i',
                 $_SERVER ['HTTP_USER_AGENT'] )) {
        //redirect, load different templates, stylesheets  
        header ( "Location: mobile/index.php" );
  }
?>

To detect a wider range of mobile devices, we require a lot more regex. The website http://detectmobilebrowser.com/ has gained popularity, because it can generate the long regex that we require for several different scripting languages or frameworks (fifteen and counting). It will also redirect the client to a mobile specific page if we want. Listing 3-5 shows sample regex produced by the site.

Listing 3-5. The Regex Generated by detectmobilebrowser.com

<?php
$useragent = $_SERVER['HTTP_USER_AGENT'];

if(preg_match('/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|symbian|treo|up.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|e-|e/|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(-|2|g)|yas-|your|zeto|zte-/i', substr($useragent,0,4)))
header('Location: http://detectmobilebrowser.com/mobile'),
    ?>

This type of solution will work for some cases. However, for more accurate results and to recognize device capabilities, we need a more elaborate system. That system is WURFL, which will be covered next.

Detecting Mobile Capabilities

To go beyond mere device detection and know what the device is capable of doing requires using the more elaborate WURFL system.

WURFL

The Wireless Universal Resource FiLe (WURFL) is an XML file, invented by Luca Passani, that contains mobile device capabilities.

Introduction

Currently, over 500 different device capabilities are listed in the WURFL. Implementations to use WURFL have been created in many languages and platforms including Java and .NET. In PHP, the official API is known as The New PHP WURFL API and is available at http://wurfl.sourceforge.net/nphp/.

Device capabilities use an inheritance stack hierarchy. If a capability is not listed for the most specific model, then a more generic device is checked. If the capability is still not listed, then WURFL checks the next most generic device and repeats this process until a basic root device level is reached. This hierarchical structure saves space and increases performance. WURFL also attempts to use a ZIP archived version of the XML file using ZipArchive, a package that is included with PHP >= 5.2.0. As the ZIP version of the file is currently under a megabyte (MB) in size while the actual XML file is 16MB, this is another performance improvement.

Some useful capabilities to know about a specific device could be the screen resolution, codec support and formats, JavaScript, Java, and Flash support.

images Note Contributions to the XML file are mostly volunteered by developers and end users, and can contain errors. Also, new devices are being created all the time. Though it is very large and comprehensive, we should never expect WURFL to be 100% accurate. If you need to include a device soon, you can list its capabilities and patch the information to the main XML file.

If accuracy is of the utmost importance, proprietary systems that claim even better accuracy do exist.

Setup

For all of the examples in this chapter, we will place the WURFL library files in a directory called wurfl, which will be relative to the webroot as ./wurfl/. We will use a common configuration file for our examples and obtain a WURFLManager object each time by using the code in Listing 3-6.

Listing 3-6. Creating a WURFLManager Object: wurflSetup.php

<?php

error_reporting(E_ALL);
define( "WURFL_DIR", dirname(__FILE__) . '/wurfl/WURFL/' );
define( "RESOURCES_DIR", dirname(__FILE__) . "/wurfl/examples/resources/" );

require_once WURFL_DIR . 'Application.php';

function getWurflManager() {
    $config_file = RESOURCES_DIR . 'wurfl-config.xml';
    $wurfl_config = new WURFL_Configuration_XmlConfig( $config_file );

    $wurflManagerFactory = new WURFL_WURFLManagerFactory( $wurfl_config );
    return $wurflManagerFactory->create();
}

?>
Detecting Devices with WURFL

In our first device detection example, we will print out the device stack using the new WURFL PHP API. We will output the device hierarchy of a UA, using the fallback and id properties. See Listing 3-7.

Listing 3-7. Outputting the Device Stack of a User Agent from Most Specific to Generic

<?php

error_reporting(E_ALL);
require_once('wurflSetup.php'),

$wurflManager = getWurflManager();

$device = $wurflManager->getDeviceForHttpRequest($_SERVER);

print "<p>ID Stack is: <br/>";
while ($device != null)
{
    print $device->id . "<br/>";
    if (!$device->fallBack || $device->fallBack == "root")
    {
        break;
    }
    $device = $wurflManager->getDevice($device->fallBack);
}
print "</p>";

?>

Here is the output of the script when browsing on a desktop computer in the Firefox 4 browser:

ID Stack is:
firefox_1
firefox
generic_web_browser
generic_xhtml
generic

and in the Chrome browser:

ID Stack is:
google_chrome_1
google_chrome
generic_web_browser
generic_xhtml
generic

images Note Running the script in Listing 3-7 for the first time can take a very long while, as WURFL builds the resource cache. You may need to increase your php.ini max_execution_time directive.

If we want to emulate using another device, we can modify the user agent server variable. A modified version of Listing 3-7 is shown in Listing 3-8. The output is shown in Listing 3-9.

Listing 3-8. Emulating Another Device by Modifying the Server User Agent

<?php

error_reporting(E_ALL);
require_once('wurflSetup.php'),

$wurflManager = getWurflManager();

$_SERVER['HTTP_USER_AGENT'] =
"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML,images
 like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";

$device = $wurflManager->getDeviceForHttpRequest( $_SERVER );

print "<p>ID Stack is: <br/>";
while ( $device != null) {
    print $device->id . "<br/>";
    if ( !$device->fallBack  || $device->fallBack == "root" )
    {
        break;
    }
    $device = $wurflManager->getDevice( $device->fallBack );
}
print "</p>";

?>

Listing 3-9. WURFL Output of the Emulated iPhone 4 User Agent

ID Stack is:
apple_iphone_ver4_sub405
apple_iphone_ver4
apple_iphone_ver3_1_3
apple_iphone_ver3_1_2
apple_iphone_ver3_1
apple_iphone_ver3
apple_iphone_ver2_2_1
apple_iphone_ver2_2
apple_iphone_ver2_1
apple_iphone_ver2
apple_iphone_ver1
apple_generic
generic_xhtml
generic
Detecting and Listing Device Capabilities with WURFL

In Listing 3-10, we will show the available capability groups that we can inspect. We will also output all of the specific capabilities for the display and css groups that are available. The output is shown in Listing 3-11.

Listing 3-10. Listing the Available Capability Groups

<?php

error_reporting(E_ALL);
require_once('wurflSetup.php'),

$wurflManager = getWurflManager();

$device = $wurflManager->getDeviceForHttpRequest( $_SERVER );
$capability_groups = $wurflManager->getListOfGroups();
asort( $capability_groups );

foreach ( $capability_groups as $c ) {
    print $c . "<br/>";
}
?>

Listing 3-11. Output of Listing 3-10

ajax
bearer
bugs
cache
chtml_ui
css
display
drm
flash_lite
html_ui
image_format
j2me
markup
mms
object_download
pdf
playback
product_info
rss
security
sms
sound_format
storage
streaming
transcoding
wap_push
wml_ui
wta
xhtml_ui

To output a list of all available capabilities, we can modify Listing 3-10 to use the getCapabilitiesNameForGroup method, shown in Listing 3-12. The first part of the output is shown in Listing 3-13.

Listing 3-12. Listing all Capabilities That We Can Inspect

<?php

error_reporting(E_ALL);
require_once('wurflSetup.php'),

$wurflManager = getWurflManager();

$device = $wurflManager->getDeviceForHttpRequest( $_SERVER );
$capability_groups = $wurflManager->getListOfGroups();
asort( $capability_groups );

foreach ( $capability_groups as $c ) {
    print "<strong>" . $c . "</strong><br/>";
    var_dump( $wurflManager->getCapabilitiesNameForGroup( $c ) );
}
?>

Listing 3-13. The First Part of the Output from Listing 3-12

ajax

array
  0 => string 'ajax_preferred_geoloc_api' (length=25)
  1 => string 'ajax_xhr_type' (length=13)
  2 => string 'ajax_support_getelementbyid' (length=27)
  3 => string 'ajax_support_event_listener' (length=27)
  4 => string 'ajax_manipulate_dom' (length=19)
  5 => string 'ajax_support_javascript' (length=23)
  6 => string 'ajax_support_inner_html' (length=23)
  7 => string 'ajax_manipulate_css' (length=19)
  8 => string 'ajax_support_events' (length=19)

bearer

array
  0 => string 'sdio' (length=4)
  1 => string 'wifi' (length=4)
  2 => string 'has_cellular_radio' (length=18)
  3 => string 'max_data_rate' (length=13)
  4 => string 'vpn' (length=3)

We can modify Listing 3-12 to be more visually useful and to display only certain device capabilities, prefixing supported capabilities with green checkmarks (rendered with HTML entities) and listing unsupported capabilities with red strikeout styling. See Listing 3-14. The output is shown in Figure 3-1.

Listing 3-14. Displaying Color-Coded Device Capability Values

<?php
error_reporting ( E_ALL );
require_once ('wurflSetup.php'),

$wurflManager = getWurflManager ();

$device = $wurflManager->getDeviceForHttpRequest ( $_SERVER );
$capability_groups = $wurflManager->getListOfGroups ();
asort ( $capability_groups );

foreach ( $capability_groups as $group ) {
        //only output the capabilities of certain groups
        if (in_array ( $group, array ("ajax", "css", "image_format" ) )) {
                print "<strong>" . $group . "</strong><br/>";
                print "<ul>";
                foreach ( $wurflManager->getCapabilitiesNameForGroup ( $group ) as $name ) {
                        $c = $device->getCapability ( $name );
                        if ($c == "false") {
                                $c = "<li><span style='color:red;
                                                       text-decoration:line- through;'>";
                                $c .= $name . "</span>";
                        } else if ($c == "true") {
                                $c = "<li><span style='color:green;'> &#10003; ";
                                $c .= $name . "</span>";
                        } else {
                                $c = "<li>" . $name . ": <em>" . $c . "</em>";
                        }
                        print $c;
                        print "</li>";
                }

                print "</ul>";
        }
}

?>
images

Figure 3-1. Some output of Listing 3-14, displaying easier to see device capabilities

For our final script using the new WURFL PHP API, we will output some specific capabilities of our user-agent device. See Listing 3-15.

Listing 3-15. Outputting Selected Audio and Display Capabilities of the iPhone 4

<?php

error_reporting(E_ALL);
require_once('wurflSetup.php'),

$wurflManager = getWurflManager();

$_SERVER['HTTP_USER_AGENT'] =
        "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9images
(KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";

$device = $wurflManager->getDeviceForHttpRequest($_SERVER);

//output fields that interest us

//display information
print "<h2>" . $device->id . "</h2>";
print "<p><strong>Display: </strong><br/>";
print $device->getCapability( 'resolution_width' ) . " x "; //width
print $device->getCapability( 'resolution_height' ) . " : "; //height
print $device->getCapability( 'colors' ) . ' colors<br/>';
print "dual orientation: ".$device->getCapability( 'dual_orientation' ) . "</p>";

//audio information
print "<p><strong>Supported Audio Formats:</strong><br/>";
foreach ( $wurflManager->getCapabilitiesNameForGroup( "sound_format" ) as $name ) {
    $c = $device->getCapability( $name );
    if ( $c == "true") {
            print $name . "<br/>";
    }
}
print "</p>";
?>

Running Listing 3-15 outputs the following information:


apple_iphone_ver4_sub405

Display:

320 x 480 : 65536 colors

dual orientation: true

Supported Audio Formats:

aac

mp3

images Note As mentioned before, user-agent identification is not guaranteed. When testing a Kindle 3, with user agent as follows:

Mozilla/5.0 (Linux; U; en-US) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+)images
 Version/4.0 Kindle/3.0 (screen 600x800; rotate)

Danchilla obtained the erroneous results:


toshiba_folio100_ver1
Display:
600 x 1024 : 256 colors
dual orientation: true
Supported Audio Formats:
aac
mp3

Tera-WURFL

The Tera-WURFL implementation of WURFL is available at www.tera-wurfl.com. The new PHP WURFL API is focused on accurate results. Tera-WURFL is focused more on performance. To acheive this, a database is used to fetch results instead of the large XML file. Tera-WURFL currently supports MySQL, Microsoft SQL Server, and MongoDB. It claims to be five to ten times faster than normal WURFL, 99% accurate, and to offer better desktop detection. Also, Tera-WURFL offers the ability to show a picture of the mobile device that is being used. We will show how to display the device image later on.

Setup

To set up Tera-WURFL, we need to do the following:

  1. Create a database and modify the credentials in the TeraWurflConfig.php configuration file to use it.
  2. Go to the administration page at http://localhost/Tera-WURFL/admin/. If you receive an error because of missing tables, do not worry – they will be created when we load the data.
  3. You can load the local XML file or remote XML file.

images Note If you receive an error message similar to “fatal error maximum function nesting level of '100' reached aborting,” then you need to disable xdebug in your php.ini file temporarily or increase your xdebug nesting level limit by setting the php.ini directive xdebug.max_nesting_level=100 to a higher value such as 500.

Detecting Devices with Tera-WURFL

In our first example with Tera-WURFL, shown in Listing 3-16, we will feed in the user-agent string for the iPhone 4 and verify that Tera-WURFL recognizes it and is setup properly.

Listing 3-16. Tera-WURFL Code to Identify a Specific User Agent

<?php

error_reporting(E_ALL);
require_once('Tera-WURFL/TeraWurfl.php'),

$teraWURFL = new TeraWurfl();
$iphone_ua = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us)images
AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";

if ( $teraWURFL->getDeviceCapabilitiesFromAgent( $iphone_ua ) ) {
   print "ID: ".$teraWURFL->capabilities['id']."<br/>";
} else {
    print "device not found";
}
?>

The output from running Listing 3-16 is:

ID: apple_iphone_ver4_sub405

If we did not pass in the user-agent as the parameter, then just like WURFL, the result would be from the actual client used.

Detecting and Listing Device Capabilities with Tera-WURFL

In Listing 3-17, we will output display and audio capabilities of the iPhone device. This is the Tera-WURFL equivalent to the WURFL functionality of Listing 3-15.

Listing 3-17. Determining Display and Sound Format Capabilities of the iPhone 4 with Tera-WURFL

<?php

error_reporting(E_ALL);
require_once('Tera-WURFL/TeraWurfl.php'),

$teraWURFL = new TeraWurfl();
$iphone_ua = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us)images
AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";

if ( $teraWURFL->getDeviceCapabilitiesFromAgent( $iphone_ua ) ) {
    $brand_name = $teraWURFL->getDeviceCapability( "brand_name" );
    $model_name = $teraWURFL->getDeviceCapability( "model_name" );
    $model_extra_info = $teraWURFL->getDeviceCapability( "model_extra_info" );

    //output fields that interest us
    print "<h2>" . $brand_name . " " . $model_name . " " . $model_extra_info . "</h2>";

    //display information
    print "<p><strong>Display: </strong><br/>";
    print $teraWURFL->getDeviceCapability( 'resolution_width' ) . " x "; //width
    print $teraWURFL->getDeviceCapability( 'resolution_height' ) . " : "; //height
    print $teraWURFL->getDeviceCapability( 'colors' ) . ' colors<br/>';
    print "dual orientation: " . $teraWURFL->getDeviceCapability( 'dual_orientation' );
    print "</p>";

    //audio information
    print "<p><strong>Supported Audio Formats:</strong><br/>";

    foreach ( $teraWURFL->capabilities['sound_format'] as $name => $value ) {
         if ( $value == "true" ) {
            print $name . "<br/>";
        }
    }
    print "</p>";
} else
{
    print "device not found";
}
?>

The output of Listing 3-17 is:

Apple iPhone 4.0

Display:

320 x 480 : 65536 colors

dual orientation: 1

Supported Audio Formats:

aac

mp3

Device Image Output with Tera-WURFL

In our last example with Tera-WURFL, we will output a device image. First, we need to download an archive of device images from http://sourceforge.net/projects/wurfl/files/WURFL%20Device%20Images/. Then we need to unzip the file and place the contents into a web accessible folder. We will create a folder called device_pix in /Tera-WURFL/. We will be adding to our previous example in Listing 3-17. First we need to include the new utility file, and then we can add the code to fetch the appropriate device image and display it. See Listing 3-18. The output is shown in Figure 3-2.

Listing 3-18. Displaying the Device Image

<?php

error_reporting ( E_ALL );
require_once ('Tera-WURFL/TeraWurfl.php'),
require_once ('Tera-WURFL/TeraWurflUtils/TeraWurflDeviceImage.php'),

$teraWURFL = new TeraWurfl ();
$iphone_ua = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us)?
AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";

if ($teraWURFL->getDeviceCapabilitiesFromAgent ( $iphone_ua )) {
        $brand_name = $teraWURFL->getDeviceCapability ( "brand_name" );
        $model_name = $teraWURFL->getDeviceCapability ( "model_name" );
        $model_extra_info = $teraWURFL->getDeviceCapability ( "model_extra_info" );
        
        //output fields that interest us
        print "<h3>" . $brand_name . " " . $model_name . " " . $model_extra_info . "</h3>";
        
        //image
        $image = new TeraWurflDeviceImage ( $teraWURFL );
        //location on server
        $image->setBaseURL ( '/Tera-WURFL/device_pix/' );
        //location on filesystem
        $image->setImagesDirectory ( $_SERVER ['DOCUMENT_ROOT'].
                                    '/Tera-WURFL/device_pix/' );

        $image_src = $image->getImage ();
        if ($image_src) {
                print '<img src="' . $image_src . '"/>';
        } else {
                echo "No image available";
        }

        //display information
        print "<p><strong>Display: </strong><br/>";
        print $teraWURFL->getDeviceCapability ( 'resolution_width' ) . " x "; //width
        print $teraWURFL->getDeviceCapability ( 'resolution_height' ) . " : "; //height
        print $teraWURFL->getDeviceCapability ( 'colors' ) . ' colors<br/>';
        print "dual orientation: " . $teraWURFL->getDeviceCapability ( 'dual_orientation' );
        print "</p>";
        //audio information
        print "<p><strong>Supported Audio Formats:</strong><br/>";
        
        foreach ( $teraWURFL->capabilities ['sound_format'] as $name => $value ) {
                if ($value == "true") {
                        print $name . "<br/>";
                }
        }
        print "</p>";
} else {
        print "device not found";
}
?>
images

Figure 3-2. Output of Listing 3-18, displaying the device image

Rendering Tools

To dynamically adjust content on different mobile devices we can use several tools. These include abstract markup using the Wireless Abstraction Library (WALL), automatic image resizing and CSS media properties.

WALL

In addition to the WURFL, Luca Passani is also responsible for the creation of WALL. WALL is a library that abstracts the markup in mobile devices. What exactly does this mean? Well, first you need to know that, unlike the content found on normal desktop browsers, which is written in HTML or XHTML, there are more markup variants with greater discrepancy on mobile devices.

Some of the most common markup schemes available are the following:

  • XHTML MP (Mobile Profile)
  • CHTML (Compact HTML)
  • HTML

The intersection of acceptable tags across all of these markup languages is very limited. For example, the line break tag displayed as <br> instead of <br/>, or vice versa, may be ignored or cause an error depending on the markup used.

With WALL, we can markup the line break tag as <wall:br/>. With WURFL, we can find the desired markup of the device by finding the preferred_markup capability. With this information, WALL will render the appropriate markup for the device as either <br> or <br/>.

WALL was originally written for Java Servlet Pages (JSP). The library WALL4PHP, available at http://laacz.lv/dev/Wall/, was written to be used with PHP. There is also an updated version of the library, maintained by the Tera-WURFL developers and available at https://github.com/kamermans/WALL4PHP-by-Tera-WURFL. We will use the original implementation for the following examples. Detailed instructions for integrating WALL with WURFL can be found at http://www.tera-wurfl.com/wiki/index.php/WALL4PHP.

A PHP file with WALL might look like Listing 3-19.

Listing 3-19. Document with WALL Markup

<?php require_once('WALL4PHP/wall_prepend.php'), ?>
<wall:document><wall:xmlpidtd />
<wall:head>
    <wall:title>WALL is Cool</wall:title>
</wall:head>
<wall:body>
    <wall:h1>A header</wall:h1>    
    <wall:block>This will be a paragraph in HTML</wall:block>    
    <wall:menu autonumber="true">
       <wall:a href="http://urlA">A</wall:a>
       <wall:a href="http://urlB">B</wall:a>
    </wall:menu>
</wall:body>
</wall:document>

Depending on the user-agent it would render differently. If the device supports HTML, the markup could be output as shown in Listing 3-20.

Listing 3-20. Rendered Markup of a Device That Supports HTML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
  "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>WALL is Cool</title>
</head>
<body>
<h1>A header</h1>
<p>This will be a paragraph in HTML</p>
<ol>
      <li><a accesskey="1" href="urlA">A</a></li>
      <li><a accesskey="2" href="urlB">B</a></li>
</ol>
</body>
</html>

Image Resizing

Another WURFL utility is the PHP Image Rendering library available at http://wurfl.sourceforge.net/utilities/dwld/ImageAdapter.zip. This utility works with WURFL to take a source image and generate an appropriately sized output image for display. If necessary, the image will also be converted to a format that the device supports. This utility requires that you have the GD graphics library, available at http://php.net/manual/en/book.image.php, installed for PHP.

Instructions for setting up the PHP Image Rendering library are at http://wurfl.sourceforge.net/utilities/phpimagerendering.php.

The basic outline is as follows:

  1. Creating a new database
  2. Altering DBConfig.php

Once the database is set up, we just need to provide an image and target user agent. See Listing 3-21.

Listing 3-21. Code Based on the ImageAdapter Library File example.php, to Output Images with Two Different User Agents

<?php
error_reporting ( E_ALL ^ E_DEPRECATED);
require_once ('ImageAdapter/imageAdaptation.php'),

$base_image = 'ImageAdapter/imgc/eye.jpg';

$iphone_ua = "Mozilla/4.0 (compatible; MSIE 4.01;
            Windows CE; PPC; 240x320; HP iPAQ h6300)";
$img = convertImageUA ( $base_image, $iphone_ua );
if ( $img ) {
        print "<img src="$img"><br/>";
}

$trident_ua = "Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; HTC; 7 Mozart; Orange)";
$img = convertImageUA ( $base_image, $trident_ua );

if ( $img ) {
        print "<img src="$img">";
}
?>
images

Figure 3-3. Top image: iPhone UA; Bottom image: Trident UA

images Note If Listing 3-21 is not run in the same directory as the WURFL library files, then you will need to adjust the relative include paths of the files wurfl_class.php, wurfl_config.php, and imageAdapation.php. eg) Changing require_once('./wurfl_config.php'), to require_once('/ImageAdapter/wurfl_config.php'),

This utility is showing its age, as it uses the deprecated ereg_replace and has some sloppy code style. However, it does work and demonstrates the power that is available by using WURFL capabilities.

Responsive CSS

To make web design more responsive, we can use fluid grid layouts and have images resize like in the above section. We can also use mobile specific stylesheets. A recent advancement in CSS3 is media queries. The properties that can be queried are width, height, device-width, device-height, orientation, aspect-ratio, device-aspect-ratio, color, color-index, monochrome, resolution, scan and grid. See Listing 3-22.

Listing 3-22. Sample Device Property Media Queries

   @media screen and (min-device-width:400px) and (max-device-width:600px){
     /* limit device width */
   }
   @media screen and (orientation:landscape){
    /* good for flippable devices like the iPad and kindle */
   }

In-depth coverage of CSS is beyond the scope of this book, but there is an excellent article available at www.netmagazine.com/tutorials/adaptive-layouts-media-queries. All of these techniques can improve the mobile display of a website. More information on the CSS3 specification of media queries is available at www.w3.org/TR/css3-mediaqueries.

Emulators and SDKs

To aid limited budgets that can not afford physical phones to test on and for all around ease of use, many emulators and software developer kits (SDKs) exist for mobile devices. Some only emulate a single device, while others can emulate several at a time. Here are a few links:

Developing on an Android

Google's Android operating system can run Java and native C code. The Scripting Layer For Android (SL4A) project available at http://code.google.com/p/android-scripting/ supports scripting languages on the Android. However, PHP is not one of the scripting languages officially supported at this time.

To develop applications on an Android, we can use the open source PHP for Android project, available at www.phpforandroid.net/. This project provides unofficial support for PHP within SL4A by providing an Android Package (APK) file.

Adobe Flash Builder for PHP

Very recently, Zend announced that it has teamed up with Adobe to bring PHP support into Flash Builder 4.5 (see Figure 3-4). More information about Flash Builder for PHP can be found at www.zend.com/en/products/studio/flash-builder-for-php/. Flash Builder for PHP integrates Zend Studio in the IDE. Flex can be used on the front end with a PHP backend.

The IDE strives to expediate development and to increase the ability for mobile code to be cross-platform. It can even cross-compile Flex code to run natively on iOS devices such as the iPhone and iPad.

images

Figure 3-4. Flash Builder announcement page on the Zend website

QR Codes

QR (Quick Response) codes are a type of 2D barcode. They were introduced in Japan almost twenty years ago to help keep track of automobile parts. Modern mobile devices with built-in cameras have led to the global popularity of QR codes.

QR codes often represent a URL but can contain a larger amount of text. We will show how to easily generate QR codes with three different libraries. Two of the libraries, TCPDF and Google Chart API, are covered in more depth in Chapter 10.

The first library we will touch on here, and generate QR codes with, TCPDF, is available at www.tcpdf.org/. With TCPDF, we can generate QR Codes as part of a PDF, but can not output directly to standalone image files. See Listing 3-23.

Listing 3-23. Generating a QR Code Inside of a PDF with TCPDF

<?php

error_reporting(E_ALL);
require_once('/tcpdf/config/lang/eng.php'),
require_once('/tcpdf/tcpdf.php'),

$pdf = new TCPDF();     //create TCPDF object
$pdf->AddPage();        //add a new page
$pdf->write2DBarcode( 'Hello world qrcode', 'QRCODE' );
//write 'Hello world qrcode' as a QR Code
$pdf->Output( 'qr_code.pdf', 'I' ); //generate and output the PDF
?>
images

Figure 3-5. QR Code for the string “Hello world qrcode.” The image should appear identical when produced by any of the libraries.

To save a QR code to a file, we can use the library phpqrcode, which is available at http://phpqrcode.sourceforge.net/index.php. See Listing 3-24.

Listing 3-24. Generating a QR Code to an Image File or Direct to Browser with phpqrcode

<?php
require_once('phpqrcode/qrlib.php'),

QRcode::png( 'Hello world qrcode', 'qrcode.png' ); //to a file
QRcode::png( 'Hello world qrcode' ); //direct to browser
?>

We can also use the Google Chart API wrapper available at http://code.google.com/p/gchartphp/. See Listing 3-25.

Listing 3-25. QR Code Generation with qrcodephp

<?php
error_reporting(E_ALL);
require_once ('GChartPhp/gChart.php'),

$qr = new gQRCode();
$qr->setQRCode( 'Hello world qrcode' );
echo "<img src="".$qr->getUrl()."" />";
?>

Summary

In this chapter, we discussed detecting mobile devices and their capabilities. There is no perfect device detection system in existence at the moment, but what we have is fairly reliable. That being said, it is up to the programmer to be vigilant and keep up to date files – whether using browscap, WURFL, or another system.

We also showed tools that can abstract markup, automatically resize images and fluidly resize our content. Whenever possible use tools that do the work for us. The work can be to know what a device is capable of, how to transform existing styles, images and markup. Automation and assistance are both great things that should be used and embraced in all areas of development.

Mobile technology is still expanding and the methods of development are also rapidly adjusting. To become a good mobile developer and stay one, you need to keep abreast with best practices, latest technologies, and emerging SDKs and APIs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset