Problem Solution Discussion Serving Banner Ads

SELECT type, data FROM image WHERE name = ?, undef, name or error Cannot find image with name name; } else { type = dbh-selectrow_array SELECT type FROM image WHERE name = ?, undef, name or error Cannot find image with name name; my fh = new FileHandle; my image_path = image_dir . path_sep . name; open fh, image_path or error Cannot read image_path: ; binmode fh; helpful for binary data my size = stat fh[7]; read fh, data, size == size or error Failed to read entire file image_path: ; fh-close ; } dbh-disconnect ; Send image to client, preceded by Content-Type: and Content-Length: headers. print header -type = type, -Content_Length = length data; print data; exit 0; ---------------------------------------------------------------------- sub error { my msg = shift; print header , start_html Error, p escapeHTML msg, end_html ; exit 0; }

17.9 Serving Banner Ads

17.9.1 Problem

You want t o display banner ads by choosing im ages on t he fly from a set of im ages.

17.9.2 Solution

Use a script t hat select s a random row from an im age t able and sends t he im age t o t he client .

17.9.3 Discussion

The display_im age.pl script j ust shown assum es t hat t he URL cont ains a param et er t hat nam es t he im age t o be sent t o t he client . Anot her applicat ion m ight det erm ine which im age t o display for it self. One popular im age- relat ed use for web program m ing is t o serve banner advert isem ent s for display in web pages. A sim ple way t o do t his is by m eans of a script t hat picks an im age at random each t im e it is invoked. The following Pyt hon script , banner.py, shows how t o do t his, where t he ads are t he flag im ages in t he image t able: usrbinpython banner.py - server randomly chosen banner ad from image table sends no response if no image can be found import sys sys.path.insert 0, usrlocalapachelibpython import MySQLdb import Cookbook conn = Cookbook.connect try: query = SELECT type, data FROM image ORDER BY RAND LIMIT 1 cursor = conn.cursor cursor.execute query row = cursor.fetchone cursor.close if row is not None: type, data = row Send image to client, preceded by Content-Type: and Content-Length: headers. The Expires:, Cache-Control:, and Pragma: headers help keep browsers from caching the image and reusing it for sucessive requests for this script. print Content-Type: s type print Content-Length: s len data print Expires: Sat, 01 Jan 2000 00:00:00 GMT print Cache-Control: no-cache print Pragma: no-cache print print data except MySQLdb.Error, e: pass conn.close banner.py sends a few headers in addit ion t o t he usual Content-Type: and Content-Length: headers. The ext ra headers help keep browsers from caching t he im age. Expires: specifies a dat e in t he past t o t ell t he browser t hat t he im age is out of dat e. The Cache-Control: and Pragma: headers t ell t he browser not t o cache t he im age. The script sends bot h headers because som e browsers underst and one, and som e t he ot her. Why suppress caching? Because if you dont , t he browser will send a request for banner.py only t he first t im e it sees it in a link. On subsequent request s for t he script , t he brower will reuse t he im age, which rat her defeat s t he int ent of having each such link resolve t o a random ly chosen im age. I nst all t he banner.py script in your cgi-bin direct ory. Then, t o place a banner in a web page, use an img t ag t hat invokes t he script . For exam ple, if t he script is inst alled as cgi- bin banner.py, t he following page references it t o include an im age below t he int roduct ory paragraph: -- bannertest1.html - page with single link to banner-ad script -- html head titleBanner Ad Test Page 1title head body bgcolor=white pYou should see an image below this paragraph.p img src=cgi-binbanner.py body html I f you request t his page, it should display an im age, and you should see a succession of random ly chosen im ages each t im e you reload t he page. I am assum ing here t hat you have loaded several im ages int o t he image t able by now using t he load_im age.pl script discussed in Recipe 17.7 . Ot herwise you m ay not see any im ages at all I f you m odify banner.py not t o send t he cache- relat ed headers, you likely will see t he sam e im age each t im e you reload t he page. The cache- cont rol headers suppress caching for links t o bannery.py t hat occur over t he course of successive page request s. Anot her com plicat ion occurs if m ult iple links t o t he script occur w it hin t he sam e page. The following page illust rat es what happens: -- bannertest2.html - page with multiple links to banner-ad script -- html head titleBanner Ad Test Page 2title head body bgcolor=white pYou should see two images below this paragraph, and they probably will be the same.p img src=cgi-binbanner.py img src=cgi-binbanner.py pYou should see two images below this paragraph, and they probably will be different.p img src=cgi-binbanner.py?image1 img src=cgi-binbanner.py?image2 body html The first t wo links t o banner.py are ident ical. What youll probably find when you request t his page is t hat your browser will not ice t hat fact , send only a single request t o t he web server, and use t he im age t hat is ret urned where bot h links appear in t he page. As a result , t he first t w o im ages displayed in t he page will be ident ical. The second t wo links t o banner.py show how t o solve t his problem . The links include som e ext ra fluff at t he end of t he URLs t hat m ake t hem look different . banner.py doesnt use t hat inform at ion at all, but m aking t he links look different fools t he browser int o sending t wo im age request s. The result is t hat t he second t wo im ages will differ from each ot her—unless banner.py happens t o random ly select t he sam e im age bot h t im es, of course.

17.9.4 See Also