13.2.2.1. Redundant path information
Unfortunately, there are some browsers (specifically some versions of
Internet Explorer) that sometimes pay more attention to the extension
of a resource they are fetching than to the HTTP media type header.
According to the HTTP standard, this is wrong of course, and probably
an accidental bug, but if you want to accommodate users of these
browsers, you may wish to append redundant path information onto URLs
to provide an acceptable file extension:
<IMG SRC="/cgi/survey_graph.cgi/survey.png" >
The web server will still execute
survey_graph.cgi, which generates the image
while ignoring the additional /survey.png path information.
Incidentally, adding false path information like this
is a good idea whenever your CGI script is
generating content that you expect users to save, because browsers
generally default to the filename of the resource they requested, and
the user probably would rather the file be saved as
survey.png than
survey_graph.cgi.
For CGI scripts like random_image.cgi that
determine the filename and/or extension dynamically, you can still
accomplish this with redirection. For example, we could replace the
line that sets $image in
random_image.cgi (Example 13-1)
with the following lines:
my( $image ) = $q->path_info =~ /(\w+\.\w+)$/;
unless ( defined $image and -e IMAGE_DIRECTORY . "/$image" ) {
$image = random_file( IMAGE_DIRECTORY, '\\.(png|jpg|gif)$' );
print $q->redirect( $q->script_name . "/$image" );
exit;
}
The first time this script is accessed, there is no additional path
information, so it fetches a new image from our
random_file function and redirects to itself
with the filename appended as path information. When this second
request arrives, the script retrieves the filename from the path
information and uses this if the filename matches our regular
expression and it exists. If it isn't a valid filename, the
script acts as if no path had been passed and generates a new
filename.
Note that our filename regular expression,
/(\w+\.\w+)$/, prevents any images in our image
directory that have characters not matched by \w
from being displayed, including images that contain hyphens.
Depending on the filenames you are using, you may need to adjust this
pattern.
13.2.2.2. Preventing caching
In Example 13-1, we generated an
Expires HTTP header in order to discourage
caching. Unfortunately, not all browsers respect this header, so it
is quite possible for a user to get a stale image instead of a
dynamic one. Some browsers also try to determine whether a resource
is generated dynamically by something such as a CGI script or whether
it is static; these browsers seem to assume that images are static,
especially if you append additional path information as we just
discussed.
There is a way to force browsers not to cache images, but this
requires that the tag for the image also be dynamically generated. In
these circumstances, you can add a value that constantly changes,
such as the time in seconds, to the URL:
my $time = time;
print $q->img( { -src => "/cgi/survey_graph.cgi/$time/survey.png" } );
By adding the time to the additional path information, the browser
views each request (more than a second apart) as a new resource.
However, this technique does fill the browser's cache with
duplicate images, so use it sparingly, and always combine this with
an Expires header for the sake of browsers that
support it. Adding a value like this to the query string also works:
print $q->img( { -src => "/cgi/survey_graph.cgi/survey.png?random=$time" } );
If nothing else on the HTML page is dynamic, and you do not wish to
convert it to a CGI script, then you can also accomplish this via a
server-side include (see Chapter 6, "HTML Templates"):
<!--#config timefmt="%d%m%y%H%M%S" -->
<IMG SRC="/cgi/survey_graph.cgi/<!--#echo var="DATE_LOCAL"-->/survey.png">
Although this is a little hard to read and is syntactically invalid
HTML, the SSI tag will be parsed by an SSI-enabled server and
replaced with a number representing the current date and time before
it is
sent to
the
user.