We can detect which browser we are dealing with on the client itself using scripting, or on the server with either scripting or a special Active Server component. We’ll start with the client-side techniques. These allow us to detect the version, and hence the capabilities of the browser, inside a page that we provide.
All browsers that support scripting also provide a standard set of objects, as part of their Document Object Model (DOM). In fact this is a bit of a misnomer, because the objects also provide information about the browser itself, and not just the document (or page) it is displaying. The object we're interested in is the navigator object—probably named as such because the first browsers were often referred to as 'navigators', and Netscape adopted this as their product name.
The navigator object, a sub-object of the main top-level window object, provides the three useful properties userAgent, appName and appVersion. The userAgent property contains the string that completely identifies the browser, and is sent to the server in the HTTP headers with each page request it makes. The appName and appVersion properties are available only in client-side script, and contain the manufacturer's name and the browser version in a more readable format.
The following code, which you'll find on our Web site at http://webdev.wrox.co.uk/books/1797/, writes the values of the three properties into the page using client-side script when you load it. It also provides some information about your chosen browser, by analyzing the property values. We've highlighted the script code to make it easier to see what's going on:
<HTML>
<HEAD><TITLE>Detecting the browser type</TITLE></HEAD>
<BODY>
<H3>Details of your browser</H3>
<TABLE>
<TR>
<TD ALIGN="RIGHT">navigator.userAgent:</TD>
<TD><B>
<SCRIPT LANGUAGE="JavaScript">
<!--
document.write(navigator.userAgent)
//-->
</SCRIPT></B>
</TD>
</TR>
<TR>
<TD ALIGN="RIGHT">navigator.appName:</TD>
<TD><B>
<SCRIPT LANGUAGE="JavaScript">
<!--
document.write(navigator.appName)
//-->
</SCRIPT></B>
</TD>
</TR>
<TR>
<TD ALIGN="RIGHT">navigator.appVersion:</TD>
<TD><B>
<SCRIPT LANGUAGE="JavaScript">
<!--
document.write(navigator.appVersion)
//-->
</SCRIPT></B>
</TD>
</TR>
</TABLE><P>
<SCRIPT LANGUAGE="JavaScript">
<!--
if (navigator.appName.indexOf('Netscape') != -1) {
document.write('To upgrade your browser go to ' +
'<A HREF="http://home.netscape.com/download/">' +
'http://home.netscape.com/download/<\/A><\/P>');
if (navigator.appVersion.substr(0, 1) > 3)
document.write('You can use Netscape Dynamic HTML');
}
if (navigator.appName.indexOf('Microsoft') != -1) {
document.write('To upgrade your browser go to ' +
'<A HREF="http://www.microsoft.com/ie/">' +
'http://www.microsoft.com/ie/<\/A><\/P>');
if (navigator.appVersion.substr(0, 1) > 3)
document.write('You can use Microsoft Dynamic HTML');
}
//-->
</SCRIPT>
<NOSCRIPT>
Sorry, your browser doesn't support client-side scripting,
so it can't display the details about your browser.
</NOSCRIPT>
</BODY>
</HTML>
Note that, where we have closing HTML tags, we include a backslash character in the string we write to the document. For example, '..<\/A><\/P>
'. According to the W3C standards, a combination of a forward slash character followed immediately by an alphabetic character indicates the end of a <SCRIPT>
section. So, if we are trying to write any closing HTML tags with document.write
, we must declare at least part of the 'illegal' combination within the string as being a character literal. In JavaScript we can do this with a backslash, here placed before the forward slash. In VBScript, we usually replace the forward slash with Chr(47)
. However, most browsers don’t follow the W3C rule, and will only accept </SCRIPT>
as a closing script tag. But it's wise to play safe...
Here are the results with Internet Explorer 4 and Navigator 4:
So, we can quite easily detect the browser type using script running in the page on the client. We'll see how we might use this later on. However, it's not always as straightforward as you might imagine. For example, here's what the page looks like when you open it in Opera:
Whoops, a wrong hyperlink for the upgrade. But whose fault is this? Look at the value of the navigator.appName property—
'Netscape'!
Obviously we can only use client-side script when the browser supports this. If you look back at the end of the code we used earlier, you'll see that we tried to trap this problem using a <NOSCRIPT>
section, which contains a note to the viewer explaining why they can’t see any browser details. An easy way to prevent this occurring is to do the work on the server instead of on the client. There are two basic ways of achieving this, either by analyzing the HTTP USER-AGENT
value sent from the browser, or with a special component that can do the spadework for us.
When we get a page request from a browser or user agent, it should provide a value for the USER-AGENT
string within the HTTP headers. We saw this when we looked at the contents of the Request.ServerVariables
collection in Chapter 2. We can quite easily look at the string, and decide the browser type. The ASP code below does just that, and provides a similar result with Internet Explorer and Navigator as our previous client-side page (we can't get at the appName
and appVersion
properties, which are only available to script running on the browser, so these are omitted):
<%@ LANGUAGE=VBSCRIPT %>
<% strUA = Request.ServerVariables("HTTP_USER_AGENT") %>
...
<TABLE>
<TR>
<TD ALIGN="RIGHT">navigator.userAgent:</TD>
<TD><B><% = strUA %></B>
</TD>
</TR>
</TABLE>
<P>
<%
QUOT = Chr(34)
If InStr(strUA, "MSIE") Then 'its a Microsoft Browser
Response.Write "To upgrade your browser go to " _
& "<A HREF=" & QUOT & "http://www.microsoft.com/ie/" _
& QUOT & ">http://www.microsoft.com/ie/</A></P>"
intVersion = CInt(Mid(strUA, InStr(strUA, "MSIE") + 5, 1))
If intVersion > 3 Then
Response.Write "You can use Microsoft Dynamic HTML"
End If
Else
If InStr(strUA, "Mozilla") Then 'its a Netscape-compatible browser
If InStr(strUA, "compatible;") = 0 Then 'its probably a Netscape browser
Response.Write "Your browser is probably Navigator. You can " _
& "download the latest verion of Navigator from " _
& "<A HREF=" & QUOT & "http://home.netscape.com/download/" _
& QUOT & ">http://home.netscape.com/download/</A></P>"
intVersion = CInt(Mid(strUA, InStr(strUA, "/") + 1, 1))
If intVersion > 3 Then
Response.Write "You can probably use Netscape Dynamic HTML"
End If
Else 'not Netscape, so we'll allow the user to search on the Web for it
strVersion = Mid(strUA, InStr(strUA, "compatible;") + 12)
strProduct = Left(strVersion, InStr(strVersion, ";") - 1)
strSearchURL = "http://www.altavista.digital.com/cgi-bin/query?q=" _
& strProduct & " web browser"
Response.Write "Your browser is Navigator-compatible. You can " _
& "search for the manufacturer using a search engine, such as " _
& "<A HREF=" & QUOT & strSearchURL & QUOT & ">" & strSearchURL & "</A></P>"
End If
End If
End If
%>
...
In the code above, for Internet Explorer, we just look for the sub-string MSIE in the user agent string. We get the version from the part of the string after MSIE:
If InStr(strUA, "MSIE") Then 'its a Microsoft Browser
...
intVersion = CInt(Mid(strUA, InStr(strUA, "MSIE") + 5, 1))
Here's the result, when viewed in IE 4:
However, Navigator is a bit more of a problem. Because Netscape believe that they invented browsers (in fact Mosaic was the first one), Netscape don’t think they should have to put their product name into the user agent string. They begin it with Mozilla (the development code-name for Navigator), but everyone else does as well, because early server-side code routines expected this and the newcomers to the browser manufacturing game didn’t want their browser rejected by the server.
The end result is that we can only tell if it's not Netscape Navigator—if we find the sub-string compatible within the user agent string we know it's something else. If we don't find it, we can almost certainly assume that it's Navigator—though it might not always be. And if it really is Navigator, the version number follows the first slash character in the string (directly after the word Mozilla). Here's the relevant section from the ASP code we used earlier:
If InStr(strUA, "Mozilla") Then 'its a Netscape-compatible browser
If InStr(strUA, "compatible;") = 0 Then 'its probably a Netscape browser
...
intVersion = CInt(Mid(strUA, InStr(strUA, "/") + 1, 1))
Here's the result in Navigator 4:
If the user agent string contains the word compatible
followed by a semi-colon, the next word is usually the manufacturer or browser name. Following the same style as we did with the other two browsers, but not knowing the manufacturer's web address, we can use this approach to make it easy for visitors to search for their browser manufacturer on the Web if they need an upgrade.
This code runs when we know that it's not a Microsoft browser, and that it's probably not a Netscape browser either. It pulls the manufacturer's name or browser name out of the user agent string, and puts it in a hyperlink to the AltaVista search engine:
Else 'not Netscape, so we'll allow the user to search on the Web for it
strVersion = Mid(strUA, InStr(strUA, "compatible;") + 12)
strProduct = Left(strVersion, InStr(strVersion, ";") - 1)
strSearchURL = "http://www.altavista.digital.com/cgi-bin/query?q=" _
& strProduct & " web browser"
Response.Write "Your browser is Navigator-compatible. You can " _
& "search for the manufacturer using a search engine, such as " _
& "<A HREF=" & QUOT & strSearchURL & QUOT & ">" & strSearchURL & "</A></P>"
Here's how this works in Opera:
We've spent some time on the contents of the user agent string, because it's useful to know how to interpret it. However, there are components we can use to make identifying browsers easier and more accurate. The downside is that they are likely to impose a heavier load on the server than the few simple lines of script we've used so far.
ASP comes complete with a component called the Browser Capabilities component. We met this in Chapter 2, when we used it to figure out if the browser we were serving to supported frames:
...
Set objBCap = Server.CreateObject("MSWC.BrowserType")
If Not(objBCap.frames) Then Response.Redirect "mainpage.asp" 'no frames support
...
The Browser Capabilities component uses the user agent string sent from the browser to identify it as accurately as possible. In most cases, for all the common browsers, it will identify it absolutely. This means that it can accurately report the various abilities of that browser in detail.
The information about all the browser types is stored in a text file named browscap.ini
, located in the same folder as the component on the server. The default is Winnt\System32\inetsrv\
(or whatever the path to the %system32%
folder actually is on your machine). In this file are sections for each browser user agent string, for example:
;;ie 4 final release
[Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)]
parent=IE 4.0
platform=Win95
beta=False
The third line shows that the parent
for this entry is the entry for IE 4.0
, and that only the platform
and beta
entries differ from those of the parent. The parent
entry (elsewhere in the file) looks like this:
[IE 4.0]
browser=IE
Version=4.0
majorver=4
minorver=0
frames=TRUE
tables=TRUE
cookies=TRUE
backgroundsounds=TRUE
vbscript=TRUE
javascript=TRUE
javaapplets=TRUE
ActiveXControls=TRUE
Win16=False
AK=False
SK=False
AOL=False
crawler=False
cdf=True
Each of the entries in the file is available as a property of the component, so we can do things like this:
...
Set objBCap = Server.CreateObject("MSWC.BrowserType")
'see if this browser supports ActiveX Controls
If objBCap.ActiveXControls Then %>
'HTML here to define the ActiveX Control for presenting some information
<% Else %>
'HTML here to use a different way of presenting the information
<% End If %>
...
Note how the component exposes the browser make and version, which saves us having to use script to get at it like we did earlier:
...
strBrowserName = objBCap.browser 'a string defining the manufacturer
sngBrowserVersion = CSng(objBCap.Version) 'a number for use in comparison tests
...
You can edit the file yourself, and add other browsers. You can also add extra properties, because the component automatically exposes all the entries it finds as properties. So, you could add the Web Home page URL for each browser to the file if you wanted, making it easy to display it as a link (like we did with ASP in our previous example). The file also accepts wildcards, so you can—to some extent—future-proof for new browser versions. For instance, an asterisk (*
) matches any combination of characters; so that [Mozilla/2.0
(compatible;
MSIE 4.*;
Windows
95)]
means any MSIE version 4 browser.
The Windows NT4 Option Pack and NT5 documentation contain more details about the Browser Capabilities component. Look up Browser Capabilities component (IIS) in the Index. You can also download the latest version of the browscap.ini
file from http://www.cyscape.com/browscap/ or direct from Microsoft at http://www.microsoft.com/iis/support/iishelp/iis/htm/asp/comp1g11.htm.
While the Browser Capabilities component is a great deal quicker, easier and more accurate than our attempts at browser detection with script, it's still not perfect. Another approach is taken by CyScape Inc, who not only provide updated versions of browscap.ini
, but also manufacture a component called BrowserHawk. This recognizes many more different types of browsers, and provides a lot more information about each one. You'll find CyScape at http://www.cyscape.com/
BrowserHawk can tell you if the browser supports Style Sheets and CSS, File Uploads, SSL encrypted communication, as well as many other features. In fact there is a whole section of the site devoted to the advantages of BrowserHawk over the Browser Capabilities component, starting at http://www.cyscape.com/browserhawk/intro.asp.
To change over from the Browser Capabilities component to BrowserHawk is easy. You just change the class string in the Server.CreateObject
statement that creates the component instance. The remainder of your code (according to CyScape) will continue to work as normal. For more information, or to download an evaluation copy of BrowserHawk, go to http://www.cyscape.com/.