我写了一个简单的类来检查用户代理是否显示不兼容浏览器的警告。我正在做这个服务器端,我知道这可能是客户端。
首先,我不太适合编写正则表达式。
我写了一个正则表达式,用于搜索小写浏览器名称,后跟版本号。我用这样的数组做了一个foreach()
:
<?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]}'"";
}
}
?>
这将产生:Browser: "Firefox", version "23.0.6"
.
我发现这适用于Firefox,MS IE和旧版本的Opera。但是,某些浏览器(如 Safari 和较新版本的 Opera)具有不同的用户代理字符串,其中包含 Version/x.x.x,即
只是为了给你一个想法,这里有 3 个用户代理字符串,我需要突出显示。
-
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
因此,在每一个中,以下人类逻辑都是正确的:
- 如果字符串中有
Version/x.x.x
,则为版本号。 - 如果没有,则
Browsername/x.x.x
版本号。
此外,如果您查看上面的第一个也是最后一个用户代理字符串,您可以看到Version
可以在浏览器名称之前或之后。
有人可以帮我制作一个正则表达式以与preg_match()
一起使用吗?我是否需要使用条件语句,或者是否可以搜索可选分组?我有点困惑..
谢谢!
编辑 17-09-2013: 我忘了提,我不想使用get_browser()
,它使用一个巨大的库来检测浏览器功能等。我只需要一个简短的浏览器"白名单",应该需要几毫秒而不是几百毫秒来读取浏览帽.ini文件。否则乔治的答案就是答案。
最终的做法略有不同,因为我在某些浏览器中遇到了一些麻烦,而 Remus 的答案。
<?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
?>
鉴于您的一些结果,这有效。它可能并非在所有情况下,但它会大大减少您的处理时间。
我会使用单个正则表达式来提取版本:
(?:version'/|(?:msie|chrome|safari|firefox|opera) )(['d.]+)
然后,由于您只搜索少量确切的字符串,因此您可以使用 php 的stripos()
来检查浏览器字符串。
<?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";
?>
这样做的好处是立竿见影的:
- 您无需使用正则表达式多次测试用户代理。
-
stripos()
的处理速度明显快于正则表达式。
你也可以在这里使用正则表达式:http://regex101.com/r/lE6lI2
你听说过浏览和get_browser()
吗?在我的安装中:
$info = get_browser();
echo $info->browser; // Chrome
echo $info->version; // 29.0
要使用它,请从这里获取 PHP 版本的 browscap 的副本.ini(例如 php_browscap.ini
),在browscap
指令下php.ini
引用它,你就可以开始了。
这个类/函数做得很好:
old dead link: https://github.com/diversen/coscms/blob/master/coslib/useragent.php
我已经用iPhone和歌剧对此进行了测试。同时,您将获得运行浏览器的操作系统。
编辑:
我可以看到这个函数有一个自己的 git 存储库。在更新和维护时使用它:
https://github.com/donatj/PhpUserAgent