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

  • M2-HAT.jpg
  • screenshot-openmediavault-storage%0Ashared-folders%0Aacl-file-access-control-lists.png
  • openmediavault-dashboard.png
  • openmediavault.png
  • new-world-record.png
  • iceland.png
  • poppy-wars.png
  • sardinia-small.png
  • jong-tegen-oud-2024.png
  • tegen-par-2024-2nd-place.jpeg
  • stanford-reunion.png
  • kiff.png

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 23 years, 9 months and 15 days old.

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

Important events

Graduated from Stanford 45 years and 11 months ago.

Kiffin Rockwell was shot down and killed 108 years, 7 months and 10 days ago.

Believe it or not but I am 67 years, 6 months and 25 days young.

First met Thea in Balestrand, Norway 44 years, 10 months and 21 days ago.

Began well-balanced and healthy life style 12 years, 3 months and 27 days ago.

My father passed away 24 years, 6 months and 16 days ago.

My mother passed away 7 years, 1 month and 9 days ago.

Started Gishtech 9 years and 10 days ago.