Space Cat, Prince Among Thieves

PHP User Agent Parser

Demo You are running version on
CCBot/2.0
Try It!

Recent Activity

Jesse Donat (donatj)

"Opera Next" support added
Missing \
Playbook support added
phpunit.xml added

Unified casing of PLAYSTATION and Playstation to PlayStation
Fixed a problem with the Lynx version0
Test added for PSP Vita
Support for Playstation Vita added
composer.json added

Updated readme to include build status
.travis.yml added
Tests converted to PhpUnit

Merge branch 'master' of https://github.com/donatj/PhpUserAgent
Used a better variable name.
PHPDoc made more usual

Update README.md

BalckBerry => BlackBerry

3DS support added
WiiU support added

Very happy license added

Cleaned up merged code
Merge pull request #8 from atomantic/Fix_For_CLI_Unit_Tests_And_Non_UI_Requests

Unit Test Support

Adam Eivy (atomantic)

now this method can be safely invoked by a command-line or server-side interaction without erroring out

Jesse Donat (donatj)

Readme Updated
Support for Chrome OS for Chromebooks added
Another Kindle Fire Test Case Added

Test style fixup
Kindle Fire support fixed up
CSS Cleanup
Commented regex did not match preg
slight logic cleanup

There are many User Agent string parsers out there, many PHP ones infact, but none of what I tested were able to do all of the following.

  1. Correctly identify certain versions of IE7 and above that included a user string mentioning IE6 as follows
    1. Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1))
  2. Correctly identify various mobile platforms, Android and Windows Phone 7 in particular.
  3. Operates simply without large class structures.

This is why I set about building my own.  I don’t guarantee it to be perfect, but it works for my needs. I strongly welcome forking and pull requests through Github for any changes. 

Comments are more than welcome below.

Known Limitations

  • Does not detect Ice Weasel as Firefox
  • Probably many others not coming to mind right now.

View the test suite of User Agents I'm currently running it against here.


<?php

/**
 * Parses a user agent string into its important parts
 * 
 * @author Jesse G. Donat <donatj@gmail.com>
 * @link https://github.com/donatj/PhpUserAgent
 * @link http://donatstudios.com/PHP-Parser-HTTP_USER_AGENT
 * @param string $u_agent
 * @return array an array with browser, version and platform keys
 */
function parse_user_agent$u_agent null ) { 
    if(
is_null($u_agent) && isset($_SERVER['HTTP_USER_AGENT'])) $u_agent $_SERVER['HTTP_USER_AGENT'];

    
$data = array(
        
'platform' => null,
        
'browser'  => null,
        
'version'  => null,
    );
    
    if(!
$u_agent) return $data;
    
    if( 
preg_match('/\((.*?)\)/im'$u_agent$parent_matches) ) {

        
preg_match_all('/(?P<platform>Android|CrOS|iPhone|iPad|Linux|Macintosh|Windows(\ Phone\ OS)?|Silk|linux-gnu|BlackBerry|PlayBook|Nintendo\ (WiiU?|3DS)|Xbox)
            (?:\ [^;]*)?
            (?:;|$)/imx'
$parent_matches[1], $resultPREG_PATTERN_ORDER);

        
$priority = array('Android''Xbox');
        
$result['platform'] = array_unique($result['platform']);
        if( 
count($result['platform']) > ) {
            if( 
$keys array_intersect($priority$result['platform']) ) {
                
$data['platform'] = reset($keys);
            }else{
                
$data['platform'] = $result['platform'][0];
            }
        }elseif(isset(
$result['platform'][0])){
            
$data['platform'] = $result['platform'][0];
        }
    }

    if( 
$data['platform'] == 'linux-gnu' ) { $data['platform'] = 'Linux'; }
    if( 
$data['platform'] == 'CrOS' ) { $data['platform'] = 'Chrome OS'; }

    
preg_match_all('%(?P<browser>Camino|Kindle(\ Fire\ Build)?|Firefox|Safari|MSIE|AppleWebKit|Chrome|IEMobile|Opera|OPR|Silk|Lynx|Version|Wget|curl|NintendoBrowser|PLAYSTATION\ (\d|Vita)+)
            (?:;?)
            (?:(?:[/ ])(?P<version>[0-9A-Z.]+)|/(?:[A-Z]*))%ix'

    
$u_agent$resultPREG_PATTERN_ORDER);

    
$key 0;

    
$data['browser'] = $result['browser'][0];
    
$data['version'] = $result['version'][0];

    if( 
$key array_search'Playstation Vita'$result['browser'] ) !== false ) {
        
$data['platform'] = 'PlayStation Vita';
        
$data['browser'] = 'Browser';
    }elseif( (
$key array_search'Kindle Fire Build'$result['browser'] )) !== false || ($key array_search'Silk'$result['browser'] )) !== false ) {
        
$data['browser']  = $result['browser'][$key] == 'Silk' 'Silk' 'Kindle';
        
$data['platform'] = 'Kindle Fire';
        if( !(
$data['version'] = $result['version'][$key]) || !is_numeric($data['version'][0]) ) {
            
$data['version'] = $result['version'][array_search'Version'$result['browser'] )];
        }
    }elseif( (
$key array_search'NintendoBrowser'$result['browser'] )) !== false || $data['platform'] == 'Nintendo 3DS' ) {
        
$data['browser']  = 'NintendoBrowser';
        
$data['version']  = $result['version'][$key];
    }elseif( (
$key array_search'Kindle'$result['browser'] )) !== false ) {
        
$data['browser']  = $result['browser'][$key];
        
$data['platform'] = 'Kindle';
        
$data['version']  = $result['version'][$key];
    }elseif( (
$key array_search'OPR'$result['browser'] )) !== false || ($key array_search'Opera'$result['browser'] )) !== false ) {
        
$data['browser'] = 'Opera';
        
$data['version'] = $result['version'][$key];
        if( (
$key array_search'Version'$result['browser'] )) !== false ) { $data['version'] = $result['version'][$key]; }
    }elseif( 
$result['browser'][0] == 'AppleWebKit' ) {
        if( ( 
$data['platform'] == 'Android' && !($key 0) ) || $key array_search'Chrome'$result['browser'] ) ) {
            
$data['browser'] = 'Chrome';
            if( (
$vkey array_search'Version'$result['browser'] )) !== false ) { $key $vkey; }
        }elseif( 
$data['platform'] == 'BlackBerry' || $data['platform'] == 'PlayBook' ) {
            
$data['browser'] = 'BlackBerry Browser';
            if( (
$vkey array_search'Version'$result['browser'] )) !== false ) { $key $vkey; }
        }elseif( 
$key array_search'Safari'$result['browser'] ) ) {
            
$data['browser'] = 'Safari';
            if( (
$vkey array_search'Version'$result['browser'] )) !== false ) { $key $vkey; }
        }
        
        
$data['version'] = $result['version'][$key];
    }elseif( 
$result['browser'][0] == 'MSIE' ){
        if( 
$key array_search'IEMobile'$result['browser'] ) ) {
            
$data['browser'] = 'IEMobile';
        }else{
            
$data['browser'] = 'MSIE';
            
$key 0;
        }
        
$data['version'] = $result['version'][$key];
    }elseif( 
$key array_search'PLAYSTATION 3'$result['browser'] ) !== false ) {
        
$data['platform'] = 'PlayStation 3';
        
$data['browser']  = 'NetFront';
    }

    return 
$data;

}
Source Availbile at Github as Well

Comment by: ling on

ling GravatarThank you very much !!

Comment by: Edmonsur on

Edmonsur GravatarThank you!!

Comment by: scoot on

scoot GravatarWow, just what I was looking for. Looked in eight places before I found this site. The other stuff I found were all backdated. Thank you very much for making an up to date version!

Comment by: dankoi on

dankoi GravatarThank you so much!
Great job!

Comment by: Valery on

Valery GravatarCan you add platform version support?
For example WinXP, Win7, Win8, etc.
And processor detail 32/64 bit.

Comment by: Wairowe on

Wairowe GravatarHi, love this clean bit of script!

Can you look to add the new Windows Surface RT (ARM)

Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)

Comment by: RuuRd on

RuuRd Gravatarthanks Donat for your great parse_user_agent function!

I read through your code and I have a few questions.

as far as I know array_intersect never returns a boolean .....

if( $keys = array_intersect($priority, $result['platform']) ) {


assignment to $key instead of evaluation:
if( ( $data['platform'] == 'Android' && !($key = 0) ) ||


some $key = array_search() evaluation to “!== false” seem to be missing ..
like
elseif( $key = array_search( 'Safari', $result['browser'] ) ) {


Your function works well though!

Comment by: Jesse G. Donat on

Jesse G. Donat GravatarPHP uses implicit type conversion, whereas an empty array is false-y and one containing any value is truth-y, and my code is simply taking advantage of this feature of the language to save on code.

Comment by: sachz on

sachz Gravatarthank you for this useful script (:

Email address will never be publicly visible.