It is useful to not return image data on a conditional GET request. It is also useful to return headers such that the image can be cached. This happens automatically in apache if apache is serving the file. However, this does not happen with the easy url (image/view/nodeid/size).
I was going to create a patch for some revision of image.module, but the one posted on the modules page was not the same as the one in the drupal 4.6 release, so I'm just including the function that I changed here.
Use it if you wish, it will help with traffic for anyone that serves any number of images.
function image_file_download($file) {
$size = image_get_info(file_create_path($file));
if ($size) {
$modified = filemtime(file_create_path($file));
//apache only
$request = getallheaders();
if (isset($request['If-Modified-Since'])) {
//remove information after the semicolon and form a timestamp
$request_modified = explode(';', $request['If-Modified-Since']);
$request_modified = strtotime($request_modified[0]);
}
// Compare the mtime on the request to the mtime of the image file
if ($modified <= $request_modified) {
header('HTTP/1.1 304 Not Modified');
exit();
}
//enable caching on this url for proxy servers
$headers = array('Content-Type: ' . $size['mime_type'],
'Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified) . ' GMT',
'Cache-Control: public');
return $headers;
}
}
| Comment | File | Size | Author |
|---|---|---|---|
| #10 | image.module.25977.patch | 1.81 KB | raintonr |
Comments
Comment #1
drewish commentedi think this would be an interesting feature but the apache specific nature of getallheaders() is kind of a problem...
Comment #2
fagoI've just got it working with imagecache (patch for it is coming). I'd like to see it for the image module too.
Here is the code I've used:
With that function it should be not hard to integrate it in image module too.
Note that this solution should work with APACHE and LIGHTTPD, as the used server variables are described in the CGI interface. drupal_page_cache_header() uses them too, so they should be save to use. I've tested my solution with lighttpd - it works :)
Comment #3
fagoI've just added an improvement to my code above: Setting content-length headers.
To do so just add the line
$headers[] = 'Content-Length: '. $fileinfo[7];before the call to imagecache_cache_set_cache_headers()
Comment #4
raintonr commentedI'm posting this here, but maybe we need another thread about this... although it is Apache specific...
If you are using apache mod_deflate then no matter how you try and configure it not to compress images it still seems to if the output is a stream from a PHP script. This seems to be a known problem. It's discussed in http://codex.gallery2.org/Gallery2:Performance_Tips for example:
Anyhow, I eventually found the answer here: http://www.php.net/manual/en/function.apache-setenv.php#60530
So easy when you know how! Just insert a call to
apache_setenv('no-gzip', '1');before returning the modified headers inimage_file_downloadworks wonders. Have tested this with Apache/2.0.54 w' PHP 5.0.4.Comment #5
dharamgollapudi commentedsubscribing...
Comment #6
raintonr commentedI've been writing some custom modules that generate graphs. As part of this have been looking at how the caching and the
If-Modified-Sinceheader works and have discovered something a bit useful.It would seem that when you tell the server to return code 304 (not modified) unless you also include the other headers (cache-control, etc) some browsers (well, Firefox at least) and I'd imagine some network infrastructure too, forgets about the previously cached version of the image.
The upshot of this is that a user flicking between pages, which lets say all have the same image in a block on the left, causes a response 200 (image is sent), then 304 (not modified), then 200 (image is sent again), then 304, etc.
With the code change below though this doesn't happen, things work as you'd expect. Ie. response 200 sent first time, then 304 on all subsequent pages. Note this also includes the Apache gzip fix mentioned above:
Comment #7
Hetta commentedAs a patch, where should this end up? Cos image_file_download() looks quite different from above, both for 5.x-2-dev and 6.x-1-dev.
You don't check for user access rights, for instance.
Comment #8
raintonr commentedI think access rights, etc. are catered for outside of this function. The 'stock' image file download in my module looks like this:
This is quiet old, the ID atop reads:
// $Id: image.module,v 1.209.2.36 2007/07/06 15:22:19 drewish Exp $Comment #9
sunPlease submit a proper patch. See http://drupal.org/patch for details.
Comment #10
raintonr commentedPlease find attached a patch just rolled against 1.9 of image. Looking in CVS the
image_file_downloadfunction looks unchanged between 1.9 and HEAD so this patch should work for D5 and D6 versions.You might want to check for other servers and make sure it works with something other than Apache. I can confirm this works in D5 with Apache and 1.9 of image.
Comment #11
jubalkessler commentedThe attached patch worked for me, with offset adjustment, for 6.x-1.0-alpha4.
I look forward to seeing this incorporated into the next release of Image.
Comment #12
raintonr commentedI upgraded to 5.x-2.0-alpha3 over the weekend in preparation for a move to D6 and can confirm that patch in #10 works for that version too.
Could someone please roll this (or a variant to check for Apache) into the standard release?
Comment #13
joachim commentedHadn't we better go with the approach from #2, which works in at least apache + one other server?
Comment #14
sunGiven that (a different) Image module is in Drupal 7 core, the contrib Image module remains minimally maintained now. It won't see any new features. Instead, we're trying hard to make upgrades to D7 work. See project page for details. Thanks!