How to cache images generated by PHP
When spitting out images with php the browser doesn't seem to cache the resulting image because the browser was no caching.
This image script pulled off 400mb in 3 days:http://ruralromeos.com/new_singles.php
To fix this we simply told the browser to cache the image.
There are two options in the code below, use whichever one suits you. (ie: if you know the image will never change use option 1, or if you have a file to base the mtime off use option 2).
session_start(); // if you are using sessions.
// not sure if this stuff is really needed, but works:
header("Cache-Control: private, max-age=10800, pre-check=10800");
header("Pragma: private");
header("Expires: " . date(DATE_RFC822,strtotime(" 2 day")));
// the browser will send a $_SERVER['HTTP_IF_MODIFIED_SINCE']
// option 1, you can just check if the browser is sendin this
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
// if the browser has a cached version of this image, send 304
header('Last-Modified: '.$_SERVER['HTTP_IF_MODIFIED_SINCE'],true,304);
exit;
}
// option 2, if you have a file to base your mod date off:
$img = "some_image.png";
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
&&
(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == filemtime($img))) {
// send the last mod time of the file back
header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($img)).' GMT',
true, 304);
exit;
}
// and here we send the image to the browse with all the stuff
// required for tell it to cache
header("Content-type: image/jpeg");
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($img)) . ' GMT');
// use ob buffering to find the image size.
ob_start();
imagejpeg($image,null,100);
$ImageData = ob_get_contents();
$ImageDataLength = ob_get_length();
ob_end_clean();
header("Content-Length: ".$ImageDataLength);
echo $ImageData;
imagedestroy($image);



Comments
Brett
June 5th, 2009
Reply
Hi With this code, when will it ever reach option 2 - if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
// if the browser has a cached version of this image, send 304
header('Last-Modified: '.$_SERVER['HTTP_IF_MODIFIED_SINCE'],true,304);
exit;
}
// option 2, if you have a file to base your mod date off:
$img = "some_image.png";
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
&&
(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == filemtime($img))) {
// send the last mod time of the file back
header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($img)).' GMT',
true, 304);
exit;
}
you have if (isset($_SERVER..) then have the same thing in the second if statement?
I wasn't able to get things to cache with this script. I wrote something based off this but with some additional code changes - seems to work unsure about the expires stuff though. Brett
http://www.breathteching.com/2009/06/05/image-caching-specifically-for-firefox/
RottNKorpse
July 5th, 2009
Reply
Brett it isn't using the same if statement...on the second one it also has (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == filemtime($img))) {
just not on the same line
bucabay
September 22nd, 2009
Reply
If the image is static, the best thing is to just send a redirect to that image. That way the server handles the cache without having to invoke PHP on subsequent requests.
If you're gonna handle the image with PHP, I wouldn't buffer the contents. Just read size of the file with filesize() to get content-length. http://us2.php.net/manual/en/function.filesize.php.