The Internet was funded by the National Science Foundation; however, with the entry of the everyday user into Cyberspace, that funding was eliminated a few years ago. This places the burden of paying for the hardware, software, and telephone connections on the private sector. This expense is felt by all of us, directly or indirectly. It becomes clear as you surf the Web through an ever increasing number of sites that display advertising from a variety of clients. A common method of displaying advertisements is in the form of a "banner" or "billboard" graphic which, when clicked, takes the user directly to the advertiser's site.
Whether you agree with Web advertising or not, at some point in time you may encounter a situation where you'll need to incorporate it into a site.
If you have access to the CGI layer of your Web server, it's simple to maintain a list of advertisers and display graphic hyperlinks. Two separate files are required:
As with all scripts in this book, the full source code is found on the companion CD-ROM. The following sections touch on the code's highlights.
The "billboard database" is as simple as a flat text file with one advertiser per line. Each line or record needs to contain two fields:
The easiest way to handle this is to use a delimiter as a field separator. A delimiter is a character that never occurs in either field. Because Perl is a wonderful text processor, parsing a line into individual fields is simple. For example, assuming that the | character was used as a delimiter, a sample database would look something like:
eff_gry_lg.gif|http://www.eff.org/ cigjs.gif|http://www.visi.com/~sjwalter/javascript/
A Perl fragment that demonstrates how to load a flat text file into two Perl arrays, one for image URLs, one for hyperlinks, is shown in listing 8.1.
Listing 8.1 Parsing the Database
open (BILLBOARDS, 'billboards.dat'); while (<BILLBOARDS>) { ($image, $url) = split (/\|/, $_); chop $url; push (@imageURLs, $image); push (@linkURLs , $url); } close (BILLBOARDS);
When the while loop is finished, "imageURLs" and "linkURLs" contain all the image and hyperlink URLs from the database. Selecting a pair of URLs randomly then involves generating a random number:
$which = int(rand(@imageURL));
and using it to index into the respective arrays:
$theImage = $imageURLs[$which]; $theLink = $linkURLs[$which];Dynamically Generating HTML
Chapter 1 "Browser Identification," introduced a method of wrapping HTML files with a CGI script that selects different files based on the specific type of browser. Once the correct HTML file was identified, it was opened and sent from Perl back to the server for transmission to the browser. The same technique must be used here, because Perl needs to process the HTML file before the server feeds it back to the browser.
NOTE |
An alternative technique would be to use server-side includes. This technique enables you to embed references to CGI scripts into your HTML files. These server-processed files (included in the data stream) then pass to the browser. For an example of billboards built around server-side includes, see the companion CD-ROM. |
The code fragment that handles the file opening and processing task is shown in listing 8.2.
Listing 8.2 Opening and "Printing" a File through Perl
print "Content-type: text/html\n\n"; ... open (HTML, "<", $htmlFile); while (<HTML>) { print; } close (HTML);
The while loop does the bulk of the work, and reads in
the HTML document one line at a time and prints it back to standard
output. From inside CGI, standard output corresponds to the input
stream of the server which turns around and sends the data back
to the browser for formatting.
A Little File Trick in Perl |
If you didn't have to parse the file and just wanted to send it from the server to the user's browser, you could dispense with the while loop altogether: open (HTML, "<$htmlFile"); print <HTML>; close (HTML); which would route the entire file directly to standard output; that is, back to the server and on to the user. This is especially good if you want to send an image file (a graphic) from the server: open (GIF, "<myimage.gif"); print <GIF>; close (GIF); However, if you are going to send a graphic, you should also turn off buffering, as CGI scripts are usually "buffered" and don't actually transmit their data until they finish, with the following statements before the code that transmits the image file: select(stdout); $| = 1; |
Inside the while block, you have access to a new line from the HTML file with each iteration through the loop. This means that you can examine each line for a flag, or token, and replace the flag with some custom HTML. One example is the link for the billboard, and this is exactly how the billboard system works.
For example, if the following line were used as a placeholder for an advertisement:
<!-- BILLBOARD -->
modifying the while loop to:
while (<HTML>) { if(/\<\!-- BILLBOARD --\>/) { print &BillboardLink; } else { print "$_"; } }
would replace any references to <!-- BILLBOARD --> with a hyperlink and graphic from the database of advertisers. The BillboardLink function does the actual HTML creation, and takes the randomly selected billboard and formats the HTML tags (see listing 8.3).
Listing 8.3 Perl-Generated HTML
sub BillboardLink { $which = int(rand(@imageURL)); print "<A HREF=\"$imageURLs[$which]\">"; print "<IMG SRC=\"$linkURLs[$which]\"></A>"; }
For security reasons, VBScript and JavaScript, like databases, aren't permitted to load external files from the server. To get around this, you need to incorporate the billboard database into the HTML file. This can be done in one of two ways:
Source codes for both methods are on the companion CD-ROM. The second method does use some additional tricks that warrant further discussion in the following section.
While JavaScript provides a basic collection of objects dealing with various parts of the browser, the billboard database needs a customized object with two properties: the URL of the image to display and the URL of the associated hyperlink. This requires creating a user-defined object.
To create your own objects, you first need to write a function whose name is the same as the object you wish to define (like Billboard). Initialize any properties of the object within the body of the function. For the billboard database, each object is one graphic with its associated link, so the initializer function would look like the one shown in listing 8.4.
Listing 8.4 Defining a Billboard Object
function Billboard(strImageURL, strLinkURL) { this.imageURL = strImageURL; this.linkURL = strLinkURL; return this; }
NOTE |
User-defined objects can also hold methods as well as properties. If you wish to associate a method to an object, you must first define the function function aNewFunction(...) { ... } then hook it to a property of the object in the constructor function: this.aNewFunction = aNewFunction; Once this is done, whenever a new object of this type is created, it will also have the aNewFunction() method associated with it. An example of this trick in action is available on the CD-ROM. |
Now that the initializer function is defined, creating new Billboard objects is as simple as using the JavaScript new operator:
myBillboard = new Billboard('ad.gif', 'http://mysite.com/');
TIP |
A parameter that does not pass to the function even though the function specifies it, is considered not defined. In JavaScript, any parameter that's not defined is assumed to be null, so a statement such as: anotherBillboard = new Billboard(); is valid, and would create a Billboard object with both its properties set to null. This is a handy trick when you want to allocate space for an object, but you won't know what the property values are until later. These reveal, for example, when computed by another function or retrieved from a form. |
Once you create objects, you access them and their properties the same way you would access any of the built-in objects of JavaScript.
Creating an array is an excellent way to make your advertisement objects easier to handle. Arrays are constructed in a manner similar to building user-defined objects. First, create a function that initializes the array, then fill it with objects. An array-creation function (listing 8.5) differs from an object-creation function in that it has elements (accessed through subscripts) instead of properties. Each element is an independent object. The one property an array does have is the length property, which holds the size, or number of elements and objects of the array.
Listing 8.5 Initializing an Array
function initArray(iSize) { this.length = iSize; for(var i=1; i<=iSize; i++) this[i] = null; return this; }
CAUTION |
With the release of Navigator 3.0, Netscape has extended JavaScript to include a real Array object. However, because this is only supported by Navigator 3.0, the method shown in listing 8.5 is still the recommended technique (until surfers stop using Navigator 2.x and Internet Explorer catches up). |
Array Indexes in JavaScript |
If you were to examine the source code on various sites around the Web, you may find a function similar to initArray(), but with a for loop that starts at 0 instead of 1: for(var i=0; i<iSize; i++) this[i] = null; with the element indexing starting at 0 as well. If all the array holds is simple properties, this doesn't cause a problem, which is why many pages that initialize arrays in this manner still work. However, if the array elements are objects (either built-in or user-defined), this method has the side effect of destroying the value stored in the length property, making the array more difficult to manage. Whether dealing with properties or objects, it's best to index your arrays from 1 instead of 0. |
With the function defined, creating the array and loading it with advertisers becomes simple:
advertisers = initArray(5); // 5-element array advertisers[1] = new Billboard(...); ... advertisers[5] = new Billboard(...);
TIP |
If you aren't sure how big an array should be, don't worry. JavaScript supports dynamic resizing, which enables you to initialize additional elements long after you originally created the array. For example, if you started with an array of 10 elements: myArray = new initArray(10); And you need to store an additional (11th) element, just store it: myArray[11] = newElement; and JavaScript takes care of the rest. It even includes updating the value stored in the length property to reflect the new size of the array. Just remember that whatever new element you initialize, the size of the new array also includes any elements between the new element and the previous high index. In other words, if you started with 10-element array and added an element at index 100: myArray[100] = newElement; "myArray" would be resized to also initialize elements 11 through 99 (to null). |
With the basis for the billboard database finished, all that's left to write is the code to generate the hotlink and graphic tag for a randomly selected advertiser from the database. A demonstration of the script fragment that selects an advertiser and constructs the HTML code from the advertisers array built earlier appears in listing 8.6.
Listing 8.6 Pick an Advertiser, Any Advertiser
... advertisers = new initArray(5); advertisers[1] = new Billboard(...); ... function random(iMax) { var now = new Date(); var time = now.getTime(); return (time / 10) % iMax; } function buildHTML() { var iWhich = random(advertisers.length); return "<A HREF=\"" + advertisers[iWhich].linkURL + "\" " + "TARGET=\"_top\"><IMG SRC=\"" + advertisers[iWhich].imageURL + "\">"; }
TIP |
While not shown in the above example, it's a good idea to include WIDTH and HEIGHT attributes in your <IMG> tags for two reasons. First, some versions and platforms of Navigator may crash when asked to display an object that isn't pre-sized by the attributes. Second, and perhaps more important, the inclusion of WIDTH and HEIGHT speeds up page loading. When a browser is given an image without size designations, extra steps and time must be taken to read that information from the image file. This delays the page from formatting until that information retrieves. Adding the WIDTH and HEIGHT attributes lets the browser layout the page as quickly as possible. |
Unless your site is configured with frames, the inclusion of the TARGET attribute isn't necessary. It's a nice touch, however, that ensures that your advertiser gets complete run of the browser's client area. Calling the buildHTML() function from inside the HTML body itself is academic:
document.write(buildHTML());
and can be placed anywhere-centered on the page, in a table for automatic formatting, or in a separate frame.
This chapter introduces several tricks for automating advertising on your Web pages, and also shows you how to handle scripting arrays consisting of complex objects. For more information on related tricks, check out: