Previously on mobiForge Ronan posted about a lightweight approach to device detection using regular expressions in PHP. Since this is still an approach widely adopted by many web developers today, we feel that it’s about time we revisited the original article.
For those new to the subject, the approach works by matching User-Agent strings of mobile devices using regular expressions. As we mentioned in the original article, using a PHP regex solution to detect devices can be a good solution for certain use cases. For example, for smaller websites without a high volume of traffic, or where the site owner is not too concerned about detecting their mobile traffic with very high accuracy, or where the goal is simple mobile or tablet redirection.
In this article, we provide an updated version of the original algorithm which includes explicit tablet detection, for those who want to optimise for their tablet visitors, and we also broaden the original regex patterns to catch some of the more recent mobile devices not detected by the original.
But before we jump in, there are limitations that you should be aware of before choosing this option.
- Accuracy – Regex User-Agent matching can work well in the general case, but will inevitably fail to recognise some portion of devices correctly, e.g. certain Android tablets. And while it is might be possible to add more specific patterns to the regex to match edge-cases by matching specific model numbers, this has the disadvantage of reducing the perfomance of the detection, and will have knock-on performance implications for your site
- Performance – Regular expressions can be slow to execute, particularly for complicated patterns. If performance is a key factor for you, then this is not the way to go
- Maintenance – The regex patterns will need to be updated regularly to keep up to date with new devices that may not be already covered
- Device capabilities – If you need anything more than simple traffic routing (mobile/tablet/desktop), for instance if you need to know device properties such as screen size, memory limit, HTML5 support, and so on, then this is not the solution for you
So, with those caveats out of the way, time for the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php $tablet_browser = 0; $mobile_browser = 0; if (preg_match('/(tablet|ipad|playbook)|(android(?!.*(mobi|opera mini)))/i', strtolower($_SERVER['HTTP_USER_AGENT']))) { $tablet_browser++; } if (preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone|android|iemobile)/i', strtolower($_SERVER['HTTP_USER_AGENT']))) { $mobile_browser++; } if ((strpos(strtolower($_SERVER['HTTP_ACCEPT']),'application/vnd.wap.xhtml+xml') > 0) or ((isset($_SERVER['HTTP_X_WAP_PROFILE']) or isset($_SERVER['HTTP_PROFILE'])))) { $mobile_browser++; } $mobile_ua = strtolower(substr($_SERVER['HTTP_USER_AGENT'], 0, 4)); $mobile_agents = array( 'w3c ','acs-','alav','alca','amoi','audi','avan','benq','bird','blac', 'blaz','brew','cell','cldc','cmd-','dang','doco','eric','hipt','inno', 'ipaq','java','jigs','kddi','keji','leno','lg-c','lg-d','lg-g','lge-', 'maui','maxo','midp','mits','mmef','mobi','mot-','moto','mwbp','nec-', 'newt','noki','palm','pana','pant','phil','play','port','prox', 'qwap','sage','sams','sany','sch-','sec-','send','seri','sgh-','shar', 'sie-','siem','smal','smar','sony','sph-','symb','t-mo','teli','tim-', 'tosh','tsm-','upg1','upsi','vk-v','voda','wap-','wapa','wapi','wapp', 'wapr','webc','winw','winw','xda ','xda-'); if (in_array($mobile_ua,$mobile_agents)) { $mobile_browser++; } if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'opera mini') > 0) { $mobile_browser++; //Check for tablets on opera mini alternative headers $stock_ua = strtolower(isset($_SERVER['HTTP_X_OPERAMINI_PHONE_UA'])?$_SERVER['HTTP_X_OPERAMINI_PHONE_UA']:(isset($_SERVER['HTTP_DEVICE_STOCK_UA'])?$_SERVER['HTTP_DEVICE_STOCK_UA']:'')); if (preg_match('/(tablet|ipad|playbook)|(android(?!.*mobile))/i', $stock_ua)) { $tablet_browser++; } } if ($tablet_browser > 0) { // do something for tablet devices print 'is tablet'; } else if ($mobile_browser > 0) { // do something for mobile devices print 'is mobile'; } else { // do something for everything else print 'is desktop'; } ?> |
As in our previous article, the code is based on work by Andy Moore. The approach taken for tablet detection is a broad, (mostly) generic matching pattern. It should perform reasonably well, and will be suitable for you if accurate detection of every single tablet device is not critical. It will likely fail on a certain portion of tablets that are difficult to distinguish from their mobile counterparts without specifying individual model numbers.
We also added some special treatment for the proxy-based browser Opera Mini, which has recently started to send the new HTTP_DEVICE_STOCK_UA
header that helps to identify the underlying device.
It should also perform reasonably well at detecting mobile browsers, but once again, if you require high accuracy, performance, or device properties, then you should look to a more dedicated device detection solution.