How to Enable Client-Side Caching of Resized Images
About a month ago, I wrote a tutorial on dynamically resizing images in PHP. Despite my best intentions, I never found the time to go back and rewrite the script to include server-side caching of the images created.
However, one reader asked if it was possible to enable a client-side cache of a dynamically resized image. It surely is, and it’s very simple.
Dynamic Image Resizing: Revisited
If you’ve got no clue how to resize an image in PHP, then you ought to go back and re-read the original article. For the rest of you, here’s a quick refresher on what happens.
Our script takes a filename as a $_GET parameter. If the file exists, the script loads it in as an image resource. Using the GD library, we create a new image resource that is the proper size.
Finally, we use a content-type header to tell the browser to interpret the data as an image and we output the image data. Like this…
header("content-type: image/png"); imagepng($dst_img);
Enabling a Client Side Cache
In order to enable a client-side cache, all we need to do is add an extra header to the mix.
There is a set of headers in HTTP to handle this sort of need – Cache-Control. You can use this to enable caching, disable caching, and set some restrictions on what can be cached for how long.
The option we’re most interested in is max-age=[seconds]. This response header is sent along with the data to tell the browser that it can re-use a cached copy as long as it is no older than the specified age.
To enable this with PHP, add another header() call before the imagepng() call, and set a Cache-Control header with an appropriate max-age. Like so…
header("Cache-Control: max-age=3600"); header("content-type: image/png"); imagepng($dst_img);
Keep Request Queries Consistent
With this system, you could set a pretty long max-age for the cache. Assuming that the original image never changes, the user could cache a resized copy for months and your script would be happy.
However, you need to keep your query strings consistent for this to work. Since your request includes a query string, that full string is included in the location that is cached.
According to your browser, it’s not the image that is cached, it’s the location…
http://www.earn-web-cash.com/scripts/resize-image.php?image=http://www.earn-web-cash.com/wp-content/uploads/2008/01/dzone-screenshot.png
If you were to change the query string in any way – leaving out the www, for example – the browser will think it is fetching a new resource and it won’t consult the cache.
This is especially important if you include size parameters in the query string to dynamically choose the new size. You would need to be careful to keep the parameters in the same order every time for the cache to work properly.
Rich said this on March 6th, 2008 at 11:21 am
Works like a charm!
Works in every browser (FF, IE, Safari, Opera..etc)
Pat said this on March 10th, 2008 at 4:45 am
Hey, cheers for the tute.
I couldnt seem to get it to cache still, would calling the script through htaccess rewrite make any difference?
ie http://www.domain.com/image/4.jpg
Pat
Pat said this on March 10th, 2008 at 6:11 am
ok, I moved the cache control under the content-type:
header(‘Content-type: image/jpeg’);
header(‘Cache-Control: max-age=3600′);
and now the reponse header is saying 3600 instead of ‘ no-store, no-cache, must-revalidate, post-check=0, pre-check=0′
however I am still getting a passed expiry date.
as in the following reponse headers:
Date Mon, 10 Mar 2008 11:10:17 GMT
Server Apache/1.3.39 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 mod_jk/1.2.14 mod_ssl/2.8.30 OpenSSL/0.9.7a PHP-CGI/0.1b
Cache-Control max-age=3600
Expires Thu, 19 Nov 1981 08:52:00 GMT
Pragma no-cache
X-Powered-By PHP/5.2.1
Keep-Alive timeout=15, max=66
Connection Keep-Alive
Transfer-Encoding chunked
Content-Type image/jpeg
any idea why the expiry date would be in the past, the server time is correct
Pat
NL said this on April 12th, 2008 at 3:19 am
Apaches default behavour is to disable caching as much as possible. That is why default headers are applied.
You should be able to do:
But some servers override the expire-header anyway
NL said this on April 12th, 2008 at 3:20 am
Apaches default behavour is to disable caching as much as possible. That is why default headers are applied.
You should be able to do:
– start of code –
// Expire in 1 day
$oDate = mktime(date(‘H’), date(‘i’), date(’s’), date(‘m’), date(‘d’) + 1, date(‘Y’));
header(‘Expires: ‘ . date(‘D, d M Y H:i:s’, $oDate) . ‘ GMT’);
– end of code –
But some servers override the expire-header anyway
suleiman said this on April 17th, 2008 at 5:55 pm
is there a way to set expire headers for images that are not hosted on your server?
Quinta said this on October 24th, 2008 at 3:02 am
Great work.
Newblown said this on December 30th, 2008 at 1:53 pm
It’s so simple !
John639 said this on May 20th, 2009 at 9:55 am
Very nice site! cheap cialis http://opeaixy.com/qsqaxa/4.html
Enable Client Side Caching for Resized Images - Tutorial Collection said this on June 4th, 2009 at 9:45 pm
[...] View Tutorial No Comment var addthis_pub=”izwan00″; BOOKMARK This entry was posted on Friday, June 5th, 2009 at 8:19 am and is filed under Php Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. [...]