Random banner

| Perl | 4 Comments

As you have probably already noticed, I recently implemented a random banner to be displayed on the main page of my website. By clicking refresh a few times you can see it working. Slowly but surely I will add more banners to my collection. It's an elegant way of enabling such a feature, so I thought that it'd be nice to share it with anyone interested.

Basically I create and then keep a bunch of 905x170 pictures which I save in the images directory. These can be randomly displayed in the banner div#homepage-image which is inserted using the /cgi-bin/rand-banner.pl random banner generator script.

This is made possible by including the following lines in the css file:

/* custom.css */
...
/* Banner is randomly generated */
#homepage-image { background-image: url('/cgi-bin/rand-banner.pl'); }
...

This script is run automatically every day by including the following line in the crontab:

@daily /www/kiffingish.com/cgi-bin/rand-banner.pl crontab

For those interested, I have also included the perl script which does all of the magic. It should be pretty straight-forward what this script does, which shows you the power of perl.

#!/usr/bin/perl

use strict;
use warnings;

# rand-banner.pl [crontab] :
# If called with 'crontab' just create the file list of banners,
# otherwise return the binary contents of a random banner immage
# for displaying on a web page.

use CGI;
my $cgi = new CGI;

# Directories based from root dir.
my $root_dir = "/path/to/root/dir";
my $cgi_dir = "$root_dir/cgi-bin";
my $doc_dir = "$root_dir/docs";
my $img_dir = "$doc_dir/images";
my $banners_lst = "banners.lst";

# Coversion file ext to http img/type.
my %ext2typ = ( bmp => 'bmp',
                gif => 'gif',
                jpeg => 'jpeg',
                jpg  => 'jpeg',
                png  => 'png',
                tif  => 'tiff',
                tiff => 'tiff',
);

# Only interested in the following file types.
my $img_filter = join(',', keys %ext2typ);

# If called with 'crontab' or banners.lst does not exist, collect
# list of banners from 905x170 files in images directory.
my $crontab = (defined($ARGV[0]) && ($ARGV[0] eq 'crontab'));
if ($crontab || (! -f $banners_lst)) {
    # See: http://www.imagemagick.org/script/identify.php
    my $output = `identify $img_dir/*.{$img_filter} 2>/dev/null |grep ' 905x170 ' | sed 's/\\[.*//' | sed 's/^.*\\///'`;
    open my $fh, ">", $banners_lst or die "Cannot open file '$banners_lst' for writing ($!)";
    print $fh $output;
    close $fh;
}

# All done if called from crontab.
exit if $crontab;

# Grab the latest banner list.
open my $fh, "<", $banners_lst or die "Cannot open file '$banners_lst' for reading ($!)";
my @banners = <$fh>;
close $fh;

# Take a random item from the list.
my $banner = $banners[rand @banners];
chomp($banner);

# Define banner image filepath.
$banner =~ /^.*\.(.*)$/;
my $ext = $1;
my $img = "$img_dir/$banner";

# Get the binary contents of the image file.
open (IMAGE, $img) or die "Cannot open image file '$img' for reading ($!)";
my $size = -s $img;
my $data;
read IMAGE, $data, $size;
close (IMAGE);

# Return image data to the caller. Be sure to disable caching so
# that each new request returns a new banner image.
print "Content-type: image/$ext2typ{$ext}\n";
print "Cache-Control: max-age=0, no-cache, no-store, must-revalidate\n";
print "Pragma: no-cache\n";
print "Expires: Wed, 11 Jan 1984 05:00:00 GMT\n";
print "\n";
print $data;

This might seem like alot of work for something very simple, but the challenge was worth it for me. I kind like this little added feature to my website. Have fun using it.

4 Comments

You are using the 3-argument form of open(), which is good, but you missed one spot. Now I'm pretty sure there's no file named "foo | some-dangerous-command" in your banner dir :-)

I object to line 39. Calling 'grep' and 'sed' from Perl is an abomination in the eyes of God ;-> And the "$img_dir/*.{$img_filter}" syntax depends on your shell being bash or zsh, but is not compatible with some other shells, like dash.

Besides, http://search.cpan.org/~jcristy/PerlMagick-6.86/Magick.pm is here so we don't need to call ImageMagick binaries - in this particular case, Ping() method can be used to get the dimensions of a particular image file, while the list of candidate files in a directory can be obtained by using readdir() or, probably more easily, glob().

Yes, I am a purist. And a nitpicker.

Random entries

Here are some random entries that you might be interested in:

Recent Assets

  • tegen-par-2024-2nd-place.jpeg
  • stanford-reunion.png
  • kiff.png
  • hoid.png
  • Dad-in-front-of-log-cabin.png
  • mistborn-trilogy.png
  • 2024-03-Heren1-27h.png
  • three-body-problem.png
  • 10CC.png
  • minds-and-machines.jpeg
  • puglia.png
  • 2023-09-24-jong-tegen-oud-1.jpg

Recent Comments

  • Random banner: You are right about making the sed and grep system ...
    - Kiffin
  • Random banner: I object to line 39. Calling 'grep' and 'sed' from ...
    - blotosmetek
  • Random banner: Thanks for the heads up. That's a good point you m ...
    - Kiffin
  • Random banner: You are using the 3-argument form of open(), which ...
    - stevenharyanto

Golf Handicap

Information

This personal weblog was started way back on July 21, 2001 which means that it is 7-21-2001 old.

So far this blog contains no less than 2518 entries and as many as 1877 comments.

Important events

Graduated from Stanford 6-5-1979 ago.

Kiffin Rockwell was shot down and killed 9-23-1916 ago.

Believe it or not but I am 10-11-1957 young.

First met Thea in Balestrand, Norway 6-14-1980 ago.

Began well-balanced and healthy life style 1-8-2013 ago.

My father passed away 10-20-2000 ago.

My mother passed away 3-27-2018 ago.

Started Gishtech 04-25-2016 ago.