Image Caching With PHP

While working on my next project, I am looking for the best possible techniques to make it fastest possible (both client and server). My app requests a lot of images here and there, it may count up to hundreds or thousands requests in a while. I can not hold all of those wthin flash player cache because some of them may change, and I also want shortest possible respond times and client-server traffic reduction as well as server side computing reduction. Thats where browser caching comes into the scene. I have experimented a bit with all possible http headers to understand each browser specifics and I came with a solution.

// $this->time() - returns filemtime() for the file
// $this->filename() - returns full path to the file

$etag=md5($this->time().$this->filename());
$time=gmdate('r', $this->time());

header('Last-Modified: '.$time);
header("Cache-Control: must-revalidate");
header('Expires: '.$time);
header("Etag: ".$etag); 

$test1 = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) 
	&& $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $time;
$test2 = isset($_SERVER['HTTP_IF_NONE_MATCH']) 
	&& str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == $etag;
if($test1 || $test2){
	header('HTTP/1.1 304 Not Modified');
	exit();
}

header("Content-Length: ".filesize($this->filename()));
header("Content-type: image/png");

readfile($this->filename());

This is how it works:

  1. flash app requests a new image (thorough browser) from php server, minimum requests headers added with browser while it is a new image
  2. php server responds with important cache and Etag headers info and image bytes (content)
  3. browser caches response headers, flash player handles response

Repeated request:

  1. when flash player requests the same image again, browser adds Etag and date into request headers (while it caches the last response)
  2. php server catches request headers and see browser cached info in $_SERVER vars
  3. while Etag matches, it responds with 304 Not Modifed header and no content pushed (traffic is saved, server computing reduced)
  4. browser push its cached content into flash player (faster response)

Now someone changes the image on php server:

  1. flash player requests the image, browser adds headers
  2. php server generates new Etag for the image and compares it with browser added request headers
  3. those does not match so the new image content is pushed with response

Nice thing is, there are no random parameters required with your requests, while all requets are sent to the server and handled appropriately, so your content is always fresh. This script is tested with IE and Chrome (works as expected). I was not able to make my proxy watcher communicate with opera and my firefox settings are set to no-cache at all.

8 comments so far

  1. Thanks guy! :-)

  2. Anonymous June 4, 2010 07:21

    Why not just have Apache do this for you using per-filetype caching, expiration, and etag settings in an .htaccess file? IIS has similar settings.

    This method introduces the extra overhead of running a PHP script, to do nothing more than what is already a built-in capability of the web server.

    Is there some other reason I’m missing here?

  3. Jozef Chúťka June 4, 2010 09:39

    @Anonymous .. in my case I need some extra processing to generate the image and so on. Anyway, I would like to see .htaccess solution, could you post please?

  4. […] Image Caching With PHP at Jozef Ch�ťka’s blog […]

  5. […] Image Caching With PHP at Jozef Chúťka’s blog […]

  6. Christian June 15, 2010 10:38

    I also strongly suggest to let Apache take over.
    AFAIK the default settings of Apache will be sufficient for that already.
    You should save the generated file to the filesystem under the URL that it is called from. Succeeding requests will then be served statically.

    I have done this for the symfony framework in a plugin (http://www.symfony-project.org/plugins/sfImageTransformExtraPlugin) but I’m sure even if you do not use symfony you can get some ideas from the readme.

  7. Julio April 18, 2011 15:31

    Thank you!!! You saved me a lot of work!!!

  8. ser March 14, 2012 16:21

    It works! thx!

Leave a comment

Please be polite and on topic. Your e-mail will never be published.