dotMobimobiThinkingmobiForgemobiReadyDeviceAtlasgoMobi
background image

Device Detection in the Cloud: DeviceAtlas Personal

Section Feature Image
Posted by ruadhan - 19 Jun 2010
Twitter share icon Facebook share icon Google Plus share icon

In this article we offer full tutorial on how to use the preview release of the service. So what is DA Personal?

The purpose of DeviceAtlas Personal is to make device detection even easier. The main difference between DA Personal and DeviceAtlas, is that Personal is a Web service. It works as follows: a user visits your Web site on his mobile device. You then forward the User-Agent HTTP request header to the DA Personal service, and the response you receive will contain information about the user's device. That's it!

Note that this is a preview version of the service, and right now we make no guarantees about stability, performance, or uptime. Note also that device detecton is currently based on the User-Agent string, but we will be adding UAProf support soon too. We invite you to take the service for a spin, and let us know what you think, and if it appeals to you.

Using DA Personal

So DA Personal sounds good. No need to install anything, no need to update device data, so how does it work?

Since DA Personal offers a Web service API, all you have to do to use it is to send an HTTP request and handle the response. This means that you can use any server technology you want with the service. In this tutorial, we use PHP (a Python example is forthcoming too!)

For those eager to get up and running right away, here is some quick code to get you going. (A bit more detail is provided later for those who don't mind reading). The code below relies on the file_get_contents function, but you can achieve the same with cURL if this function is not available in your setup.

<?php
define('DA_URI', 'http://deviceatlas.appspot.com/query');
$da_json = @file_get_contents(DA_URI . "?User-Agent=" . urlencode($_SERVER["HTTP_USER_AGENT"]));
  if ($da_json !== FALSE) {
    $da_results = array_merge(json_decode($da_json, TRUE), $da_results);
    $da_results['_source'] = 'webservice';
  } else {
    $da_results['_error'] .= "Error fetching DeviceAtlas data from webservice.\n";
  }
?>

The real work is done in the call to the DA Personal service:

$da_json = @file_get_contents(DA_URI . "?User-Agent=" . urlencode($_SERVER["HTTP_USER_AGENT"]));

We access the User-Agent header of the requesting device with $_SERVER["HTTP_USER_AGENT"], and we send this header to the DA Personal service specified by DA_URI.

After the code above is executed, the response from the DA personal service comes back in JSON format, and we store it in an array called $da_results. For the purpose of this example, we can output this array to the browser, and it should tell us a few things about the device that we are on. So, the code to output to the browser follows:

<h1>DA Personal Test</h1>
 
<?php
//Output results
if(isset($da_results['_error'])){
  echo sprintf("<p>%s</p>", nl2br($da_results['_error']));
} else {
  echo "<p>User-Agent: {$_SERVER["HTTP_USER_AGENT"]}</p>";
  echo "<p>Read from {$da_results['_source']}</p>";
  echo sprintf("<pre>%s</pre>", print_r ($da_results, true));
}
echo "<p>Time taken: ".(microtime(1) - $start_time)." secs</p>";
?>

The results of viewing this page on a mobile device (an iPhone, zoomed, in this case) is shown to the right. The properties returned from the DeviceAtlas database are:

  • displayWidth
  • isBrowser
  • mobileDevice
  • displayHeight

Equipped with this information about the user's mobile device, your app can now go about adapting content for the device. We include an example toward the end of this article to show how you would resize images to fit the screen width of the requesting device.

That's it! The code above is all you need to get started with DA Personal. But read on to find out about results caching, and to see an image resizing example.

Caching

It is also possible, and recommended, to implement caching with DA Personal, so that multiple similar requests are not made to the API unnecessarily. In the following code sample we demonstrate how to cache both using cookies and by storing the information sent back by DeviceAtlas as a cached file.

If we set the DA_USE_COOKIES flag, then the code below will store the device data in a cookie identified by Mobi_Mtld_DA_Properties. If, on a subsequent request, that cookie is detected with the request, then we simply read the device data from the cookie, obviating the need for a request to the DA Personal service. So using cookies in this way will give us per-user caching.

if(DA_USE_COOKIES && isset($_COOKIE['Mobi_Mtld_DA_Properties'])){
  $da_results = (array) json_decode($_COOKIE['Mobi_Mtld_DA_Properties'], TRUE);
  $da_results['_source'] = 'cookie';
}

If we set the DA_USE_CACHE flag, then caching will be performed using local files. For each User-Agent header that is sent to DA Personal, we store the device data in a local file. If we encounter the same User-Agent header again, our app will now read from the file instead of making the HTTP request to the DA Personal server. It may not always be possible to use file caching, for instance if you do not have file system write access on your server.

if(DA_USE_CACHE && $da_results['_source'] === 'none'){
  $da_cache_file = md5($_SERVER["HTTP_USER_AGENT"]) . '.json';
  if(!file_exists(DA_CACHE_DIR) && !@mkdir(DA_CACHE_DIR)){
    $da_results['_error'] = "Unable to create cache directory: " . DA_CACHE_DIR . "\n";
  } else {
    $da_json = @file_get_contents(DA_CACHE_DIR . $da_cache_file);
    if ($da_json !== FALSE) {
      $da_results = (array) json_decode($da_json, TRUE);
      $da_results['_source'] = 'cache';
      if(DA_USE_COOKIES){
        setcookie('Mobi_Mtld_DA_Properties', $da_json);
      }
    }
  }
}

The best performance will be experienced when both both cookie and file based caching are turned on. You can tweak this to suit your particular setup.

Image resizing example

As an example of DA Personal in action to get you started, we demonstrate how you might use this service to resize images on your Web site to match the width of the screen of the requesting device, so that you can avoid sending images that are too large to the device. Note that we have left the caching code out of this example for brevity, although it is included in the listing at the bottom of this article.

First we start off as before, by sending the User-Agent header of the device the the DA Personal service.

$da_json = @file_get_contents(DA_URI . "?User-Agent=" . urlencode($_SERVER["HTTP_USER_AGENT"]));

To resize the image, to the width of the requesting device, we call another script we have written (explained below). We pass into the script the name of the image we want to resize (we use the mobiForge logo), and importantly, we also pass in the displayWidth property returned by DeviceAtlas, stored in $da_results['displayWidth'].

<img src="resize_image.php?image=http://mobiforge.com/logo.png&width=<?php print $da_results['displayWidth']?> />

That's it from the DeviceAtlas end of things, we now go through the image resizing script, which is more of a PHP exercise than DeviceAtlas specific, but we include it here for completeness.

First we retrieve the image name, and the desired image size from the request:

$imagepath=$_GET['image'];
$display_width = $_GET['width'];

Next we determine some basic information about the image: width, height, and type (JPEG, GIF, or PNG):

$image_info = getimagesize($imagepath);
$orig_width = $image_info[0];
$orig_height = $image_info[1];
$image_type = $image_info[2];

We now load the image into memory using the appropriate PHP function dependent on the image type:

if( $image_type == IMAGETYPE_JPEG ) {
  $image = imagecreatefromjpeg($imagepath);
} elseif( $image_type == IMAGETYPE_GIF ) {
  $image = imagecreatefromgif($imagepath);
} elseif( $image_type == IMAGETYPE_PNG ) {
  $image = imagecreatefrompng($imagepath);
}

In this example, we are going to resize the image to fit the width of the requesting device. First we will check if the image already fits on to the device screen. If so, we leave it as is. Otherwise, we scale the image to fit the display width, by determining the ratio of original width to display width, and then by scaling the height accordingly:

if($orig_width > $display_width) {
  $ratio = $display_width/$orig_width;
  $display_height = $ratio * $orig_height;

Next, create a new image in memory with the desired dimensions, and we use the imagecopyresampled function to resize the original image and copy into our new image:

  $display_image=imagecreatetruecolor($display_width, $display_height);
  imagecopyresampled($display_image, $image, 0, 0, 0, 0, $display_width, $display_height, $orig_width, $orig_height);

Finally, we write the image to output, ensuring that we write the correct Content-type header:

switch($image_type) {
  case IMAGETYPE_JPEG:
    header('Content-Type: image/jpeg');
    imagejpeg($display_image);
        break;
  case IMAGETYPE_GIF:
    header('Content-Type: image/gif');
    imagegif($display_image);
        break;
  case IMAGETYPE_PNG:
    header('Content-Type: image/png');
    imagepng($display_image);
        break;
}

And that's it! Example images are given below, showing how the page is rendered on various devices. As expected, the image occupies the width of the screen for each device.

  
Image resizing examples: Nokia n95 (left), Nokia n70 (middle), Sharp GX10 (right)

The full script is listed at the end.

Conclusion

In this tutorial, we have demonstrated how to do device detection with DeviceAtlas Personal. We have also demonstrated how to use DeviceAtlas Personal to do some simple image adaptation so that image width matches the width of the requesting device, a common task for mobile Web developers. There are of course many other possible uses for this service - it's limited only by your imagination! What would you do? Try it out, and let us know how you get on.

We note also that the device detection here is currently based on the User-Agent header alone, although support for use the UAProf URL will also be added soon to help with the detection. We urge you to take the API for a test spin and let us know what you think, and tell us how you are using it. Please leave any feedback in the DeviceAtlas forum.

Image resizing full code listing

Below are the listings for the two PHP files used in the image resizing example. Note that the first, da_personal.php contains the code to cache the results from the DA Personal server. An obvious improvement would be to cache the resized images too, so that CPU is not wasted resizing to the same size over and over.

da_personal.php:

<?php
error_reporting(E_ALL);
$start_time = microtime(1);
/**
 * DA Personal - Start
 *
 * NB: If DA_USE_COOKIES is TRUE this snippet must appear before any output is returned by PHP.
 *
 * Results:
 * $da_results contains the DeviceAtlas query results
 * $da_results['_error'] not set on success, contains error messages on failure (1 per line).
 * $da_results['_source'] will be 'cookie', 'cache', 'webservice' or 'none'.
 */
define('DA_USE_COOKIES', TRUE);
define('DA_USE_CACHE', TRUE);
define('DA_CACHE_DIR', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'DeviceAtlasCache' . DIRECTORY_SEPARATOR);
define('DA_URI', 'http://deviceatlas.appspot.com/query');
$da_results = array('_source' => 'none');
 
if(DA_USE_COOKIES && isset($_COOKIE['Mobi_Mtld_DA_Properties'])){
  $da_results = (array) json_decode($_COOKIE['Mobi_Mtld_DA_Properties'], TRUE);
  $da_results['_source'] = 'cookie';
}
if(DA_USE_CACHE && $da_results['_source'] === 'none'){
  $da_cache_file = md5($_SERVER["HTTP_USER_AGENT"]) . '.json';
  if(!file_exists(DA_CACHE_DIR) && !@mkdir(DA_CACHE_DIR)){
    $da_results['_error'] = "Unable to create cache directory: " . DA_CACHE_DIR . "\n";
  } else {
    $da_json = @file_get_contents(DA_CACHE_DIR . $da_cache_file);
    if ($da_json !== FALSE) {
 
      $da_results = (array) json_decode($da_json, TRUE);
      $da_results['_source'] = 'cache';
      if(DA_USE_COOKIES){
        setcookie('Mobi_Mtld_DA_Properties', $da_json);
      }
    }
  }
}
if($da_results['_source'] === 'none'){
  $da_json = @file_get_contents(DA_URI . "?User-Agent=" . urlencode($_SERVER["HTTP_USER_AGENT"]));
  if ($da_json !== FALSE) {
    $da_results = array_merge(json_decode($da_json, TRUE), $da_results);
    $da_results['_source'] = 'webservice';
    if(DA_USE_COOKIES){
      setcookie('Mobi_Mtld_DA_Properties', $da_json);
    }
    if(DA_USE_CACHE){
      if(@file_put_contents(DA_CACHE_DIR . $da_cache_file, $da_json) === FALSE){
        $da_results['_error'] .= "Unable to write cache file " . DA_CACHE_DIR . $da_cache_file . "\n";
      }
    }
  } else {
    $da_results['_error'] .= "Error fetching DeviceAtlas data from webservice.\n";
  }
}
// DA Personal - End
?>
<html>
  <head><title>DA Image resizing</title></head>
  <body>
  <h1>Image resizing</h1>
    <div>
    <?php if(!array_key_exists('displayWidth', $da_results)) $da_results['displayWidth']=1000; ?>
      <img src="resize_image.php?image=http://mobiforge.com/logo.png&width=<?php print $da_results['displayWidth']?>" />
    </div>
  </body>
</html>

resize_image.php:

<?php
$imagepath=$_GET['image'];
$display_width = $_GET['width'];
$image_info = getimagesize($imagepath);
$orig_width = $image_info[0];
$orig_height = $image_info[1];
$image_type = $image_info[2];
 
if( $image_type == IMAGETYPE_JPEG ) {
  $image = imagecreatefromjpeg($imagepath);
} elseif( $image_type == IMAGETYPE_GIF ) {
  $image = imagecreatefromgif($imagepath);
} elseif( $image_type == IMAGETYPE_PNG ) {
  $image = imagecreatefrompng($imagepath);
}
 
 
//In this example we don't care about height
//We just want to scale image so it fits to width
//And if the width is already < screen width we do nothing
if($orig_width > $display_width) {
  $ratio = $display_width/$orig_width;
  $display_height = $ratio * $orig_height;
 
  $display_image=imagecreatetruecolor($display_width, $display_height);
  imagecopyresampled($display_image, $image, 0, 0, 0, 0, $display_width, $display_height, $orig_width, $orig_height);
 
}
else $display_image = $image;
 
 
switch($image_type) {
  case IMAGETYPE_JPEG:
    header('Content-Type: image/jpeg');
    imagejpeg($display_image);
        break;
  case IMAGETYPE_GIF:
    header('Content-Type: image/gif');
    imagegif($display_image);
        break;
  case IMAGETYPE_PNG:
    header('Content-Type: image/png');
    imagepng($display_image);
        break;
}
?>

Download source code:

AttachmentSize
da_personal.php.txt2.52 KB
resize_image.php.txt1.31 KB

Posted by ruadhan - 19 Jun 2010

ruadhan's picture

Mobile Web Guy

@rodono
+RuadhanODonoghue

Posted by MobilePhoneGames 5 years ago

Hi Ruadhan,
Nice..
Do we have opportunity to optimize image on the fly?
And what about quality of resized image, if original image saved as 8 bit png for example?
thx

Mobile Cell Phone Games Download.
http://mobile-phone-games.mobi

Posted by catchytech 5 years ago

1) Will DA-personal cost money? If so I think many users will still prefer WURFL.
2) In the php example what about caching resized images. I am using .NET and saving (caching) resized images for later use, but some image sizes are very rare and not worth caching. What do you think about it?

CatchyTech.mobi

Posted by ruadhan 5 years ago

(1) DA Personal is free for non-commercial use.
(2) It's definitely worth caching images. What works best for you will depend on the devices accessing your site, but disk storage is cheap, and the images targeted at mobile devices are small...

Ruadhan O'Donoghue
Editor, mobiForge

Posted by jsaydm 5 years ago

1. Can you give us a guide on pricing for commercial use
2. Can we use it for development purposes in the meantime to see if it meets our needs

Posted by ruadhan 5 years ago

1. (via dotMobi Product Manager) DeviceAtlas Personal may not be used for commercial use; it can be used to evaluate DeviceAtlas as a whole, and establish whether it adds value for a site, but if usage on a commercial site is desired it is recommended to use the standard DeviceAtlas product (per deviceatlas.com). DeviceAtlas Personal is not designed to be as fast, or to provide the scalability or reliability that would typically be required for a commercial site. In addition, the commercial version of DeviceAtlas provides considerably more data on the visiting device, which can be used to further enhance the visitor's experience.

2. Yes, fine to use during development! Of course there is also a free Developer license for the full DeviceAtlas product: http://deviceatlas.com/#free

Hope this helps!

Ruadhan O'Donoghue
Editor, mobiForge

Posted by jsaydm 5 years ago

Thanks that clears that up.

Posted by darragh 5 years ago

Typically I find when I'm developing a mobile web site, the only 'device' attribute I'm interested in is the width of the 'browser'. Although most device databases contain a 'displayWidth' property, this is usually the screen width of the phone, and not the browser. WURFL contains the max_image_width property, and DeviceAtlas has the Usable Display Width property. Howerver, the above service only returns the displayWidth property. This seems quite poor, given that in your example you're using this property to resize an image for display in a web page...my guess is that this would on many phones result in a small amount of horizontal scrolling.

Is there some reason you return such a limited subset of the deviceAtlas ?

Otherwise, I really like how you've designed and implemented this web service.

Posted by OkInteractif 5 years ago

DARRAGH I totally agree with that. The usable Display Width property worth more than just the displayWidth.

As for the da_personal.php example, I wanted to give it a try but stupidly it seems that the cookie don't remember the json data ... The first time it loads it's just like your example but when I reload the page I only see "Array( [_source] => cookie)" I tried to reach the displayWidth property directly but with no results ... However the code seems to be fine?

Posted by northernguy69 5 years ago

I've used deviceAtlas and it's a great tool for testing mobile sites. Another company that is definitely worth mentioning when it comes to device detection and user agent profiles is "Mobile Phone Wizards". Their product "DetectRight" (www.detectright.com) is a simple web based API that essentially allows you to get a large amount of descriptive details about a device that comes to your site. I use it on mobile sites for the company I work for and I would definitely suggest it to anyone that needs device detection software to take a look at their product.

Regards

Posted by Milind 4 years ago

Hi

I am using DA personal webservice and i want information about vendor & model of mobile device, how can i pull that info from this webservice.

Any help will be appreciated.

Thanks in advance.

Posted by lajeeshk 4 years ago

i use $_SERVER['HTTP_USER_AGENT'] for detecting mobile device model .but only some browsers are returns device name and model number like uc web and nokia in built browser.opera mini does not returns the device name and model no..how to resolve this issue