PHP Classes

File: MobileUserAgent.php

Recommend this page to a friend!
  Classes of Craig Manley  >  MobileUserAgent  >  MobileUserAgent.php  >  Download  
File: MobileUserAgent.php
Role: Class source
Content type: text/plain
Description: The main class. Complete package with docs is available here: http://sourceforge.net/projects/mobileuseragent/
Class: MobileUserAgent
Extract information from mobile browser identifier
Author: By
Last change: Fixed userAgent() method.
Date: 17 years ago
Size: 21,986 bytes
 

Contents

Class file image Download
<?php // +----------------------------------------------------------------------+ // | Mobile user agent string parsing class for PHP5. | // | Copyright (C) 2004 Craig Manley | // +----------------------------------------------------------------------+ // | This library is free software; you can redistribute it and/or modify | // | it under the terms of the GNU Lesser General Public License as | // | published by the Free Software Foundation; either version 2.1 of the | // | License, or (at your option) any later version. | // | | // | This library is distributed in the hope that it will be useful, but | // | WITHOUT ANY WARRANTY; without even the implied warranty of | // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | // | Lesser General Public License for more details. | // | | // | You should have received a copy of the GNU Lesser General Public | // | License along with this library; if not, write to the Free Software | // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | // | USA | // | | // | LGPL license URL: http://opensource.org/licenses/lgpl-license.php | // +----------------------------------------------------------------------+ // | Author: Craig Manley | // +----------------------------------------------------------------------+ // // $Id: MobileUserAgent.php,v 1.6 2004/12/21 15:07:29 cmanley Exp $ // /** * @author Craig Manley * @copyright Copyright 2004, Craig Manley. All rights reserved. * @version $Revision: 1.6 $ * @package com.craigmanley.classes.mobile.MobileUserAgent */ /** * Parses a mobile user agent string into it's basic constituent parts, the * most important being vendor and model. * * One reason for doing this would be to use this information to lookup vendor-model * specific device characteristics in a database. Of course you could use user agent * profiles for this, but not all mobile phones have (valid) user agent profiles, especially * the older types of mobile phones. * * Another reason would be to detect if the visiting client is a mobile handset. You could do * it like this: * <pre> * require_once('MobileUserAgent.php'); * $mua = new MobileUserAgent(); * $is_client_mobile = $mua->success(); * </pre> * * Some references: * <ul> * <li>{@link http://www.handy-ortung.com }</li> * <li>{@link http://www.mobileopera.com/reference/ua }</li> * <li>{@link http://www.appelsiini.net/~tuupola/php/Imode_User_Agent/source/ }</li> * <li>{@link http://www.zytrax.com/tech/web/mobile_ids.html }</li> * <li>{@link http://webcab.de/wapua.htm }</li> * <li>{@link http://www.nttdocomo.co.jp/english/p_s/i/tag/s2.html }</li> * <li>{@link http://test.waptoo.com/v2/skins/waptoo/user.asp }</li> * </ul> * * @package com.craigmanley.classes.mobile.MobileUserAgent */ class MobileUserAgent { // Private members private $useragent = null; private $vendor = null; private $model = null; private $version = null; private $imode_cache = null; private $screendims = null; private $is_standard = false; private $is_imode = false; private $is_mozilla = false; private $is_rubbish = false; private $is_series60 = null; /** * Constructor. * * @param string $useragent Optional useragent string. If null, environment variable HTTP_USER_AGENT is used. */ function __construct($useragent = null) { if (!(isset($useragent) && strlen($useragent))) { if (!isset($_SERVER['HTTP_USER_AGENT'])) { throw new Exception('Environment variable HTTP_USER_AGENT is missing!'); } $useragent = $_SERVER['HTTP_USER_AGENT']; } $this->useragent = $useragent; $hash = $this->_parseUserAgent($useragent); if ($hash) { $this->vendor = $hash['vendor']; $this->model = $hash['model']; if (isset($hash['version'])) { $this->version = $hash['version']; } if (isset($hash['imode_cache'])) { $this->imode_cache = $hash['imode_cache']; } if (isset($hash['screendims'])) { $this->screendims = $hash['screendims']; } } } /** * Parses a standard mobile user agent string with the format vendor-model/version. * If no match can be made, FALSE is returned. * If a match is made, an associative array is returned containing the compulsory * keys "vendor" and "model", and the optional keys "version", and "screendims". * * Below are a few samples of these user agent strings: * <pre> * Nokia8310/1.0 (05.57) * NokiaN-Gage/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 * SAGEM-myX-6/1.0 UP.Browser/6.1.0.6.1.c.3 (GUI) MMP/1.0 UP.Link/1.1 * SAMSUNG-SGH-A300/1.0 UP/4.1.19k * SEC-SGHE710/1.0 * </pre> * * @param string $useragent User agent string. * @return mixed */ protected function _parseUserAgentStandard($useragent) { // Standard vendor-model/version user agents if (!preg_match('/^((ACER|Alcatel|AUDIOVOX|BlackBerry|CDM|Ericsson|LG\b|LGE|Motorola|MOT|NEC|Nokia|Panasonic|QCI|SAGEM|SAMSUNG|SEC|Sanyo|Sendo|SHARP|SIE|SonyEricsson|Telit|Telit_Mobile_Terminals|TSM)[- ]?([^\/\s\_]+))(\/(\S+))?/', $useragent, $matches)) { return false; } $both = $matches[1]; $vendor = $matches[2]; $model = $matches[3]; $version = null; if (count($matches) >= 6) { $version = $matches[5]; } // Fixup vendors and models. if ($vendor == 'ACER') { $vendor = 'Acer'; } elseif ($vendor == 'AUDIOVOX') { $vendor = 'Audiovox'; } elseif ($vendor == 'CDM') { $vendor = 'Audiovox'; $model = "CDM-$model"; } elseif ($vendor == 'Ericsson') { if ($model == 'T68_NIL') { $model = 'T68'; } } elseif (substr($vendor,0,2) == 'LG') { $vendor = 'LG'; if (preg_match('/^([A-Za-z\d]+)-/', $model, $m)) { // LGE510W-V137-AU4.2 $model = $m[1]; } } elseif ($vendor == 'MOT') { $vendor = 'Motorola'; $model = preg_replace('/[\._]$/', '', $model); } elseif ($vendor == 'PHILIPS') { $model = strtoupper($model); } elseif ($vendor == 'SAGEM') { if ($model == '-') { return false; } } elseif ($vendor == 'SEC') { $vendor = 'SAMSUNG'; $model = preg_replace('/\*.*$/','',$model); } elseif ($vendor == 'SIE') { $vendor = 'Siemens'; } elseif ($vendor == 'Telit_Mobile_Terminals') { $vendor = 'Telit'; } elseif ($vendor == 'TSM') { $vendor = 'Vitelcom'; $model = $both; } $result = array('vendor' => $vendor, 'model' => $model); if (isset($version)) { $result['version'] = $version; } return $result; } /** * Parses an i-mode user agent string. * If no match can be made, FALSE is returned. * If a match is made, an associative array is returned containing the compulsory * keys "vendor" and "model", and the optional keys "version", "imode_cache", * and "screendims". * * Below are a few samples of these user agent strings: * <pre> * portalmmm/1.0 m21i-10(c10) * portalmmm/1.0 n21i-10(c10) * portalmmm/1.0 n21i-10(;ser123456789012345;icc1234567890123456789F) * portalmmm/2.0 N400i(c20;TB) * portalmmm/2.0 P341i(c10;TB) * DoCoMo/1.0/modelname * DoCoMo/1.0/modelname/cache * DoCoMo/1.0/modelname/cache/unique_id_information * DoCoMo/2.0 modelname(cache;individual_identification_information) * </pre> * * @param string $useragent User agent string. * @return mixed */ protected function _parseUserAgentImode($useragent) { $vendors = array ( 'D' => 'Mitsubishi', 'ER' => 'Ericsson', 'F' => 'Fujitsu', 'KO' => 'Kokusai', // Hitachi 'M' => 'Mitsubishi', 'P' => 'Panasonic', // Matsushita 'N' => 'NEC', 'NM' => 'Nokia', 'R' => 'Japan Radio', 'S' => 'SAMSUNG', 'SH' => 'Sharp', 'SO' => 'Sony', 'TS' => 'Toshiba', ); // Standard i-mode user agents if (preg_match('/^(portalmmm|DoCoMo)\/(\d+\.\d+) ((' . implode('|',array_keys($vendors)) . ')[\w\-]+)\((c(\d+))?/i', $useragent, $matches)) { $result = array('vendor' => $vendors[strtoupper($matches[4])], 'model' => $matches[3], 'version' => $matches[2]); if ((count($matches) == 7) && strlen($matches[6])) { $result['imode_cache'] = $matches[6] + 0; } else { $result['imode_cache'] = 5; } return($result); } // DoCoMo HTML i-mode user agents elseif (preg_match('/^DoCoMo\/(\d+\.\d+)\/((' . implode('|',array_keys($vendors)) . ')[\w\.\-\_]+)(\/c(\d+))?/i', $useragent, $matches)) { // HTML 1.0: DoCoMo/1.0/modelname // HTML 2.0: DoCoMo/1.0/modelname/cache // HTML 3.0: DoCoMo/1.0/modelname/cache/unique_id_information $result = array('vendor' => $vendors[strtoupper($matches[3])], 'model' => $matches[2], 'version' => $matches[1]); if (count($matches) >= 6) { $result['imode_cache'] = $matches[5] + 0; } else { $result['imode_cache'] = 5; } return $result; } return false; } /** * Parses a Mozilla (so called) compatible user agent string. * If no match can be made, FALSE is returned. * If a match is made, an associative array is returned containing the compulsory * keys "vendor" and "model", and the optional keys "version", and "screendims". * * Below are a few samples of these user agent strings: * <pre> * Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 3650;424) Opera 6.10 [en] * Mozilla/4.0 (compatible; MSIE 6.0; Nokia7650) ReqwirelessWeb/2.0.0.0 * Mozilla/1.22 (compatible; MMEF20; Cellphone; Sony CMD-Z5) * Mozilla/1.22 (compatible; MMEF20; Cellphone; Sony CMD-Z5;Pz063e+wt16) * Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PPC; 240x320) * mozilla/4.0 (compatible;MSIE 4.01; Windows CE;PPC;240X320) UP.Link/5.1.1.5 * Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320) * Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; SmartPhone; 176x220) * Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; 240x320; PPC) * Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; Smartphone; 176x220; Mio8380; Smartphone; 176x220) * Mozilla/4.0 (MobilePhone SCP-8100/US/1.0) NetFront/3.0 MMP/2.0 * Mozilla/2.0(compatible; MSIE 3.02; Windows CE; Smartphone; 176x220) * Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS Series 60 42) Opera 6.0 [fr] * Mozilla/SMB3(Z105)/Samsung UP.Link/5.1.1.5 * </pre> * * @param string $useragent User agent string. * @return mixed */ protected function _parseUserAgentMozilla($useragent) { // SAMSUNG browsers if (preg_match('/^Mozilla\/SMB3\((Z105)\)\/(Samsung)/', $useragent, $matches)) { return(array('vendor' => strtoupper($matches[2]), 'model' => $matches[1])); } // Extract the string between the brackets. if (!preg_match('/^Mozilla\/\d+\.\d+\s*\(([^\)]+)\)/i', $useragent, $matches)) { return false; } $parts = preg_split('/\s*;\s*/', $matches[1]); // split string between brackets on ';' seperator. // Micro$oft PPC and Smartphone browsers. Unfortunately, one day, if history repeats itself, this will probably be the only user-agent check necessary. if ((count($parts) >= 4) && ($parts[0] == 'compatible') && ($parts[2] == 'Windows CE')) { $result = array('vendor' => 'Microsoft'); if (($parts[3] == 'PPC') || (strtolower($parts[3]) == 'smartphone')) { $result['model'] = 'SmartPhone'; if ((count($parts) >= 5) && preg_match('/^\d{1,4}x\d{1,4}$/i', $parts[4])) { $result['screendims'] = strtolower($parts[4]); } } elseif ((count($parts) >= 5) && (($parts[4] == 'PPC') || (strtolower($parts[4]) == 'smartphone'))) { $result['model'] = 'SmartPhone'; if (preg_match('/^\d{1,4}x\d{1,4}$/i', $parts[3])) { $result['screendims'] = strtolower($parts[3]); } } if (array_key_exists('model',$result)) { return $result; } } // Nokia's with Opera browsers or SonyEricssons. if ((count($parts) >= 4) && ($parts[0] == 'compatible') && preg_match('/^(Nokia|Sony)\s*(\S+)$/', $parts[3], $matches)) { if ($matches[1] == 'Sony') { $matches[1] = 'SonyEricsson'; } return(array('vendor' => $matches[1], 'model' => $matches[2])); } // SANYO browsers if ((count($parts) >= 1) && preg_match('/^MobilePhone ([^\/]+)\/([A-Z]+\/)?(\d+\.\d+)$/', $parts[0], $matches)) { // MobilePhone PM-8200/US/1.0 return(array('vendor' => 'Sanyo', 'model' => $matches[1], 'version' => $matches[3])); } // Nokias with ReqwirelessWeb browser if ((count($parts) >= 3) && ($parts[0] == 'compatible') && preg_match('/^(Nokia)\s*(\S+)$/', $parts[1], $matches)) { return(array('vendor' => $matches[1], 'model' => $matches[2])); } return false; } /** * Parses a non-standard mobile user agent string. * If no match can be made, FALSE is returned. * If a match is made, an associative array is returned containing the compulsory * keys "vendor" and "model", and the optional keys "version", and "screendims". * * Below are a few samples of these user agent strings: * <pre> * LGE/U8150/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 * PHILIPS855 ObigoInternetBrowser/2.0 * PHILIPS 535 / Obigo Internet Browser 2.0 * PHILIPS-FISIO 620/3 * PHILIPS-Fisio311/2.1 * PHILIPS-FISIO311/2.1 * PHILIPS-Xenium9@9 UP/4.1.16r * PHILIPS-XENIUM 9@9/2.1 * PHILIPS-Xenium 9@9++/3.14 * PHILIPS-Ozeo UP/4 * PHILIPS-V21WAP UP/4 * PHILIPS-Az@lis288 UP/4.1.19m * PHILIPS-SYSOL2/3.11 UP.Browser/5.0.1.11 * Vitelcom-Feature Phone1.0 UP.Browser/5.0.2.2(GUI * ReqwirelessWeb/2.0.0 MIDP-1.0 CLDC-1.0 Nokia3650 * SEC-SGHE710 * </pre> * Notice how often one certain brand of these user-agents is handled by this function. I say no more. * * @param string $useragent User agent string. * @return mixed */ protected function _parseUserAgentRubbish($useragent) { // Old ReqwirelessWeb browsers for Nokia. ReqwirelessWeb/2.0.0 MIDP-1.0 CLDC-1.0 Nokia3650 if (preg_match('/(Nokia)\s*(N-Gage|\d+)$/', $useragent, $matches)) { return(array('vendor' => $matches[1], 'model' => $matches[2])); } // LG Electronics elseif (preg_match('/^(LG)E?\/(\w+)(\/(\d+\.\d+))?/', $useragent, $matches)) { // LGE/U8150/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 $result = array('vendor' => $matches[1], 'model' => $matches[2]); if ((count($matches) == 5) && strlen($matches[4])) { $result['version'] = $matches[4]; } return $result; } // And now for the worst of all user agents, those that start with the text 'PHILIPS'. elseif (preg_match('/^(PHILIPS)(.+)/', $useragent, $matches)) { $vendor = $matches[1]; $model = null; $garbage = trim(strtoupper($matches[2])); // everything after the word PHILIPS in uppercase. if (preg_match('/^-?(\d+)/', $garbage, $matches)) { // match the model names that are just digits. $model = $matches[1]; // PHILIPS855 ObigoInternetBrowser/2.0 // PHILIPS 535 / Obigo Internet Browser 2.0 } elseif (preg_match('/^-?(FISIO)\s*(\d+)/', $garbage, $matches)) { // match the FISIO model names. $model = $matches[1] . $matches[2]; // PHILIPS-FISIO 620/3 // PHILIPS-Fisio311/2.1 // PHILIPS-FISIO311/2.1 } elseif (preg_match('/^-?(XENIUM)/', $garbage, $matches)) { // match the XENIUM model names. $model = $matches[1]; // PHILIPS-Xenium9@9 UP/4.1.16r // PHILIPS-XENIUM 9@9/2.1 // PHILIPS-Xenium 9@9++/3.14 } elseif (preg_match('/^-?([^\s\/]+)/', $garbage, $matches)) { // match all other model names that contain no spaces and no slashes. $model = $matches[1]; // PHILIPS-Ozeo UP/4 // PHILIPS-V21WAP UP/4 // PHILIPS-Az@lis288 UP/4.1.19m // PHILIPS-SYSOL2/3.11 UP.Browser/5.0.1.11 } if (isset($model)) { return(array('vendor' => $vendor, 'model' => $model)); } } // Vitelcom user-agents (used in Spain) elseif (preg_match('/^(Vitelcom)-(Feature Phone)(\d+\.\d+)/', $useragent, $matches)) { // Vitelcom-Feature Phone1.0 UP.Browser/5.0.2.2(GUI) -- this is a TSM 3 or a TSM 4. return(array('vendor' => $matches[1], 'model' => $matches[2], 'version' => $matches[3])); } return false; } /** * Parses a user agent string. * This method simply calls the other 4 _parseUserAgent*() methods to do the work. * If no match can be made, FALSE is returned. * If a match is made, an associative array is returned containing the compulsory * keys "vendor" and "model", and the optional keys "version", "imode_cache", * and "screendims". * * @param string $useragent User agent string. * @return mixed */ protected function _parseUserAgent($useragent) { if ($result = $this->_parseUserAgentStandard($useragent)) { $this->is_standard = true; return $result; } if ($result = $this->_parseUserAgentMozilla($useragent)) { $this->is_mozilla = true; return $result; } if ($result = $this->_parseUserAgentImode($useragent)) { $this->is_imode = true; return $result; } if ($result = $this->_parseUserAgentRubbish($useragent)) { $this->is_rubbish = true; return $result; } return false; } /** * Returns true if the user-agent string passed into the constructor could be parsed, else false. * If this method returns false, then it's probably not a mobile user agent string that was * passed into the constructor. * * @return boolean */ public function success() { return isset($this->vendor); } /** * Returns the user agent string as passed into the constructor or read * from the environment variable HTTP_USER_AGENT. * * @return string */ public function userAgent() { return $this->useragent; } /** * Returns the vendor of the handset if success() returns true, else null. * * @return string|null */ public function vendor() { return $this->vendor; } /** * Returns the model of the handset if success() returns true, else null. * * @return string|null */ public function model() { return $this->model; } /** * Returns the version (if any) of the user agent. * The version information isn't always present, nor reliable. * * @return string|null */ public function version() { return $this->version; } /** * Determines if the parsed user-agent string belongs to an i-mode handset. * Returns true, if so, else false. * * @return boolean */ public function isImode() { return $this->is_imode; } /** * Determines if the parsed user-agent string has a Mozilla 'compatible' format. * Returns true, if so, else false. * * @return boolean */ public function isMozilla() { return $this->is_mozilla; } /** * Determines if the parsed user-agent string has a standard vendor-model/version format. * Returns true, if so, else false. * * @return boolean */ public function isStandard() { return $this->is_standard; } /** * Determines if the parsed user-agent string has a non-standard or messed up format. * Returns true, if so, else false. * * @return boolean */ public function isRubbish() { return $this->is_rubbish; } /** * Returns the maximum i-mode cache data size in kb's of the user agent if it is * an i-mode user-agent, else null. * * @return integer|null */ public function imodeCache() { return $this->imode_cache; } /** * Returns the screen dimensions in the format wxh if this information was parsed * from the user agent string itself, else null. * * @return string|null */ public function screenDims() { return $this->screendims; } /** * Determines if this is a Symbian OS Series 60 user-agent string. * * @return boolean */ public function isSeries60() { if (!isset($this->is_series60)) { // NokiaN-Gage/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 // Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS Series 60 42) Opera 6.0 [fr] $this->is_series60 = preg_match('/\b(Symbian OS Series 60|SymbianOS\/\S+ Series60)\b/', $this->useragent); } return $this->is_series60; } } ?>