开发者

reliable user browser detection with php

开发者 https://www.devze.com 2022-12-19 21:45 出处:网络
Trying to detect a user\'s browser with PHP only, is $_SERVER[\'HTTP_USER_开发者_如何学编程AGENT\'] a reliable way? Should I instead opt for the get_browser function? which one do you find brings more

Trying to detect a user's browser with PHP only, is $_SERVER['HTTP_USER_开发者_如何学编程AGENT'] a reliable way? Should I instead opt for the get_browser function? which one do you find brings more precise results?

If this method is pragmatic, is it ill advised to use it for outputting pertinent CSS links, for example:

if(stripos($_SERVER['HTTP_USER_AGENT'],"mozilla")!==false)
   echo '<link type="text/css" href="mozilla.css" />';

I noticed this question, however I wanted to clarify whether this is good for CSS-oriented detection.

UPDATE: something really suspicious: I tried echo $_SERVER['HTTP_USER_AGENT']; on IE 7 and this is what it output:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30618)

Safari gave something weird with "mozilla" in it too. What gives?


Check this code , I've found this is useful. Don't check Mozilla because most browser use this as user agent string

if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
   echo 'Internet explorer';
 elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== FALSE) //For Supporting IE 11
    echo 'Internet explorer';
 elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== FALSE)
   echo 'Mozilla Firefox';
 elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== FALSE)
   echo 'Google Chrome';
 elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== FALSE)
   echo "Opera Mini";
 elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== FALSE)
   echo "Opera";
 elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== FALSE)
   echo "Safari";
 else
   echo 'Something else';


Using an existing method (ie get_browser) is probably better than writing something yourself, since it has (better) support and will be updated with newer versions. There might be also usable libraries out there for getting the browser id in a reliable way.

Decoding the $_SERVER['HTTP_USER_AGENT'] is difficult, since a lot of browsers have quite similar data and tend to (mis)use it for their own benefits. But if you really want to decode them, you could use the information on this page for all available agent ids. This page also shows that your example output indeed belongs to IE 7. More information about the fields in the agent id itself can be found on this page, but as I said already browsers tend to use it for their own benefits and it could be in a (slightly) other format.


User Agent can be faked and its better not to depend upon user agent string rather then you can use a CSS3 media queries if you only want to detect orientation (you can explore the CSS of the famous responsive framework bootstrap to check how you can handle the orientation part using CSS)

Here is little CSS :

    @media only screen and (max-width: 999px) {
     /* rules that only apply for canvases narrower than 1000px */
    }

    @media only screen and (device-width: 768px) and (orientation: landscape) {
    /* rules for iPad in landscape orientation */
    }

    @media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
    /* iPhone, Android rules here */
    }    

Read more : About CSS orientation detection

OR You can find the orientation using JavaScript :

    // Listen for orientation changes
    window.addEventListener("orientationchange", function() {
        // Announce the new orientation number
        alert(window.orientation);
    }, false);

Read more : About detect orientation using JS

Finally if you really wants to go with user agent string then this code will help you alot, work fine almost on every browser :

<?php
class BrowserDetection {

    private $_user_agent;
    private $_name;
    private $_version;
    private $_platform;

    private $_basic_browser = array (
       'Trident\/7.0' => 'Internet Explorer 11',
    'Beamrise' => 'Beamrise',
    'Opera' => 'Opera',
    'OPR' => 'Opera',
    'Shiira' => 'Shiira',
    'Chimera' => 'Chimera',
    'Phoenix' => 'Phoenix',
    'Firebird' => 'Firebird',
    'Camino' => 'Camino',
    'Netscape' => 'Netscape',
    'OmniWeb' => 'OmniWeb',
    'Konqueror' => 'Konqueror',
    'icab' => 'iCab',
     'Lynx' => 'Lynx',
    'Links' => 'Links',
    'hotjava' => 'HotJava',
    'amaya' => 'Amaya',
    'IBrowse' => 'IBrowse',
    'iTunes' => 'iTunes',
    'Silk' => 'Silk',
    'Dillo' => 'Dillo', 
    'Maxthon' => 'Maxthon',
    'Arora' => 'Arora',
    'Galeon' => 'Galeon',
    'Iceape' => 'Iceape',
    'Iceweasel' => 'Iceweasel',
    'Midori' => 'Midori',
    'QupZilla' => 'QupZilla',
    'Namoroka' => 'Namoroka',
    'NetSurf' => 'NetSurf',
    'BOLT' => 'BOLT',
    'EudoraWeb' => 'EudoraWeb',
    'shadowfox' => 'ShadowFox',
    'Swiftfox' => 'Swiftfox',
    'Uzbl' => 'Uzbl',
    'UCBrowser' => 'UCBrowser',
    'Kindle' => 'Kindle',
    'wOSBrowser' => 'wOSBrowser',
     'Epiphany' => 'Epiphany', 
    'SeaMonkey' => 'SeaMonkey',
    'Avant Browser' => 'Avant Browser',
    'Firefox' => 'Firefox',
    'Chrome' => 'Google Chrome',
    'MSIE' => 'Internet Explorer',
    'Internet Explorer' => 'Internet Explorer',
     'Safari' => 'Safari',
    'Mozilla' => 'Mozilla'  
    );

     private $_basic_platform = array(
        'windows' => 'Windows', 
     'iPad' => 'iPad', 
      'iPod' => 'iPod', 
    'iPhone' => 'iPhone', 
     'mac' => 'Apple', 
    'android' => 'Android', 
    'linux' => 'Linux',
    'Nokia' => 'Nokia',
     'BlackBerry' => 'BlackBerry',
    'FreeBSD' => 'FreeBSD',
     'OpenBSD' => 'OpenBSD',
    'NetBSD' => 'NetBSD',
     'UNIX' => 'UNIX',
    'DragonFly' => 'DragonFlyBSD',
    'OpenSolaris' => 'OpenSolaris',
    'SunOS' => 'SunOS', 
    'OS\/2' => 'OS/2',
    'BeOS' => 'BeOS',
    'win' => 'Windows',
    'Dillo' => 'Linux',
    'PalmOS' => 'PalmOS',
    'RebelMouse' => 'RebelMouse'   
     ); 

    function __construct($ua = '') {
        if(empty($ua)) {
           $this->_user_agent = (!empty($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:getenv('HTTP_USER_AGENT'));
        }
        else {
           $this->_user_agent = $ua;
        }
       }

    function detect() {
        $this->detectBrowser();
        $this->detectPlatform();
        return $this;
    }

    function detectBrowser() {
     foreach($this->_basic_browser as $pattern => $name) {
        if( preg_match("/".$pattern."/i",$this->_user_agent, $match)) {
            $this->_name = $name;
             // finally get the correct version number
            $known = array('Version', $pattern, 'other');
            $pattern_version = '#(?<browser>' . join('|', $known).')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
            if (!preg_match_all($pattern_version, $this->_user_agent, $matches)) {
                // we have no matching number just continue
            }
            // see how many we have
            $i = count($matches['browser']);
            if ($i != 1) {
                //we will have two since we are not using 'other' argument yet
                //see if version is before or after the name
                if (strripos($this->_user_agent,"Version") < strripos($this->_user_agent,$pattern)){
                    @$this->_version = $matches['version'][0];
                }
                else {
                    @$this->_version = $matches['version'][1];
                }
            }
            else {
                $this->_version = $matches['version'][0];
            }
            break;
        }
       }
   }

    function detectPlatform() {
      foreach($this->_basic_platform as $key => $platform) {
            if (stripos($this->_user_agent, $key) !== false) {
                $this->_platform = $platform;
                break;
            } 
      }
    }

   function getBrowser() {
      if(!empty($this->_name)) {
           return $this->_name;
      }
   }        

   function getVersion() {
       return $this->_version;
    }

    function getPlatform() {
       if(!empty($this->_platform)) {
          return $this->_platform;
       }
    }

    function getUserAgent() {
        return $this->_user_agent;
     }

     function getInfo() {
         return "<strong>Browser Name:</strong> {$this->getBrowser()}<br/>\n" .
        "<strong>Browser Version:</strong> {$this->getVersion()}<br/>\n" .
        "<strong>Browser User Agent String:</strong> {$this->getUserAgent()}<br/>\n" .
        "<strong>Platform:</strong> {$this->getPlatform()}<br/>";
     }
}  

$obj = new BrowserDetection();

echo $obj->detect()->getInfo();

The above code works for me almost on every browser and i hope it will help you a bit.


class Browser { 
    /** 
    Figure out what browser is used, its version and the platform it is 
    running on. 

    The following code was ported in part from JQuery v1.3.1 
    */ 
    public static function detect() { 
        $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']); 

        // Identify the browser. Check Opera and Safari first in case of spoof. Let Google Chrome be identified as Safari. 
        if (preg_match('/opera/', $userAgent)) { 
            $name = 'opera'; 
        } 
        elseif (preg_match('/webkit/', $userAgent)) { 
            $name = 'safari'; 
        } 
        elseif (preg_match('/msie/', $userAgent)) { 
            $name = 'msie'; 
        } 
        elseif (preg_match('/mozilla/', $userAgent) && !preg_match('/compatible/', $userAgent)) { 
            $name = 'mozilla'; 
        } 
        else { 
            $name = 'unrecognized'; 
        } 

        // What version? 
        if (preg_match('/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/', $userAgent, $matches)) { 
            $version = $matches[1]; 
        } 
        else { 
            $version = 'unknown'; 
        } 

        // Running on what platform? 
        if (preg_match('/linux/', $userAgent)) { 
            $platform = 'linux'; 
        } 
        elseif (preg_match('/macintosh|mac os x/', $userAgent)) { 
            $platform = 'mac'; 
        } 
        elseif (preg_match('/windows|win32/', $userAgent)) { 
            $platform = 'windows'; 
        } 
        else { 
            $platform = 'unrecognized'; 
        } 

        return array( 
            'name'      => $name, 
            'version'   => $version, 
            'platform'  => $platform, 
            'userAgent' => $userAgent 
        ); 
    } 
} 


$browser = Browser::detect(); 


Most PHP packages that I've found seemed to be pretty good but I couldn't find a good one that gave me everything I needed so I built a Laravel helper to combine 3 of them.

Here are the packages:

jenssegers/agent

whichbrowser/parser

cbschuld/browser.php

And here's my function:

function browser($userAgent)
{
    $agent = new \Jenssegers\Agent\Agent();
    $agent->setUserAgent($userAgent);

    $result = new \WhichBrowser\Parser($userAgent);

    $browser = new \Browser($userAgent);

    return new class($agent, $result, $browser)
    {
        public function __construct($agent, $result, $browser)
        {
            $this->agent = $agent;
            $this->result = $result;
            $this->browser = $browser;
        }
        public function device()
        {
            return $this->agent->device() ?: $this->result->device->toString() ?: $this->browser->getPlatform();
        }
        public function browser()
        {
            return $this->agent->browser() ?: $this->result->browser->name ?: $this->browser->getBrowser();
        }
        public function platform()
        {
            return $this->agent->platform() ?: $this->result->os->name ?: $this->browser->getPlatform();
        }
        public function isMobile()
        {
            return $this->agent->isPhone() ?: $this->result->isType('mobile') ?: $this->browser->isMobile();
        }
        public function isTablet()
        {
            return $this->result->isType('tablet') ?: $this->browser->isTablet();
        }
        public function isDesktop()
        {
            return $this->agent->isDesktop() ?: $this->result->isType('desktop') ?: (! $this->browser->isMobile() && ! $this->browser->isTablet());
        }
        public function isRobot()
        {
            return $this->agent->isRobot() ?: $this->browser->isRobot();
        }
    };

Here's how to use it:

$browser = browser($userAgent);

$browser->device();
$browser->platform();
$browser->browser();
$browser->isMobile();
$browser->isTablet();
$browser->isDesktop();
$browser->isRobot();


if stripos($_SERVER['HTTP_USER_AGENT'],"mozilla")!==false)

That's not a useful test, almost every browser identifies itself as Mozilla.

is $_SERVER['HTTP_USER_AGENT'] a reliable way?

No.

Should I instead opt for the get_browser function?

No.

Browser-sniffing on the server side is a losing game. Apart from all the issues of trying to parse the UA string, the browsers that lie, the obscure browsers, and the possibility the header isn't there at all, if you return different page content for a different browser you must set the Vary header to include User-Agent, otherwise caching proxies may return the wrong version of the page to the wrong browser.

But if you add Vary: User-Agent IE's broken caching code gets confused and reloads the page every time. So you can't win.

If you must browser-sniff, the place to do it is on the client side, using JavaScript and, specifically in IE's case, conditional comments. It's lucky that it's IE that supports conditional comments, since that's the one browser you often need workarounds for. (See scunliffe's answer for the most common strategy.)


Something I notice, the real browser name always comes after the last (parentheses) with the exception of IE, where there is no browser name after the last (parentheses). I wonder if only reading after the last ) could improve accuracy.

you may notice this in different user agents:

Google Chrome

Safari

Firefox

Edge

IE (the exception where no browser is defined after parentheses)

example:

$userBrowser = (!empty($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:getenv('HTTP_USER_AGENT'));
$userBrowser = explode(')', $userBrowser);
$userBrowser = $userBrowser[count($userBrowser)-1];

echo $userBrowser; //this has many inaccurate browsers stripped out

A full function:

function getUserBrowser(){
  $fullUserBrowser = (!empty($_SERVER['HTTP_USER_AGENT'])? 
  $_SERVER['HTTP_USER_AGENT']:getenv('HTTP_USER_AGENT'));
  $userBrowser = explode(')', $fullUserBrowser);
  $userBrowser = $userBrowser[count($userBrowser)-1];

  if((!$userBrowser || $userBrowser === '' || $userBrowser === ' ' || strpos($userBrowser, 'like Gecko') === 1) && strpos($fullUserBrowser, 'Windows') !== false){
    return 'Internet-Explorer';
  }else if((strpos($userBrowser, 'Edge/') !== false || strpos($userBrowser, 'Edg/') !== false) && strpos($fullUserBrowser, 'Windows') !== false){
    return 'Microsoft-Edge';
  }else if(strpos($userBrowser, 'Chrome/') === 1 || strpos($userBrowser, 'CriOS/') === 1){
    return 'Google-Chrome';
  }else if(strpos($userBrowser, 'Firefox/') !== false || strpos($userBrowser, 'FxiOS/') !== false){
    return 'Mozilla-Firefox';
  }else if(strpos($userBrowser, 'Safari/') !== false && strpos($fullUserBrowser, 'Mac') !== false){
    return 'Safari';
  }else if(strpos($userBrowser, 'OPR/') !== false && strpos($fullUserBrowser, 'Opera Mini') !== false){
    return 'Opera-Mini';
  }else if(strpos($userBrowser, 'OPR/') !== false){
    return 'Opera';
  }
  return false;
}

echo 'browser detect: '.getUserBrowser();

I also tested this on chrome, edge, and firefox developer, and it worked accurately. (although I have not tested older versions of these browsers yet)


Old post still comes up in Google. get_browser() is best solution but editing php.ini might be impossible. According to this post you can't ini_set the browscap property. So what's left? phpbrowscap seems to get the job done. The docs aren't great so if you don't want it to auto-update (the default is on), then you need to set

$bc->updateMethod = phpbrowscap\Browscap::UPDATE_LOCAL;
$bc->localFile = __DIR__ . "/php_browscap.ini";


I think relying on the userAgent is a bit weak as it can (and is) often faked.

If you want to serve up CSS just for IE, use a conditional comment.

<link type="text/css" rel="stylesheet" href="styles.css"/><!--for all-->
<!--[if IE]>
  <link type="text/css" rel="stylesheet" href="ie_styles.css"/>
<![endif]-->

or if you just want one for IE6:

<!--[if IE 6]>
  <link type="text/css" rel="stylesheet" href="ie6_styles.css"/>
<![endif]-->

Since its a comment its ignored by browsers... except IE that loads it if the if test matches the current browser.


Check This Code :      
   <?php     

class OS_BR{    
private $agent = "";
private $info = array();

function __construct(){
    $this->agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL;
    $this->getBrowser();
    $this->getOS();
}     
function getBrowser(){     
    $browser = array("Navigator"            => "/Navigator(.*)/i",
                     "Firefox"              => "/Firefox(.*)/i",
                     "Internet Explorer"    => "/MSIE(.*)/i",
                     "Google Chrome"        => "/chrome(.*)/i",
                     "MAXTHON"              => "/MAXTHON(.*)/i",
                     "Opera"                => "/Opera(.*)/i",
                     );
    foreach($browser as $key => $value){
        if(preg_match($value, $this->agent)){
            $this->info = array_merge($this->info,array("Browser" => $key));
            $this->info = array_merge($this->info,array(
              "Version" => $this->getVersion($key, $value, $this->agent)));
            break;
        }else{
            $this->info = array_merge($this->info,array("Browser" => "UnKnown"));
            $this->info = array_merge($this->info,array("Version" => "UnKnown"));
        }
    }
    return $this->info['Browser'];
}
function getOS(){
    $OS = array("Windows"   =>   "/Windows/i",
                "Linux"     =>   "/Linux/i",
                "Unix"      =>   "/Unix/i",
                "Mac"       =>   "/Mac/i"
                );

    foreach($OS as $key => $value){
        if(preg_match($value, $this->agent)){
            $this->info = array_merge($this->info,array("Operating System" => $key));
            break;
        }
    }
    return $this->info['Operating System'];
}

function getVersion($browser, $search, $string){
    $browser = $this->info['Browser'];
    $version = "";
    $browser = strtolower($browser);
    preg_match_all($search,$string,$match);
    switch($browser){
        case "firefox": $version = str_replace("/","",$match[1][0]);
        break;

        case "internet explorer": $version = substr($match[1][0],0,4);
        break;

        case "opera": $version = str_replace("/","",substr($match[1][0],0,5));
        break;

        case "navigator": $version = substr($match[1][0],1,7);
        break;

        case "maxthon": $version = str_replace(")","",$match[1][0]);
        break;

        case "google chrome": $version = substr($match[1][0],1,10);
    }
    return $version;
}

function showInfo($switch){
    $switch = strtolower($switch);
    switch($switch){
        case "browser": return $this->info['Browser'];
        break;

        case "os": return $this->info['Operating System'];
        break;

        case "version": return $this->info['Version'];
        break;

        case "all" : return array($this->info["Version"], 
          $this->info['Operating System'], $this->info['Browser']);
        break;

        default: return "Unkonw";
        break;

    }
}
 }    


$obj = new OS_BR();

echo $obj->showInfo('browser');

echo $obj->showInfo('version');

echo $obj->showInfo('os');

echo "<pre>".print_r($obj->showInfo("all"),true)."</pre>"; 

 ?>


@Ekramul Hoque was on the right track but there are several flaws to his answer.

First of all, I would begin with Edge as Internet Explorer does not contain the term Edge in any of its UAs.

if(strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== FALSE) {
  echo '<link type="text/css" href="ms.css" />';

Then, continue to work backward as earlier versions of IE didn't use the Trident engine and therefore won't contain it in their UA.

} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== FALSE) {
  echo '<link type="text/css" href="ms.css" />';
} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) {
  echo '<link type="text/css" href="ms.css" />';

We need to target iOS browsers next so that the subsequent queries don't interfere with this one. All iOS browsers use webkit with the exception of Opera Mini, which does its rendering from a remote server instead of the device. This means that we can target the OS in the UA with iOS and exclude UAs that contain Opera.

} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'iOS') && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== FALSE {
  echo '<link type="text/css" href="webkit.css" />';

Next, move on to Firefox browsers. While using Firefox for the search term will work, it will only identify Firefox browsers--not Firefox based browsers. Firefox contains Gecko in its UA as Gecko is the engine that it uses, and we can therefore target that. By using Gecko, we can identify all browsers that run on the Gecko engine (ie SeaMonkey). However, many browsers use the term like Gecko for compatibility reasons, so we must be sure to match Gecko and not like Gecko.

} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') && !strpos($_SERVER['HTTP_USER_AGENT'], 'like Gecko') !== FALSE) {
  echo '<link type="text/css" href="moz.css" />';

Moving on we'll identify Opera browsers. Opera used the Presto engine to the end of v12. Starting with v15, they began using the Blink engine like Chrome. v12 and earlier contained two unique words in the UA that v15+ doesn't have--Opera and Presto. You can target either of them as they were always present together. For v15, Opera began using OPR in the UA.

} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Presto') !== FALSE) {
  echo '<link type="text/css" href="o.css" />';
} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'OPR') !== FALSE) {
  echo '<link type="text/css" href="normal.css" />';

Next up is Safari. Safari uses AppleWebKit as its rendering engine, but we can't just target that because Chrome also includes both AppleWebKit and Safari in its UA for compatibility reasons. Therefore, we need to search for AppleWebKit and not Chrome.

} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'AppleWebKit') && !strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== FALSE) {
  echo '<link type="text/css" href="webkit.css" />';

Finally, we get to Chrome. Chrome used AppleWebKit until v27. With the v28 release, they switched over to the Blink engine. We could target both engines but it would require a lot of code. Being that Chrome is almost to v70 now, we'll just search for Chrome as it's highly unlikely anyone is still running a webkit version of Chrome.

} elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== FALSE {
  echo '<link type="text/css" href="normal.css" />';

And last but not least, your fallback/else.

} else {
  echo '<link type="text/css" href="normal.css" />';
}

Now, I used css files referring to the vendor prefix to target here. Feel free to tweak this as needed to have it do what you need it to do. I hope this helped.

0

精彩评论

暂无评论...
验证码 换一张
取 消