views:

46

answers:

3

I have a php dynamically generated image which I need to write to file to call later. My problem is that I need this image to have appropriate expiration headers included in it. There are a massive number of these and their headers vary individually file-by-file making .htaccess controls not an option.

I can write expiration headers if I'm outputting the image directly to the browser with this: header("Content-Type: image/jpeg"); header('Expires: "' . gmdate("D, d M Y H:i:s", $expirationDate) . '"'); imagepng($image, NULL);

Or I can write the image to a file to be used later with this: imagepng($image, $filepath)

But I can't for the life of me figure out how to combine those two and write the image to a file while including its expiration headers. How would you go about writing an image file with an expires header?

+1  A: 

If you really want to store both the headers and the content in files on the server you could use mod_asis:

In the server configuration file, associate files with the send-as-is handler e.g.
AddHandler send-as-is asis
The contents of any file with a .asis extension will then be sent by Apache to the client with almost no changes. In particular, HTTP headers are derived from the file itself according to mod_cgi rules, so an asis file must include valid headers, and may also use the CGI Status: header to determine the HTTP response code.

Your php script then would write both the headers and the content to files that are handled as send-as-is by the apache webserver.

VolkerK
+1 Great answer, ignore mine. :-)
Tim Lytle
After you've set up the send-as-is handler, how would you go about writing such a file? I'm not entirely certain as to how to actually write file headers. I've only ever had to use php to generate them on its own.Is there a good reference on header syntax or what I would need to know to successfully force my own headers via this method?
Jen
hm hm hm, I'm not so convinced that this is the proper direction. It's an interesting alternative but I'm not sure whether the images have to be stored in files on the server anyway. Fixing the problem(s) in the "original" script could easily be a better advice.
VolkerK
+1  A: 

I think your best bet it to server the file just as you are, something like:

header("Content-Type: image/jpeg"); 
header('Expires: "' . gmdate("D, d M Y H:i:s",
  $expirationDate) . '"'); 
imagepng($image, NULL);

Sure you're using php to serve a static file, but the expire header is going to limit repeat requests.

Update: Since $image is a generated file, on the first request generate and save the image, then output it. On additional requests, just output the already generated image. Essentially the expire headers are controlling the browser's cache, while you need to implement some kind of caching on the server to avoid generating the same output multiple times.

So you're looking at two different kinds of caching. You can do them in the same script, with a combination of two scripts - really however you want.

Unless you can set a standard expire header with apache (which you say you can't, since it varies), I believe this is your best (if not only) choice.

Of course there is the convoluted and complex way:

  • Set up mod_rewrite to send requests for missing images to your php script.
  • Append some session id to the image request (so it's unique to the browser).
  • Have the php script send the expire header, and the image content.
  • Have the php script link the real static image to the session specific image name.

Or something like that. I'd just serve them all up using php.

Update: Or use mod_asis from VolkerK's great answer.

Tim Lytle
My biggest problem here is that $image is the result of a very lengthy image generation process, so I don't want to be re-running the script that creates $image every time a new user comes to the image file. I thought the simple solution would be to have the first php file write a second php file which sends the proper headers and then outputs the raw image data without any need to generate it anew, but it appears that said data doesn't like to be written to a secondary file. See my comments above for how I attempted and failed at this.
Jen
I think I found an answer. I write my png image to file, then write a php file to send the proper expiry headers and readfile the png image. Downside is I'm handling two files where I was hoping to only use one. How much of a performance hit would I take from this? Not that I have very many other options.
Jen
@Jen You're correct, you'll want to generate and save the image (caching on the server) then control the browsers cache by sending a header, then just passing the file. I've updated my answer to reference the two kinds of caching you'll be doing.
Tim Lytle
A: 

Perhaps all you have to do is exactly ...nothing, except writing the image data to the disc.
Depending on the webserver you're using some caching mechanisms work out of the box for static files (which you would create with the php script).

If you're using apache's httpd take a look at http://httpd.apache.org/docs/2.2/mod/core.html#fileetag and http://httpd.apache.org/docs/2.2/caching.html. By default httpd will also send a last-modified header and it supports If-Modified-Since request headers.
When your php script changes the image files the ETag changes as well and/or the If-Modified-Since condition would be met and the httpd sends the data. Otherwise it would only send a response saying "nothing has changed" to the client.

VolkerK