astroboy has asked for the wisdom of the Perl Monks concerning the following question:

I have a web page which shows a list of images. Users can click on a link next to each image to rotate them either left or right. The page is refreshed and the images re-displayed

The problem is, the images are being cached, so the previous orientation is being shown. I have tried setting the headers using CGI::Application as following (slightly modified from overkill anti-caching CGI headers):

# Set a last-modified date a little in the future to handle # local workstation times being slightly out. Is that valid? my $date = DateCalc('today', '+ 5 minutes'); $date = Date_ConvTZ($date, "", "GMT"); $self->header_add( -expires => 'Sat, 26 Jul 1997 05:00:00 GMT', -Last_Modified => UnixDate($date, '%a, %d %b %Y %H:%M:%S GMT') +, # HTTP/1.0 -Pragma => 'no-cache', # HTTP/1.1 -Cache_Control => join(', ', qw( no-store no-cache must-revalidate proxy-revalidate post-check=0 pre-check=0 max-age=0 s-maxage=0 )), );

An example of the produced header:

Date: Tue, 27 Mar 2007 03:52:20 GMT Server: Apache/1.3.34 (Unix) mod_fastcgi/2.4.2 PHP/5.0.5 Expires: Sat, 26 Jul 1997 05:00:00 GMT Pragma: no-cache Last-Modified: Tue, 27 Mar 2007 03:52:20 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre- +check=0 Keep-Alive: timeout=15, max=89 Connection: Keep-Alive Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked 200 OK

This seems to work intermittently in Firefox on both Windows and Linux, and slightly less often in MSIE v6. Any ideas appreciated

Replies are listed 'Best First'.
Re: Slightly OT: Stop caching images
by grinder (Bishop) on Mar 27, 2007 at 11:27 UTC

    A very cheap trick to stop images from being cached is to diddle the URI in the <img> element on the page. Instead of emitting:

    <img src="thumbnail-left.png"> <img src="thumbnail-right.png">

    Into the outgoing page, add a bogus GET parameter that makes them unique:

    <img src="thumbnail-left.png?4608fe05888c"> <img src="thumbnail-right.png?4608fe0ab9b9">

    Which, unless you have some weird'n'wacky image handler, will be ignored by your server and the client will be forced to reload the images each time due to the GET parameter, which will inhibit its ability to cache.

    And in case you were wondering, I generated the above with sprintf "%x%0x\n", time, rand(65535);. Adjust as appropriate.

    This is far less hassle than having to fiddle around with cache/no-cache parameters.

    • another intruder with the mooring in the heart of the Perl

      Duh, of course. I've done something similar with my Ajax calls, because IE caches the GET requests. Cheers for pointing that out
Re: Slightly OT: Stop caching images
by hangon (Deacon) on Mar 27, 2007 at 09:54 UTC

    Images are sent in a separate http request than your html page, so you probably need to send a non-caching header with each image. Offhand, the only way I can think of doing this is to send the images through your script where you can add your own header. You might check the server documentation to see if there is a configuration directive to send non-caching headers.

      ah, I understand now. My no-caching efforts were in vain...
Re: Slightly OT: Stop caching images
by almut (Canon) on Mar 27, 2007 at 11:37 UTC

    Not entirely sure I understand your requirements... but why do you need to disable caching at all? As long as each image is corresponding to a unique URL, things should work as intended. Let's assume you have three images. So, instead of having something like

    ----- ---------- --------- ----------- ----- | <-- | | left.jpg | | mid.jpg | | right.jpg | | --> | ----- ---------- --------- ----------- -----

    and then changing the image content that's delivered as "left.jpg" etc. when the --> button is clicked, it's proably easier to just update/rotate the URLs. For example, if you initially have

    ----- ---------- --------- ----------- ----- | <-- | | img1.jpg | | img2.jpg | | img3.jpg | | --> | ----- ---------- --------- ----------- -----

    then, after rotation, you'd output

    ----- ---------- --------- ----------- ----- | <-- | | img2.jpg | | img3.jpg | | img4.jpg | | --> | ----- ---------- --------- ----------- -----

    i.e. "img2.jpg" remains the same image (so the browser can reload it from its cache). It'll just be displayed in a different place.

    Even if your requirements are not quite as simple as that, it should still be possible to always make sure that, if the content of the image changes, it gets a new URL (so cache lookup will surely fail). At least, that approach should always work as a last resort.   But maybe I've completely misunderstood what you want to do... :)

    Having said that, if you still want to go the other route trying to disable client side caching, you might want to look into using mod_headers, which lets you set/add specific custom headers for certain URLs, even if they're static, like images.

    BTW, there's a neat caching test page (AJAX-based), to give you an idea of which caching features actually do work in current browsers... (things have gotten better, generally, but there are still a number of more sophisticated, unresolved issues)

      hmm ... I probably didn't explain myself very well. I am rotating an image (using Image::Magick's Rotate method) not changing the image order. So nothing about the web page has changed - but the image on the disk itself has rotated. I can't change the name of the image to prevent caching (other than to add redundant query info as above) as it's used throughout the system and by more than one module.

      mod_headers could be useful, though. Thanks

        Aside from cache-related pragma's and standard content-expiration, you may wish to check out the 'ETag' HTTP header, which seems to be favoured by Internet Explorer for this kind of thing.

        Using ETag, you uniquely idenify each 'version' of a resource, so if you want it to refresh, you send a different ID.

        I find it better than appending ?12309821 to a request because:
        • my logs arent filled with random numbers
        • 12309821 adds nothing to the document, semantically speaking.
        • the ETag header is generally left unmolested by internet proxies.

        -David
Re: Slightly OT: Stop caching images
by ikegami (Patriarch) on Mar 28, 2007 at 05:10 UTC

    mod_headers contain directives that allow you to add headers to requests. You might also be interested in mod_expires. Using <FilesMatch>, <Directory> or <Location>, you can limit the requests to which the headers are added.