Hack 87 A Universal Flash Plugin Sniffer 
Build a non-JavaScript-based Flash plugin
sniffer that won't need to be updated each time
Macromedia releases a new version of the Flash Player.
A Flash plugin sniffer is something
that tries to detect whether or not the Flash content within the
current web page is viewable by the browser. It does this by looking
for a particular installation of the Flash Player. The problem is
that prerequisites may have to be addressed before the sniffer itself
works correctly. Flash content that would have worked perfectly well
without a sniffer may never be reached if the sniffer itself fails!
This hack shows how to build a sniffer that has fewer prerequisites
and is thus very likely to work.
Traditional sniffers usually have to be updated whenever a new
version of the Flash Player is released. Worse still, traditional
sniffers are written in JavaScript and have notorious browser
dependencies. As the Hacks series editor Rael Dornfest once said,
"We contemplated a JavaScript Hacks book, but
everything in JavaScript is a hack." I
can't even look at a JavaScript manual any more
without giggling.
The upshot is that a JavaScript-based
Flash sniffer has a number of Achilles' heels:
The variability of JavaScript support in different browsers and the
differences in ways browsers identify (or fail to identify) the
presence of a given plugin. For example, detecting an ActiveX control
in Windows Internet Explorer is different than detecting a
Netscape-style plugin in Netscape and other browsers that
don't support ActiveX. Variability in the Flash plugin. Your sniffer may not recognize more
recent versions of the Flash plugin or versions for alternative
platforms, even if they can actually run your SWF. Whether the user has turned JavaScript support off in the current
browser (quite common in commercial organizations because it reduces
the probability of malicious JavaScript-based virus infections or
hacker Trojans), which will defeat any JavaScript-based sniffer
script altogether!
What we would really like is a Flash sniffer that
doesn't rely on JavaScript at all.
Wouldn't that be a cool hack to know?
Five Seconds and Counting...
The <meta> tag is an
HTML header tag that allows you to send information to the browser or
specialized browser plugins (such as screen readers for the sight
impaired). It is also used to present information for search engine
indexing purposes. This hack uses a particular ability of the
<meta> tag, the
client-pull. For more information, see
HTML & XHTML: The Definitive
Guide, fourth edition, by Chuck
Musciano and Bill Kennedy (O'Reilly), especially
section 13.2.1, "Uniquely
Refreshing."
Here is the syntax for the <meta> tag to
implement a client-pull:
<meta http-equiv="refresh" content="n; URL=newdoc.html">
A client-pull is simply a request for the browser to load a new HTML
document, in this case newdoc.html (which may
also include the full path to a new document, such as
http://www.myDomain.com/mydoc.html) after a
certain time delay, n, in seconds. Its
effect is much the same as if the user clicked on a hyperlink to
newdoc.html after the
n second time delay. For this hack, we set
the time delay to five seconds and specify that the browser should
load the document noflash.html.
We also embed a SWF inside our original HTML
file. The SWF uses the getURL(
) action to load an HTML page,
flash.html, containing our final Flash content.
Figure 11-2 shows the general process at work.

So what we have is an attempt to run a Flash SWF that executes a
getURL( ) action, which loads the Flash content
embedded in the flash.html web page. If that
works, we know Flash Player is installed. If it
doesn't execute, we know the appropriate Flash
Player is not present. But no worries—if Flash
doesn't change the current web page (using
getURL( ) to load
flash.html), the client-pull fires after five
seconds, loading our non-Flash HTML page, noflash.html.
Best of all, none of it is dependent on
JavaScript—the browser, OS platform, or user preferences.
Asking Flash to Run Itself
Let's
look more closely at the requirements for this hack.
Here are the steps:
Create a new Flash document and add the following script to frame 1
of the main timeline: getURL("flash.html", "_self");
Save the file as
index.fla. Publish the document with File Publish
Preview Default (HTML). This option creates the files
index.html and index.swf in
the same folder where you saved index.fla. The
two together will form our Flash sniffer. Open index.html in your HTML or text editor of
choice. The <head> section of the file will look
like this: <head>
<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
<title>index</title>
</head>
Add a new <meta> tag as shown in bold: <head>
<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
<meta http-equiv="refresh" content="5; URL=noflash.html">
<title>index</title>
</head>
Create your
noflash.html file. It should be one of the following:
In any case, your page should explain that Flash was not detected.
The page should also include a link for the user to run your
Flash-based site if she is sure she has the plugin installed. Nothing
so frustrates an end user as being told she doesn't
have the plugin because your automatic detection failed. So
don't unceremoniously send the user to the
Macromedia site to obtain the Flash plugin; leave it up to the user
to choose an appropriate course of action.
Place your flash.html and
someFlashMovie.swf (your Flash site) in the same
folder as index.html. To test your sniffer
locally, open index.html in a web browser. If
you're having trouble, see the basic files provided
on this book's web site.
Once that seems to be working, upload the files to your web server
and point your web browser to the URL where you uploaded the HTML
page, such as http://www.yourdomain.com/sniffertest/index.html.
To emulate a basic browser without any plugins, visit http://www.anybrowser.com. This site emulates
a plugin-free HTML 3.2-compatible browser—a perfect place to
test a Flash sniffer.
Making It a Bit More Discerning
Sometimes, you may find that early
versions of the Flash Player recognize the getURL(
) command, which has been supported since Flash Player 2,
but can't play all the content in your Flash
SWF-based site. An example of this might be if
you want to use Flash video, supported in Flash Player 6 and later,
but the user has Flash Player 5 installed. Flash Player 5 supports
getURL( ) but will not play the video embedded
in a SWF file. In this case, you need to check for a minimum Flash
Player plugin version.
Your Flash movie that checks the Flash Player version should itself
be a Flash Player 4- or Flash Player 5-format
.swf file. It can check the Flash Player version
and then load another .swf file, perhaps in
Flash Player 6 or Flash Player 7 format, that contains your real
Flash content.
To check the Flash Player version, use the Flash environment variable
$version. You can see the version in the
Variables tab of the Debugger panel, as shown in Figure 11-3, if you test a movie in debug mode.

The $version property is supported in Flash Player
4.0.11.0 and later. It returns a version string of the form
"platform
major,minor,build,patch",
where platform is either WIN, MAC, or UNIX
and the other items are numbers, such as "WIN
6,0,21,0". Don't use more modern
methods to retrieve the version, such as the getVersion(
) function (supported in Flash 5 and
later) or the
System.capabilities.version property (supported in Flash 6 and
later), unless you can ensure that the user has a more recent version
of the plugin. It is a pretty safe bet that users have at least Flash
Player 5 if they have any version installed, and more than 90% of
users have Flash Player 6 or later as shown in the Flash Player
census (http://www.macromedia.com/software/player_census/flashplayer/version_penetration.html).
Regardless, $version, getVersion(
), and System.capabilities.version,
when supported, all return the same string on a given platform.
The major revision number is at an offset of 4 (the fifth character)
in the $version string for Mac and Windows. Here
we use String.substr(
) to check whether the user has at least
Version 5 of the Flash Player. If so, it replaces the current page
with the flash.html site. Otherwise, it goes to
an error page that says, "You need to update your
Flash Player to at least Version 5."
if ($version.substr(4, 1) >= 5) {
getURL("flash.html", "_self");
} else {
getURL("old_flash.html", + "_self");
}
This script will fail and simply continue playing the SWF on Flash
Player 1, 2, and 3, but those versions are extremely old and
represent less than 1% of the installed base. The cool thing about
this hack is that you don't have to update this
detection system for users with Flash Player 6, Flash Player 7, or
future versions. If you want to support platforms that return
"UNIX" in the version string,
extract the major version number following the first space in the
string rather than assuming it starts at the fifth character.
Final Thoughts
The hack here relies on the absence of the Flash Player, which is
easier than actively determining the presence of the Flash Player. We
check the Flash Player version (if we need to) once we know that
Flash Player is present. Instead of trying to check the Flash Player
via JavaScript, we ask the Flash Player to identify itself.
Our sniffer is not susceptible to either JavaScript support or
revisions nor dependent on the version of the Flash Player plugin. At
a minimum, it relies only on the <meta> tag,
supported by Version 3.x browsers and later. At a maximum, it
requires a Flash Player plugin that can recognize the
if statement and $version
property, namely Flash Player 4 or higher.
Admittedly, the approach presented here is a hack—this is
Flash Hacks, after all—and is not
necessarily foolproof. Depending on their configuration, Internet
Explorer users without the Flash Player ActiveX control may be
prompted to install it. Depending on the timing (how long it takes
for the prompt to appear and for the user to respond), the user might
not be forwarded to your no-Flash page.
Plugin-detection scripts are always controversial and none are
perfect. Consider this technique one more arrow in your quiver rather
than a silver bullet (how's that for a mixed
metaphor!). See the resources in the introduction to this chapter for
more traditional browser-sniffing techniques.
|