Supporting Conditional GET in PHP
23rd April 2003
This site’s RSS feeds now support Conditional GET. Since the feeds are dynamically generated on every request, adding support took a bit of hacking around with PHP. Here’s the function I came up with (based on the excellent description provided by Charles Miller in the article linked above):
function doConditionalGet($timestamp) {
// A PHP implementation of conditional get, see
// https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers
$last_modified = substr(date('r', $timestamp), 0, -5).'GMT';
$etag = '"'.md5($last_modified).'"';
// Send the headers
header("Last-Modified: $last_modified");
header("ETag: $etag");
// See if the client has provided the required headers
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ?
stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) :
false;
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ?
stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) :
false;
if (!$if_modified_since && !$if_none_match) {
return;
}
// At least one of the headers is there - check them
if ($if_none_match && $if_none_match != $etag) {
return; // etag is there but doesn't match
}
if ($if_modified_since && $if_modified_since != $last_modified) {
return; // if-modified-since is there but doesn't match
}
// Nothing has changed since their last request - serve a 304 and exit
header('HTTP/1.0 304 Not Modified');
exit;
}Usage is simple: Work out the timestamp that the page content was last modified and call doConditionalGet($timestamp);. It will send the 304 header for you and exit if the client claims to have seen the content already—otherwise control will return to your main script and you can serve content as normal. Slightly inelegant, but it does the job.
Unfortunately I don’t have a Conditional-GET supporting RSS aggregator to hand so I have no idea if it works or not (so far I’ve only tested it by watching the headers sent with LiveHTTPHeaders). I’d be grateful if someone could confirm that this has had the desired effect.
Update: I’ve changed the above code sample (and my implementation) to send the ETag header as ETag rather than etag.
More recent articles
- Reverse engineering Codex CLI to get GPT-5-Codex-Mini to draw me a pelican - 9th November 2025
- Video + notes on upgrading a Datasette plugin for the latest 1.0 alpha, with help from uv and OpenAI Codex CLI - 6th November 2025
- Code research projects with async coding agents like Claude Code and Codex - 6th November 2025