I wrote a simple class to check for user agents to display a warning for incompatible browsers. I'm doing this server side, I know it's possible client side.
Okey first off, I'm not much good for writing regexes..
I wrote a regex that searches for lower case browser names followed by the version number.
I do a foreach()
with an array something like this:
<?php
$browsers = Array('msie','chrome','safari','firefox','opera');
foreach($browsers as $i => $browser)
{
$regex = "#({$browser})[/ ]([0-9.]*)#i";
if(preg_match($regex, $useragent, $matches))
{
echo "Browser: \"{$matches[0]}\", version: \"{$matches[1]}\"";
}
}
?>
This would yield: Browser: "Firefox", version "23.0.6"
.
I found this works for Firefox, MS IE, and older versions of Opera. However some browsers like Safari and the newer versions of Opera have a different user-agent string that contains Version/x.x.x, which is
Just to give you the an idea here are 3 user-agent strings and what I need is highlighted.
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1
Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14
So in each of these the following human logic correct:
Version/x.x.x
in the string that is the version number. Browsername/x.x.x
is the version number.Also if you look at the 1st and last user-agent string above, you can see the Version
can come before or after the browser name.
Can somebody help me to make a regex to be used with preg_match()
? Do I need to use a conditional statement or can I search for optional groupings? I'm a bit confused..
Thanks!
Edit 17-09-2013: I forgot to mention, I don't want to use get_browser()
, it uses a huge library to detect the browsers capabilities etc. I only need a short "whitelist" of browsers that should take a few milliseconds rather than a few hundred ms to read the browse cap.ini files.. Otherwise George's answer would've been the answer..
Ended up doing it a little differently since I had some trouble with some browsers with Remus' answer.
<?php
function get_useragent_info($ua)
{
$ua = is_null($ua) ? $_SERVER['HTTP_USER_AGENT'] : $ua;
// Enumerate all common platforms, this is usually placed in braces (order is important! First come first serve..)
$platforms = "Windows|iPad|iPhone|Macintosh|Android|BlackBerry";
// All browsers except MSIE/Trident and..
// NOT for browsers that use this syntax: Version/0.xx Browsername
$browsers = "Firefox|Chrome";
// Specifically for browsers that use this syntax: Version/0.xx Browername
$browsers_v = "Safari|Mobile"; // Mobile is mentioned in Android and BlackBerry UA's
// Fill in your most common engines..
$engines = "Gecko|Trident|Webkit|Presto";
// Regex the crap out of the user agent, making multiple selections and..
$regex_pat = "/((Mozilla)\/[\d\.]+|(Opera)\/[\d\.]+)\s\(.*?((MSIE)\s([\d\.]+).*?(Windows)|({$platforms})).*?\s.*?({$engines})[\/\s]+[\d\.]+(\;\srv\:([\d\.]+)|.*?).*?(Version[\/\s]([\d\.]+)(.*?({$browsers_v})|$)|(({$browsers})[\/\s]+([\d\.]+))|$).*/i";
// .. placing them in this order, delimited by |
$replace_pat = '$7$8|$2$3|$9|${17}${15}$5$3|${18}${13}$6${11}';
// Run the preg_replace .. and explode on |
$ua_array = explode("|",preg_replace($regex_pat, $replace_pat, $ua, PREG_PATTERN_ORDER));
if (count($ua_array)>1)
{
$return['platform'] = $ua_array[0]; // Windows / iPad / MacOS / BlackBerry
$return['type'] = $ua_array[1]; // Mozilla / Opera etc.
$return['renderer'] = $ua_array[2]; // WebKit / Presto / Trident / Gecko etc.
$return['browser'] = $ua_array[3]; // Chrome / Safari / MSIE / Firefox
/*
Not necessary but this will filter out Chromes ridiculously long version
numbers 31.0.1234.122 becomes 31.0, while a "normal" 3 digit version number
like 10.2.1 would stay 10.2.1, 11.0 stays 11.0. Non-match stays what it is.
*/
if (preg_match("/^[\d]+\.[\d]+(?:\.[\d]{0,2}$)?/",$ua_array[4],$matches))
{
$return['version'] = $matches[0];
}
else
{
$return['version'] = $ua_array[4];
}
}
else
{
/*
Unknown browser..
This could be a deal breaker for you but I use this to actually keep old
browsers out of my application, users are told to download a compatible
browser (99% of modern browsers are compatible. You can also ignore my error
but then there is no guarantee that the application will work and thus
no need to report debugging data.
*/
return false;
}
// Replace some browsernames e.g. MSIE -> Internet Explorer
switch(strtolower($return['browser']))
{
case "msie":
case "trident":
$return['browser'] = "Internet Explorer";
break;
case "": // IE 11 is a steamy turd (thanks Microsoft...)
if (strtolower($return['renderer']) == "trident")
{
$return['browser'] = "Internet Explorer";
}
break;
}
switch(strtolower($return['platform']))
{
case "android": // These browsers claim to be Safari but are BB Mobile
case "blackberry": // and Android Mobile
if ($return['browser'] =="Safari" || $return['browser'] == "Mobile" || $return['browser'] == "")
{
$return['browser'] = "{$return['platform']} mobile";
}
break;
}
return $return;
} // End of Function
?>
Given your handful of results, this works. It may not in all cases, but it's going to reduce your processing time drastically.
I'd use a single regular expression to extract the version:
(?:version\/|(?:msie|chrome|safari|firefox|opera) )([\d.]+)
And then, since you're only searching for a handful of exact strings, you can use php's stripos()
to check for the browser string.
<?php
$useragent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1";
$browsers = Array('msie','chrome','safari','firefox','opera');
preg_match("/(?:version\/|(?:msie|chrome|safari|firefox|opera) )([\d.]+)/i", $useragent, $matches);
$version = $matches[1];
$browser = "";
foreach($browsers as $b)
{
if (stripos($useragent, $b) !== false)
{
$browser = ucfirst($b);
break;
}
}
echo "$browser: $version";
?>
The benefits of doing it this way are immediate:
stripos()
is significantly faster at processing than regular expressions.You can also play around with the regex here: http://regex101.com/r/lE6lI2
Have you heard of browscap and get_browser()
? On my install:
$info = get_browser();
echo $info->browser; // Chrome
echo $info->version; // 29.0
To use it, grab yourself a copy of a PHP version of browscap.ini from here (e.g. php_browscap.ini
), reference it in php.ini
under the browscap
directive, and you're good to go.
This class / function does a nice job:
old dead link: https://github.com/diversen/coscms/blob/master/coslib/useragent.php
I have tested this with an iphone and opera. At the same time you will get the OS the browser is running on .)
Edit:
I can see that this function has got a git repo of it's own. Use this as this is updated and maintained:
https://github.com/donatj/PhpUserAgent
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With